Parcourir la source

Merge branch 'dev-ly' into dev-zhn

zhaonan il y a 6 jours
Parent
commit
a890fae1fe
32 fichiers modifiés avec 725 ajouts et 205 suppressions
  1. 6 1
      src/components/common/Keyword.vue
  2. 1 1
      src/components/common/ListTable.vue
  3. 69 4
      src/components/common/NavTab.vue
  4. 1 0
      src/components/common/Navbar.vue
  5. 21 6
      src/components/common/NetworkAddressesBox.vue
  6. 0 1
      src/components/form/SubmitButton.vue
  7. 29 6
      src/components/server/DomainsBox.vue
  8. 22 8
      src/components/server/HTTPCCConfigBox.vue
  9. 28 9
      src/components/server/HTTPRedirectToHTTPSBox.vue
  10. 8 1
      src/components/server/OriginSchedulingViewBox.vue
  11. 67 4
      src/components/server/ServerNameBox.vue
  12. 24 8
      src/components/server/UAMConfigBox.vue
  13. 4 3
      src/components/ui/TCheckboxBinary.vue
  14. 3 1
      src/components/ui/TDataTable.vue
  15. 4 1
      src/components/ui/TTabs.vue
  16. 15 3
      src/layouts/ChildLayout.vue
  17. 1 3
      src/layouts/ServerSettingLayout.vue
  18. 0 2
      src/views/dashboard/index.js
  19. 6 0
      src/views/layout.css
  20. 1 1
      src/views/layout.html
  21. 28 2
      src/views/layout.vue
  22. 1 2
      src/views/servers/@menu.vue
  23. 2 2
      src/views/servers/index.css
  24. 232 103
      src/views/servers/index.vue
  25. 13 4
      src/views/servers/server/settings/@setting_menu.vue
  26. 4 3
      src/views/servers/server/settings/cc/index.vue
  27. 29 5
      src/views/servers/server/settings/http/index.vue
  28. 2 4
      src/views/servers/server/settings/reverseProxy/@menu.vue
  29. 1 2
      src/views/servers/server/settings/reverseProxy/scheduling.vue
  30. 13 12
      src/views/servers/server/settings/serverNames/index.vue
  31. 4 3
      src/views/servers/server/settings/uam/index.vue
  32. 86 0
      src/views/servers/style/server.pcss

+ 6 - 1
src/components/common/Keyword.vue

@@ -59,7 +59,12 @@ const encodeHTML = function (s) {
 </script>
 
 <template>
-	<span><span style="display: none" ref="textRef"><slot></slot></span><span v-html="textValue"></span></span>
+	<span>
+		<span style="display: none" ref="textRef">
+			<slot></slot>
+		</span>
+		<span v-html="textValue"></span>
+	</span>
 </template>
 
 <style scoped>

+ 1 - 1
src/components/common/ListTable.vue

@@ -60,7 +60,7 @@ const updateColumnClass = () => {
 </script>
 
 <template>
-	<TDataTable dataKey="id" :items="items" tableClass="ui table selectable celled" scrollable @row-reorder="onRowReorder" ref="rootRef">
+	<TDataTable dataKey="id" :items="items" tableClass="ui table selectable" scrollable @row-reorder="onRowReorder" ref="rootRef">
 		<slot></slot>
 	</TDataTable>
 </template>

+ 69 - 4
src/components/common/NavTab.vue

@@ -1,6 +1,6 @@
 <script setup>
 import TTab from "@/components/ui/TTab.vue";
-import {inject, onBeforeMount, onMounted, ref} from "vue";
+import { inject, onBeforeMount, onMounted, ref } from "vue";
 
 const Tea = inject("$Tea")
 const props = defineProps({
@@ -75,6 +75,10 @@ const props = defineProps({
 	actionCart: {
 		type: Boolean,
 		default: false
+	},
+	actionGroups: {
+		type: Boolean,
+		default: false
 	}
 })
 const realHref = ref()
@@ -177,11 +181,53 @@ onMounted(() => {
 </script>
 
 <template>
-	<TTab :disabled="separator || disabled" :value="tabValue" @click="clickTab($event)" :as="(isStaticTab()) ? 'SPAN' : 'A'" :href="realHref" :target="calculateTarget()" class="flex">
+	<TTab :disabled="separator || disabled" :value="tabValue" @click="clickTab($event)"
+		:as="(isStaticTab()) ? 'SPAN' : 'A'" :href="realHref" :target="calculateTarget()" class="flex tt-tab">
 		<span v-if="!separator" class="flex items-center gap-2">
 			<span v-if="back"><i class="pi pi-arrow-left"></i></span>
 			<i v-if="icon.length > 0" :class="icon"></i>
-			<i v-if="actionCreate || actionCreateLink" class="pi pi-pen-to-square"></i>
+			<!-- <i v-if="actionCreate || actionCreateLink" class="pi pi-pen-to-square"></i> -->
+			<i v-if="actionCreate || actionCreateLink" class="pi">
+				<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+					<path
+						d="M8.33331 13.3334H2.33331C1.78103 13.3334 1.33331 12.8857 1.33331 12.3334V3.66675C1.33331 3.11446 1.78103 2.66675 2.33331 2.66675H13.6666C14.2189 2.66675 14.6666 3.11446 14.6666 3.66675V8.31381"
+						stroke="#657080" stroke-linecap="round" stroke-linejoin="round" />
+					<path
+						d="M1.33331 3.66675C1.33331 3.11446 1.78103 2.66675 2.33331 2.66675H13.6666C14.2189 2.66675 14.6666 3.11446 14.6666 3.66675V6.66675H1.33331V3.66675Z"
+						stroke="#657080" />
+					<path d="M10.6667 11.6667H14.6667" stroke="#657080" stroke-linecap="round"
+						stroke-linejoin="round" />
+					<path d="M12.6667 9.66675V13.6667" stroke="#657080" stroke-linecap="round"
+						stroke-linejoin="round" />
+					<path
+						d="M2.66667 4.66659C2.66667 4.2984 2.96514 3.99992 3.33333 3.99992C3.70152 3.99992 4 4.2984 4 4.66659C4 5.03478 3.70152 5.33325 3.33333 5.33325C2.96514 5.33325 2.66667 5.03478 2.66667 4.66659Z"
+						fill="#657080" />
+					<path
+						d="M4.66667 4.66659C4.66667 4.2984 4.96514 3.99992 5.33333 3.99992C5.70152 3.99992 6 4.2984 6 4.66659C6 5.03478 5.70152 5.33325 5.33333 5.33325C4.96514 5.33325 4.66667 5.03478 4.66667 4.66659Z"
+						fill="#657080" />
+				</svg>
+			</i>
+			<i v-if="actionGroups" class="pi">
+				<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+					<g clip-path="url(#clip0_22_569)">
+						<path
+							d="M14.3333 1.33325H1.66665C1.48255 1.33325 1.33331 1.49606 1.33331 1.69689V4.96962C1.33331 5.17045 1.48255 5.33325 1.66665 5.33325H14.3333C14.5174 5.33325 14.6666 5.17045 14.6666 4.96962V1.69689C14.6666 1.49606 14.5174 1.33325 14.3333 1.33325Z"
+							stroke="#657080" stroke-linejoin="round" />
+						<path
+							d="M14.3333 10.6667H1.66665C1.48255 10.6667 1.33331 10.8295 1.33331 11.0304V14.3031C1.33331 14.5039 1.48255 14.6667 1.66665 14.6667H14.3333C14.5174 14.6667 14.6666 14.5039 14.6666 14.3031V11.0304C14.6666 10.8295 14.5174 10.6667 14.3333 10.6667Z"
+							stroke="#657080" stroke-linejoin="round" />
+						<path d="M4.66669 5.33325V8.00269L11.3334 8.00565V10.6666" stroke="#657080"
+							stroke-linecap="round" stroke-linejoin="round" />
+						<path d="M6 12.6667H10" stroke="#657080" stroke-linecap="round" stroke-linejoin="round" />
+						<path d="M6 3.33325H10" stroke="#657080" stroke-linecap="round" stroke-linejoin="round" />
+					</g>
+					<defs>
+						<clipPath id="clip0_22_569">
+							<rect width="16" height="16" fill="white" />
+						</clipPath>
+					</defs>
+				</svg>
+			</i>
 			<i v-if="actionUpload" class="pi pi-upload"></i>
 			<i v-if="actionSetting" class="pi pi-cog"></i>
 			<i v-if="actionCart" class="pi pi-shopping-cart"></i>
@@ -190,13 +236,32 @@ onMounted(() => {
 				<span v-if="name.length > 0">{{ name }}</span>
 				<span v-else-if="overview">概览</span>
 			</span>
-			<span v-if="$slots.name"><slot name="name"></slot></span>
+			<span v-if="$slots.name">
+				<slot name="name"></slot>
+			</span>
 		</span>
 		<span v-if="separator">|</span>
 	</TTab>
 </template>
 
 <style scoped lang="postcss">
+.p-tab {
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 16px;
+	line-height: 24px;
+	vertical-align: middle;
+	padding: 0 0 10px;
+	margin-right: 30px;
+	color: rgba(101, 112, 128, 1);
+}
+
+.p-tab:hover,
+.p-tab-active {
+	font-weight: 500;
+	color: rgba(49, 49, 49, 1);
+}
+
 .p-tab.p-disabled {
 	@apply px-2;
 }

+ 1 - 0
src/components/common/Navbar.vue

@@ -131,6 +131,7 @@ defineExpose({
 
 <style scoped lang="postcss">
 .wrapper {
+	padding-bottom: 24px!important;
 	&:not(.secondary) {
 		@apply pb-4 -mt-2;
 	}

+ 21 - 6
src/components/common/NetworkAddressesBox.vue

@@ -153,20 +153,35 @@ defineExpose({
 				<TLabel v-for="(addr, index) in addresses" outlined="">
 					{{ addr.protocol }}://<span v-if="addr.host.length > 0">{{ addr.host.quoteIP() }}</span><span
 					v-if="addr.host.length == 0">*</span>:<span
-					v-if="addr.portRange.indexOf('-')<0">{{ addr.portRange }}</span><span v-else class="italic">{{ addr.portRange }}</span>&nbsp;
-					<a href="" @click.prevent="updateAddr(index, addr)" title="修改"><i
-						class="pi pi-pencil small"></i></a>&nbsp;
-					<a href="" @click.prevent="removeAddr(index)" title="删除"><i class="pi pi-remove"></i></a>
+					v-if="addr.portRange.indexOf('-')<0">{{ addr.portRange }}</span>
+					<span v-else class="italic">{{ addr.portRange }}</span>
+					<a href="" @click.prevent="updateAddr(index, addr)" title="修改">
+						<svg style="display: inline-block; margin-left: 10px;" width="14" height="14" viewBox="0 0 14 14" fill="none"
+							xmlns="http://www.w3.org/2000/svg">
+							<path d="M2.04175 12.25H12.5417" stroke="#657080" stroke-linecap="round"
+								stroke-linejoin="round" />
+							<path d="M3.20825 7.7933V9.91667H5.34244L11.3749 3.88153L9.24432 1.75L3.20825 7.7933Z"
+								stroke="#657080" stroke-linejoin="round" />
+						</svg>	
+					</a>
+					<a href="" @click.prevent="removeAddr(index)" title="删除">
+						<svg style="display: inline-block; margin-left: 10px;" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+							<path d="M4.08301 4.08325L9.91634 9.91659" stroke="#657080" stroke-linecap="round" stroke-linejoin="round"/>
+							<path d="M4.08301 9.91659L9.91634 4.08325" stroke="#657080" stroke-linecap="round" stroke-linejoin="round"/>
+						</svg>
+					</a>
 				</TLabel>
 				<TDivider></TDivider>
 			</div>
 			<div>
-				<a href="" @click.prevent="addAddr()">[添加端口绑定]</a>
+				<a href="" @click.prevent="addAddr()">添加端口绑定</a>
 			</div>
 		</div>
 	</div>
 </template>
 
 <style scoped>
-
+:deep(.label-group) {
+	gap: 0;
+}
 </style>

+ 0 - 1
src/components/form/SubmitButton.vue

@@ -9,5 +9,4 @@ import TButton from "../ui/TButton.vue";
 </template>
 
 <style scoped>
-
 </style>

+ 29 - 6
src/components/server/DomainsBox.vue

@@ -230,7 +230,7 @@ watch(mode, function (mode) {
 </script>
 
 <template>
-	<div>
+	<div class="domains-box">
 		<input type="hidden" :name="realName" :value="JSON.stringify(domains)"/>
 		<div v-if="domains.length > 0" class="label-group">
 			<TLabel outlined="" v-for="(domain, index) in domains" :class="{blue: index == editingIndex}">
@@ -249,9 +249,9 @@ watch(mode, function (mode) {
 			</TLabel>
 		</div>
 		<div v-if="isAdding || isEditing">
-			<div class="ui fields inline mt-2">
+			<div class="ui fields inline mt-2" style="align-items: start;">
 				<div class="ui field" v-if="isAdding">
-					<TSelect v-model="mode">
+					<TSelect v-model="mode" style="width: 80px!important">
 						<TOption value="single">单个</TOption>
 						<TOption value="batch">批量</TOption>
 					</TSelect>
@@ -264,9 +264,9 @@ watch(mode, function (mode) {
 						<TTextarea cols="30" v-model="batchDomains" :placeholder="'example1.com\nexample2.com\n每行一个域名'" ref="batchDomainsRef" class="w-full" rows="5"></TTextarea>
 					</div>
 				</div>
-				<div class="ui field mt-2">
-					<TButton secondary="" size="small" type="button" @click.prevent="confirm">确定</TButton>
-					&nbsp; <a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
+				<div class="ui field">
+					<TButton class="btn-confirm" secondary="" type="button" @click.prevent="confirm">确定</TButton>
+					&nbsp;&nbsp;&nbsp; <a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
 				</div>
 			</div>
 			<p class="comment" v-if="supportWildcard">支持普通域名(
@@ -290,4 +290,27 @@ watch(mode, function (mode) {
 </template>
 
 <style scoped>
+:deep(.domains-box) {
+	font-family: Source Han Sans SC;
+}
+:deep(.btn-confirm) {
+	color: rgba(101, 112, 128, 1);
+	height: 38px;
+	line-height: 38px;
+	border-radius: 4px;
+	background-color: rgba(238, 242, 250, 1);
+	font-weight: 400;
+	font-size: 14px;
+	padding: 0 14px;
+}
+:deep(.p-chip) {
+	color: rgba(101, 112, 128, 1);
+}
+:deep(.p-select-label) {
+	padding-right: 0;
+}
+.comment {
+	font-weight: 400;
+	font-size: 12px;
+}
 </style>

+ 22 - 8
src/components/server/HTTPCCConfigBox.vue

@@ -156,7 +156,7 @@ watch(useCustomThresholds, function (b) {
 			<tr>
 				<td class="title">启用CC无感防护</td>
 				<td>
-					<TCheckboxBinary v-model="config.isOn"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.isOn">{{ config.isOn ? '开启' : '关闭' }}</TCheckboxBinary>
 					<p class="comment">
 						启用后,自动检测并拦截CC攻击。
 					</p>
@@ -165,7 +165,7 @@ watch(useCustomThresholds, function (b) {
 			<tr v-show="config.isOn">
 				<td>阈值设置</td>
 				<td>
-					<TSelect v-model="config.thresholdMethod">
+					<TSelect v-model="config.thresholdMethod" style="width: 118px">
 						<TOption value="default">默认</TOption>
 						<TOption value="auto">自动</TOption>
 						<TOption value="custom">自定义</TOption>
@@ -224,7 +224,7 @@ watch(useCustomThresholds, function (b) {
 			<tr v-show="config.isOn">
 				<td>拦截强度</td>
 				<td>
-					<TSelect v-model="config.level">
+					<TSelect v-model="config.level" style="width: 118px">
 						<TOption value="low">低</TOption>
 						<TOption value="middle">中</TOption>
 						<TOption value="high">高</TOption>
@@ -236,7 +236,7 @@ watch(useCustomThresholds, function (b) {
 			</tbody>
 			<tbody v-show="config.isOn">
 			<tr>
-				<td colspan="2">
+				<td colspan="2" style="height: 30px; padding-top: 4px; padding-bottom: 4px;">
 					<MoreOptionsIndicator @change="showMoreOptions"></MoreOptionsIndicator>
 				</td>
 			</tr>
@@ -259,21 +259,21 @@ watch(useCustomThresholds, function (b) {
 			<tr>
 				<td>忽略常用文件</td>
 				<td>
-					<TCheckboxBinary v-model="config.ignoreCommonFiles"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.ignoreCommonFiles">{{ config.ignoreCommonFiles ? '忽略' : '不忽略' }}</TCheckboxBinary>
 					<p class="comment">忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。但如果单独访问这些文件,比如在浏览器里直接打开,也会加入计数。</p>
 				</td>
 			</tr>
 			<tr>
 				<td>检查请求来源指纹</td>
 				<td>
-					<TCheckboxBinary v-model="config.enableFingerprint"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.enableFingerprint">{{ config.enableFingerprint ? '开启' : '关闭' }}</TCheckboxBinary>
 					<p class="comment">在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。</p>
 				</td>
 			</tr>
 			<tr>
 				<td>启用GET302校验</td>
 				<td>
-					<TCheckboxBinary v-model="config.enableGET302"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.enableGET302">{{ config.enableGET302 ? '开启' : '关闭' }}</TCheckboxBinary>
 					<p class="comment">选中后,表示自动通过GET302方法来校验客户端。</p>
 				</td>
 			</tr>
@@ -281,7 +281,7 @@ watch(useCustomThresholds, function (b) {
 				<td>单IP最低QPS</td>
 				<td>
 					<TInputGroup>
-						<TInputText type="text" name="minQPSPerIP" maxlength="6" style="width: 6em" v-model="minQPSPerIP"/>
+						<TInputText type="text" name="minQPSPerIP" maxlength="6" style="width: 118px" v-model="minQPSPerIP"/>
 						<TInputGroupAddon>
 							<span>请求数/秒</span>
 						</TInputGroupAddon>
@@ -295,4 +295,18 @@ watch(useCustomThresholds, function (b) {
 </template>
 
 <style scoped>
+.comment {
+	margin-bottom: 0;
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 14px;
+    font-family: Source Han Sans SC;
+}
+:deep(.p-inputgroupaddon) {
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 12px;
+	line-height: 14px;
+}
 </style>

+ 28 - 9
src/components/server/HTTPRedirectToHTTPSBox.vue

@@ -84,7 +84,7 @@ watch(portString, function (v) {
 			<tr>
 				<td class="title">自动跳转到HTTPS</td>
 				<td>
-					<TCheckboxBinary v-model="redirectToHttpsConfig.isOn"/>
+					<TCheckboxBinary v-model="redirectToHttpsConfig.isOn">{{ redirectToHttpsConfig.isOn ? '开启' : '关闭' }}</TCheckboxBinary>
 					<p class="comment">开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,
 						<MoreOptionsAngle @change="changeMoreOptions"></MoreOptionsAngle>
 					</p>
@@ -110,7 +110,7 @@ watch(portString, function (v) {
 						<tr>
 							<td>端口</td>
 							<td>
-								<TInputText type="text" name="port" v-model="portString" maxlength="5" style="width:6em"/>
+								<TInputText type="text" name="port" v-model="portString" maxlength="5" />
 								<p class="comment">默认端口为443。</p>
 							</td>
 						</tr>
@@ -133,7 +133,7 @@ watch(portString, function (v) {
 					<td class="title">状态码</td>
 					<td>
 						<TSelect v-model="redirectToHttpsConfig.status">
-							<TOption value="0">[使用默认]</TOption>
+							<TOption value="0">使用默认</TOption>
 							<TOption v-for="option in statusOptions" :value="option.code">{{ option.code }} {{ option.text }}</TOption>
 						</TSelect>
 					</td>
@@ -142,28 +142,32 @@ watch(portString, function (v) {
 					<td>跳转后域名或IP地址</td>
 					<td>
 						<TInputText type="text" name="host" v-model="redirectToHttpsConfig.host" class="w-full"/>
-						<p class="comment">默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。</p>
+						<p class="comment small">默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。</p>
 					</td>
 				</tr>
 				<tr>
 					<td>端口</td>
 					<td>
 						<TInputText type="text" name="port" v-model="portString" maxlength="5" style="width:6em"/>
-						<p class="comment">默认端口为443。</p>
+						<p class="comment small">默认端口为443。</p>
 					</td>
 				</tr>
 				<tr>
 					<td>允许的域名</td>
 					<td>
-						<DomainsBox :v-domains="redirectToHttpsConfig.onlyDomains" @change="changeOnlyDomains"></DomainsBox>
-						<p class="comment">如果填写了允许的域名,那么只有这些域名可以自动跳转。</p>
+						<div style="margin-top: -0.5em; margin-bottom: -0.5em;">
+							<DomainsBox :v-domains="redirectToHttpsConfig.onlyDomains" @change="changeOnlyDomains"></DomainsBox>
+							<p class="comment small">如果填写了允许的域名,那么只有这些域名可以自动跳转。</p>
+						</div>
 					</td>
 				</tr>
 				<tr>
 					<td>排除的域名</td>
 					<td>
-						<DomainsBox :v-domains="redirectToHttpsConfig.exceptDomains" @change="changeExceptDomains"></DomainsBox>
-						<p class="comment">如果填写了排除的域名,那么这些域名将不跳转。</p>
+						<div style="margin-top: -0.5em; margin-bottom: -0.5em;">
+							<DomainsBox :v-domains="redirectToHttpsConfig.exceptDomains" @change="changeExceptDomains"></DomainsBox>
+							<p class="comment small">如果填写了排除的域名,那么这些域名将不跳转。</p>
+						</div>
 					</td>
 				</tr>
 			</table>
@@ -172,4 +176,19 @@ watch(portString, function (v) {
 </template>
 
 <style scoped>
+:deep(.p-inputtext),
+:deep(.p-inputnumber),
+:deep(.p-select) {
+    border-radius: 4px;
+    border-color: rgba(229, 232, 242, 1);
+}
+:deep(.p-inputtext:not(.w-full)),
+:deep(.p-inputnumber:not(.w-full)),
+:deep(.p-select:not(.w-full)) {
+	width: 118px!important;
+}
+.ui.table .comment.small {
+	font-weight: 400;
+	font-size: 12px;
+}
 </style>

+ 8 - 1
src/components/server/OriginSchedulingViewBox.vue

@@ -38,7 +38,7 @@ const update = function () {
 			<tr>
 				<td class="title">当前正在使用的算法</td>
 				<td>
-					{{ scheduling.name }} &nbsp; <a href="" @click.prevent="update()"><span>[修改]</span></a>
+					{{ scheduling.name }} &nbsp; <a href="" @click.prevent="update()"><span>修改</span></a>
 					<p class="comment">{{ scheduling.description }}</p>
 				</td>
 			</tr>
@@ -47,5 +47,12 @@ const update = function () {
 	</div>
 </template>
 
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>
 <style scoped>
+.title {
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 24px;
+}
 </style>

+ 67 - 4
src/components/server/ServerNameBox.vue

@@ -2,7 +2,7 @@
 
 import "@/lib/array.js"
 import useUtils from "@/utils/utils.js"
-import {inject, ref, watch} from "vue"
+import { inject, ref, watch } from "vue"
 import TLabel from "@/components/ui/TLabel.vue";
 import TDivider from "@/components/ui/TDivider.vue";
 import TInputText from "@/components/ui/TInputText.vue";
@@ -15,7 +15,7 @@ const props = defineProps(["v-server-names", "autoSubmit"])
 
 const serverNamesRef = ref()
 const keywordRef = ref()
-const {serverNames, isSearching, keyword} = (function () {
+const { serverNames, isSearching, keyword } = (function () {
 	let serverNames = props.vServerNames;
 	if (serverNames == null) {
 		serverNames = []
@@ -141,15 +141,78 @@ defineExpose({
 			<div class="ui field"><a href="" @click.prevent="addServerName()">添加域名绑定</a></div>
 			<div class="ui field" v-if="serverNames.length > 0"><span class="grey">|</span></div>
 			<div class="ui field" v-if="serverNames.length > 0">
-				<a href="" @click.prevent="showSearchBox()" v-if="!isSearching"><i class="icon search small"></i></a>
+				<!-- <span class="grey">|</span> -->
+				<span class="separator"></span>
+			</div>
+			<div class="ui field" v-if="serverNames.length > 0">
+				<a href="" @click.prevent="showSearchBox()" v-if="!isSearching">
+					搜索域名
+				</a>
 				<a href="" @click.prevent="showSearchBox()" v-if="isSearching"><i class="icon close small"></i></a>
 			</div>
 			<div class="ui field" v-if="isSearching">
-				<TInputText type="text" placeholder="搜索域名" ref="keywordRef" v-model="keyword"/>
+				<TInputText type="text" placeholder="搜索域名" ref="keywordRef" v-model="keyword" />
 			</div>
+			<TDivider></TDivider>
+		</div>
+		<div v-if="serverNames.length > 0" class="label-group">
+			<TLabel outlined="" v-for="(serverName, index) in serverNames"
+				:class="{ hidden: serverName.isShowing === false }">
+				<em v-if="serverName.type != 'full'">{{ serverName.type }}</em>
+				<span v-if="serverName.subNames == null || serverName.subNames.length == 0"
+					:class="{ disabled: serverName.isShowing === false }">{{ serverName.name }}</span>
+				<span v-else :class="{ disabled: serverName.isShowing === false }">{{ serverName.subNames[0] }}等{{
+					serverName.subNames.length }}个域名</span>&nbsp;
+				<a href="" title="修改" @click.prevent="updateServerName(index, serverName)">
+					<svg style="display: inline-block;" width="14" height="14" viewBox="0 0 14 14" fill="none"
+						xmlns="http://www.w3.org/2000/svg">
+						<path d="M2.04175 12.25H12.5417" stroke="#657080" stroke-linecap="round"
+							stroke-linejoin="round" />
+						<path d="M3.20825 7.7933V9.91667H5.34244L11.3749 3.88153L9.24432 1.75L3.20825 7.7933Z"
+							stroke="#657080" stroke-linejoin="round" />
+					</svg>
+				</a>&nbsp;
+				<a href="" title="删除" @click.prevent="removeServerName(index)">
+					<svg style="display: inline-block;" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+						<path d="M4.08325 4.08325L9.91659 9.91659" stroke="#657080" stroke-linecap="round"
+							stroke-linejoin="round" />
+						<path d="M4.08325 9.91659L9.91659 4.08325" stroke="#657080" stroke-linecap="round"
+							stroke-linejoin="round" />
+					</svg>
+				</a>
+			</TLabel>
 		</div>
 	</div>
 </template>
 
 <style scoped>
+.server-name-box {
+	font-family: Source Han Sans SC;
+}
+
+.box-actions {
+	font-weight: 400;
+	font-size: 14px;
+	vertical-align: middle;
+	color: rgba(30, 101, 255, 1);
+	gap: 0;
+}
+
+.separator {
+	display: inline-block;
+	width: 1px;
+	height: 18px;
+	background-color: rgba(229, 232, 242, 1);
+	margin: 0 20px;
+	transform: translateY(2px);
+}
+
+:deep(.p-chip.outlined) {
+	background-color: rgba(238, 242, 250, 1);
+	color: rgba(101, 112, 128, 1);
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 14px;
+	border: 1px solid rgba(238, 242, 250, 1)
+}
 </style>

+ 24 - 8
src/components/server/UAMConfigBox.vue

@@ -67,7 +67,7 @@ watch(keyLife, function (v) {
 </script>
 
 <template>
-	<div>
+	<div class="uam-config-box">
 		<input type="hidden" name="uamJSON" :value="JSON.stringify(config)"/>
 		<DefinitionTable>
 			<PriorCheckbox :v-config="config" v-if="vIsLocation || vIsGroup"></PriorCheckbox>
@@ -75,7 +75,7 @@ watch(keyLife, function (v) {
 			<tr>
 				<td class="title">启用5秒盾</td>
 				<td>
-					<TCheckboxBinary v-model="config.isOn"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.isOn">{{ config.isOn ?'开启':'关闭' }}</TCheckboxBinary>
 					<p class="comment">
 						启用后,访问网站时,自动检查浏览器环境,阻止非正常访问。
 					</p>
@@ -84,7 +84,7 @@ watch(keyLife, function (v) {
 			</tbody>
 			<tbody v-show="config.isOn">
 			<tr>
-				<td colspan="2">
+				<td colspan="2" style="height: 30px; padding-top: 4px; padding-bottom: 4px;">
 					<MoreOptionsIndicator @change="showMoreOptions"></MoreOptionsIndicator>
 				</td>
 			</tr>
@@ -94,7 +94,7 @@ watch(keyLife, function (v) {
 				<td>验证有效期</td>
 				<td>
 					<TInputGroup>
-						<TInputText type="text" name="keyLife" v-model="keyLife" maxlength="6" size="6" style="width: 6em"/>
+						<TInputText type="text" name="keyLife" v-model="keyLife" maxlength="6" size="6" style="width: 118px"/>
 						<TInputGroupAddon>
 							<span>秒</span>
 						</TInputGroupAddon>
@@ -106,7 +106,7 @@ watch(keyLife, function (v) {
 				<td>单IP最低QPS</td>
 				<td>
 					<TInputGroup>
-						<TInputText type="text" name="minQPSPerIP" maxlength="6" style="width: 6em" v-model="minQPSPerIP"/>
+						<TInputText type="text" name="minQPSPerIP" maxlength="6" style="width: 118px" v-model="minQPSPerIP"/>
 						<TInputGroupAddon>
 							<span>请求数/秒</span>
 						</TInputGroupAddon>
@@ -117,21 +117,25 @@ watch(keyLife, function (v) {
 			<tr>
 				<td>加入IP白名单</td>
 				<td>
-					<TCheckboxBinary v-model="config.addToWhiteList"></TCheckboxBinary>
+					<TCheckboxBinary v-model="config.addToWhiteList">{{ config.addToWhiteList ?'开启':'关闭' }}</TCheckboxBinary>
 					<p class="comment">选中后,表示验证通过后,将访问者IP加入到临时白名单中,此IP下次访问时不再校验5秒盾;此白名单只对5秒盾有效,不影响其他规则。此选项主要用于可能无法正常使用Cookie的网站。</p>
 				</td>
 			</tr>
 			<tr>
 				<td>例外URL</td>
 				<td class="bg-white dark:bg-black">
-					<URLPatternsBox v-model="config.exceptURLPatterns"></URLPatternsBox>
+					<div>
+						<URLPatternsBox v-model="config.exceptURLPatterns"></URLPatternsBox>
+					</div>
 					<p class="comment">如果填写了例外URL,表示这些URL跳过5秒盾不做处理。</p>
 				</td>
 			</tr>
 			<tr>
 				<td>限制URL</td>
 				<td class="bg-white dark:bg-black">
-					<URLPatternsBox v-model="config.onlyURLPatterns"></URLPatternsBox>
+					<div>
+						<URLPatternsBox v-model="config.onlyURLPatterns"></URLPatternsBox>
+					</div>
 					<p class="comment">如果填写了限制URL,表示只对这些URL进行5秒盾处理;如果不填则表示支持所有的URL。</p>
 				</td>
 			</tr>
@@ -147,4 +151,16 @@ watch(keyLife, function (v) {
 </template>
 
 <style scoped>
+.uam-config-box {
+    margin-top: 14px;
+    font-family: Source Han Sans SC;
+}
+
+.comment {
+	margin-bottom: 0;
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 14px;
+}
 </style>

+ 4 - 3
src/components/ui/TCheckboxBinary.vue

@@ -35,8 +35,7 @@ watch(() => props.modelValue, () => {
 
 <template>
 	<div :class="{'flex gap-2 items-center': $slots.default}">
-		<Checkbox ref="checkboxRef" binary v-bind="$attrs" :inputId="inputId" @change="onChange"
-				  v-model="valueRef"></Checkbox>
+		<Checkbox ref="checkboxRef" binary v-bind="$attrs" :inputId="inputId" @change="onChange" v-model="valueRef"></Checkbox>
 		<label class="cursor-pointer" :for="inputId" v-if="$slots.default">
 			<slot></slot>
 		</label>
@@ -44,5 +43,7 @@ watch(() => props.modelValue, () => {
 </template>
 
 <style scoped>
-
+:deep(.p-checkbox-box) {
+	border-radius: 0;
+}
 </style>

+ 3 - 1
src/components/ui/TDataTable.vue

@@ -85,5 +85,7 @@ provide("$t_columns", columns.value)
 </template>
 
 <style scoped>
-
+:deep(.ui.table) {
+	border-radius: 0;
+}
 </style>

+ 4 - 1
src/components/ui/TTabs.vue

@@ -7,5 +7,8 @@ import TabList from "primevue/tablist";
 </template>
 
 <style scoped>
-
+:deep(.p-tablist-active-bar) {
+	height: 2px !important;
+	background-color: rgba(30, 101, 255, 1) !important;
+}
 </style>

+ 15 - 3
src/layouts/ChildLayout.vue

@@ -3,7 +3,6 @@
 import TMenu from "@/components/ui/TMenu.vue";
 import TDivider from "@/components/ui/TDivider.vue";
 import {onMounted, onUnmounted, ref} from "vue";
-
 const props = defineProps(["ctx", "hasMenu", "hasTab"])
 
 let items = props.ctx.leftMenuItems
@@ -71,7 +70,19 @@ onUnmounted(() => {
 }
 
 .left-box.has-menu {
-	top: 10.8em;
+	/* top: 10.8em;
+	top: 88px!important; */
+	top: 30px!important;
+	position: absolute;
+	border: 1px solid rgba(229, 232, 242, 1);
+}
+
+:deep(.p-menu) {
+	border: none;
+}
+
+:deep(.wrapper) {
+	padding-bottom: 30px!important;
 }
 
 .left-box.has-tab {
@@ -84,7 +95,8 @@ onUnmounted(() => {
 }
 
 .right-box {
-	padding-left: 11.4em;
+	/* padding-left: 11.4em; */
+	padding-left: 170px;
 }
 
 .t-active-item {

+ 1 - 3
src/layouts/ServerSettingLayout.vue

@@ -7,12 +7,10 @@ const props = defineProps(["ctx"])
 
 <template>
 	<SettingMenu :ctx="ctx"></SettingMenu>
-
-	<ChildLayout :ctx="ctx" :has-menu="true">
+	<ChildLayout :ctx="ctx" :has-menu="true" class="child-box">
 		<slot></slot>
 	</ChildLayout>
 </template>
 
 <style scoped>
-
 </style>

+ 0 - 2
src/views/dashboard/index.js

@@ -22,7 +22,6 @@ export default function () {
 				for (let k in resp.data) {
 					this[k] = resp.data[k]
 				}
-
 				let bandwidthUnit = this.uiConfig.bandwidthUnit
 				if (bandwidthUnit == null || bandwidthUnit.length == 0) {
 					bandwidthUnit = "bit"
@@ -63,7 +62,6 @@ export default function () {
 			})
 	})
 
-
 	this.reloadDailyTrafficChart = function () {
 		let bandwidthUnit = this.uiConfig.bandwidthUnit
 

+ 6 - 0
src/views/layout.css

@@ -232,6 +232,12 @@ div.margin, p.margin {
 	width: 4px;
 }
 
+.main .child-box {
+	padding: 30px;
+	min-height: calc(100vh - 100px);
+	background-color: white;
+}
+
 /** 右侧文本子菜单 **/
 .text.menu {
 	overflow-x: auto;

+ 1 - 1
src/views/layout.html

@@ -1,5 +1,5 @@
 <!doctype html>
-<html lang="en">
+<html lang="en" style="background: #edeff4;">
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>

+ 28 - 2
src/views/layout.vue

@@ -100,9 +100,9 @@ const showMainMenu = () => {
 					</TTabs>
 				</TTabView>
 			</div>
-
+			
 			<!-- 功能区 -->
-			<div class="main-box mb-10 md:mb-0">
+			<div class="main-box md:mb-0">
 				<RouterView :key="$route.fullPath"></RouterView>
 			</div>
 
@@ -245,6 +245,32 @@ p.comment em, div.comment em {
 	@apply text-white;
 }
 
+.main {
+	padding-bottom: 1em;
+	font-family: Source Han Sans SC;
+}
+
+.main-box {
+	/* padding: 30px; */
+	/* min-height: calc(100vh - 100px); */
+}
+
+:deep(.p-menu-item-link) {
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 14px;
+	color: rgba(49, 49, 49, 1);
+	padding: 12px 20px;
+}
+:deep(.p-menu-list) {
+	padding: 10px 10px;
+}
+:deep(.p-menu-item-link.on) {
+	text-decoration: none;
+}
+:deep(.t-active-item) {
+	color: rgba(30, 101, 255, 1)!important;
+}
 </style>
 <style lang="postcss">
 .dark {

+ 1 - 2
src/views/servers/@menu.vue

@@ -11,11 +11,10 @@ const props = defineProps(["activeTab"])
 			<NavTab href="/servers" value="index" name="网站管理"></NavTab>
 			<NavTab separator></NavTab>
 			<NavTab href="/servers/create" value="create" name="添加网站" action-create-link></NavTab>
-			<NavTab href="/servers/groups" value="group" name="分组管理"></NavTab>
+			<NavTab href="/servers/groups" value="group" name="分组管理" action-groups></NavTab>
 		</template>
 	</Navbar>
 </template>
 
 <style scoped>
-
 </style>

+ 2 - 2
src/views/servers/index.css

@@ -8,7 +8,7 @@
 	}
 }
 
-.server-td .server-name-box {
+/* .server-td .server-name-box {
 	a {
 		display: none;
 	}
@@ -18,7 +18,7 @@
 	a {
 		display: inline;
 	}
-}
+} */
 
 @media screen and (max-width: 1300px){
 	.server-td .server-name-box {

+ 232 - 103
src/views/servers/index.vue

@@ -27,121 +27,250 @@ const ctx = ctxRef(new Context())
 </script>
 
 <template>
-	<Menu active-tab="index"></Menu>
+	<div class="child-box">
+		<Menu active-tab="index"></Menu>
 
-	<TMessage error="" v-if="!ctx.serversIsEnabled">
-		当前账号下的网站不可用,请检查账号状态以及是否有逾期未支付的账单。
-	</TMessage>
+		<TMessage error="" v-if="!ctx.serversIsEnabled">
+			当前账号下的网站不可用,请检查账号状态以及是否有逾期未支付的账单。
+		</TMessage>
 
-	<WarningMessage v-if="ctx.serversIsEnabled && ctx.countUnpaidBills > 0">
-		<a href="/finance/bills?paidFlag=0">有逾期未支付的账单,可能会影响你的CDN服务正常运行,请尽快完成支付。</a>
-	</WarningMessage>
+		<WarningMessage v-if="ctx.serversIsEnabled && ctx.countUnpaidBills > 0">
+			<a href="/finance/bills?paidFlag=0">有逾期未支付的账单,可能会影响你的CDN服务正常运行,请尽快完成支付。</a>
+		</WarningMessage>
 
-	<form action="/servers" v-show="ctx.checkedServerIds.length == 0">
-		<div class="ui fields inline">
-			<div class="ui field">
-				<TInputText name="keyword" v-model="ctx.keyword" placeholder="域名"/>
+		<form action="/servers" class="search-form">
+			<div class="ui fields inline">
+				<div class="ui field">
+					<TInputText name="keyword" v-model="ctx.keyword" placeholder="输入域名" />
+				</div>
+				<div class="ui field" v-if="ctx.groups.length > 0">
+					<TSelect name="groupId" v-model="ctx.groupId">
+						<TOption value="0">[分组]</TOption>
+						<TOption v-for="group in ctx.groups" :value="group.id">{{ group.name }}</TOption>
+					</TSelect>
+				</div>
+				<div class="ui field">
+					<TButton type="submit" secondary="" class="btn-search">搜索</TButton>
+					&nbsp;
+					<a href="/servers" v-if="ctx.keyword.length > 0 || ctx.groupId > 0">[清除条件]</a>
+				</div>
 			</div>
-			<div class="ui field" v-if="ctx.groups.length > 0">
-				<TSelect name="groupId" v-model="ctx.groupId">
-					<TOption value="0">[分组]</TOption>
-					<TOption v-for="group in ctx.groups" :value="group.id">{{group.name}}</TOption>
-				</TSelect>
-			</div>
-			<div class="ui field">
-				<TButton type="submit" secondary="">搜索</TButton>
-				&nbsp;
-				<a href="/servers" v-if="ctx.keyword.length > 0 || ctx.groupId > 0">[清除条件]</a>
+
+			<div v-if="ctx.checkedServerIds.length > 0">
+				<TButton secondary="" outlined @click.prevent="ctx.resetCheckedServers" class="btn-cancel">取消所选</TButton>
+				<TButton secondary="" outlined @click.prevent="ctx.deleteServers" class="btn-delete">删除所选{{ ctx.checkedServerIds.length }}网站</TButton>
 			</div>
-		</div>
-	</form>
+		</form>
 
-	<NotFoundInfo v-if="ctx.servers.length == 0">暂时还没有任何网站。</NotFoundInfo>
+		<NotFoundInfo v-if="ctx.servers.length == 0">暂时还没有任何网站。</NotFoundInfo>
 
-	<div v-if="ctx.checkedServerIds.length > 0">
-		<TButton secondary="" outlined @click.prevent="ctx.resetCheckedServers">取消所选</TButton> &nbsp; &nbsp;
-		<TButton secondary="" outlined @click.prevent="ctx.deleteServers">删除所选{{ctx.checkedServerIds.length}}网站</TButton>
-	</div>
 
-	<div v-if="ctx.servers.length > 0" class="mt-4">
-		<ListTable :items="ctx.servers">
-			<Column style="width: 1em" class="server-checkbox-td" frozen>
-				<template #header>
-					<TCheckboxBinary @change="ctx.changeAllChecked" v-model="ctx.allChecked"></TCheckboxBinary>
-				</template>
-				<template #body="{data: server}">
-					<TCheckboxBinary v-model="server.isChecked" @change="ctx.changeServerChecked"></TCheckboxBinary>
-				</template>
-			</Column>
-			<Column header="域名" class="domain-column server-td" frozen>
-				<template #body="{data: server}">
-					<a :href="'/servers/server?serverId=' + server.id">
-                <span v-if="server.serverNames.length > 0">
-                    <span v-if="server.serverNames[0].subNames == null || server.serverNames[0].subNames.length == 0"><Keyword :v-word="ctx.keyword">{{server.serverNames[0].name}}</Keyword></span>
-                        <span v-else>{{server.serverNames[0].subNames[0]}}</span>
-                        <span v-if="server.countServerNames > 1">等{{server.countServerNames}}个域名 <PopupIcon :href="'/servers/serverNamesPopup?serverId=' + server.id" height="30em"></PopupIcon></span>
-			        </span>
-						<span v-else class="disabled">-</span>
-					</a>
-
-					<!-- name -->
-					<span class="server-name-box inline-block ml-2">
-						<span class="grey small flex items-center gap-1"><i class="icon tag small"></i><span>{{server.name}}</span>
-							&nbsp; <a href="" @click.prevent="ctx.updateServerName(server.id)">[修改]</a>
+		<div v-if="ctx.servers.length > 0" class="table-box">
+			<ListTable :items="ctx.servers">
+				<Column style="width: 1em" class="server-checkbox-td" frozen>
+					<template #header>
+						<TCheckboxBinary @change="ctx.changeAllChecked" v-model="ctx.allChecked"></TCheckboxBinary>
+					</template>
+					<template #body="{ data: server }">
+						<TCheckboxBinary v-model="server.isChecked" @change="ctx.changeServerChecked"></TCheckboxBinary>
+					</template>
+				</Column>
+				<Column header="域名" class="domain-column server-td" frozen>
+					<template #body="{ data: server }">
+						<a :href="'/servers/server?serverId=' + server.id" class="link-server-name">
+							<span v-if="server.serverNames.length > 0">
+								<span
+									v-if="server.serverNames[0].subNames == null || server.serverNames[0].subNames.length == 0">
+									<Keyword :v-word="ctx.keyword">{{ server.serverNames[0].name }}</Keyword>
+								</span>
+								<span v-else>{{ server.serverNames[0].subNames[0] }}</span>
+								<span v-if="server.countServerNames > 1">等{{ server.countServerNames }}个域名
+									<PopupIcon :href="'/servers/serverNamesPopup?serverId=' + server.id" height="30em">
+									</PopupIcon>
+								</span>
+							</span>
+							<span v-else class="disabled">-</span>
+						</a>
+
+						<br>
+						<!-- name -->
+						<span class="server-name-box inline-block">
+							<span class="grey flex items-center gap-1">
+								<!-- <i class="icon tag mr-2"></i> -->
+								<svg style="margin-right: 4px;" width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+									<path d="M10.5423 7.31128L7.31577 10.5378C7.14697 10.7068 6.9179 10.8017 6.67903 10.8017C6.44015 10.8017 6.2111 10.7068 6.04227 10.5378L2 6.5V2H6.5L10.5423 6.04227C10.8912 6.3933 10.8912 6.96025 10.5423 7.31128Z" stroke="#657080" stroke-width="0.833333" stroke-linejoin="round"/>
+									<path fill-rule="evenodd" clip-rule="evenodd" d="M4.625 5.25C4.97018 5.25 5.25 4.97018 5.25 4.625C5.25 4.27983 4.97018 4 4.625 4C4.27983 4 4 4.27983 4 4.625C4 4.97018 4.27983 5.25 4.625 5.25Z" fill="#657080"/>
+								</svg>
+
+								<span>{{ server.name }}</span>&nbsp; 
+								<a href="" @click.prevent="ctx.updateServerName(server.id)">
+									<svg width="14" height="14" viewBox="0 0 14 14" fill="none"
+										xmlns="http://www.w3.org/2000/svg">
+										<g clip-path="url(#clip0_26_596)">
+											<path
+												d="M5.25005 8.79451L6.90954 8.79455L12.9945 2.70958L11.335 1.05005L5.25 7.13503L5.25005 8.79451Z"
+												stroke="#1E65FF" stroke-linejoin="round" />
+											<path d="M9.67548 2.70972L11.335 4.36926" stroke="#1E65FF"
+												stroke-linecap="round" stroke-linejoin="round" />
+											<path d="M8.04999 1.75H6.64999H1.04999V12.95H12.25V7.35V5.95"
+												stroke="#1E65FF" />
+										</g>
+										<defs>
+											<clipPath id="clip0_26_596">
+												<rect width="14" height="14" fill="white" />
+											</clipPath>
+										</defs>
+									</svg>
+
+								</a>
+							</span>
 						</span>
-					</span>
-
-					<div v-if="server.userPlan != null && server.userPlan.id > 0">
-						<span style="margin-top: 1em" class="small" :class="{grey: !server.userPlan.isExpired, red: server.userPlan.isExpired}">套餐:{{server.userPlan.name}} / {{server.userPlan.dayTo}} <span v-if="server.userPlan.isExpired">已过期</span></span>
-					</div>
-					<div v-if="server.trafficLimitStatus != null">
-						<ServerTrafficLimitStatusViewer v-model="server.trafficLimitStatus"></ServerTrafficLimitStatusViewer>
-					</div>
-					<div v-if="server.groups.length > 0">
-						<span style="margin-top: 1em" class="small grey" v-for="serverGroup in server.groups">[{{serverGroup.name}}] &nbsp; </span>
-					</div>
-				</template>
-			</Column>
-			<Column header="CNAME" class="domain-column">
-				<template #body="{data: server}">
-					{{server.cname}}
-				</template>
-			</Column>
-			<Column header="状态" class="status-column">
-				<template #body="{data: server}">
-					<span v-if="!server.isOn" class="grey">停用中</span>
-					<span v-else-if="server.status.isOk" class="green">正常</span>
-					<span v-else-if="server.status.message.length == 0">检查中</span>
-					<span v-else class="red flex items-center gap-1">
-						<span>{{server.status.message}}</span>
-                		<TipIcon :content="server.status.todo"></TipIcon>
-            		</span>
-				</template>
-			</Column>
-			<Column header="HTTP" class="bool-column">
-				<template #body="{data: server}">
-					<span v-if="server.httpIsOn" class="green">Y</span>
-				</template>
-			</Column>
-			<Column header="HTTPS" class="bool-column">
-				<template #body="{data: server}">
-					<span v-if="server.httpsIsOn" class="green">Y</span>
-				</template>
-			</Column>
-			<Column header="操作" class="three op" frozen align-frozen="right">
-				<template #body="{data: server}">
-					<a :href="'/servers/server?serverId=' + server.id">管理</a> &nbsp;
-					<a href="" v-if="server.isOn" @click.prevent="ctx.updateServerOff(server.id)">停用</a><a href="" v-if="!server.isOn" @click.prevent="ctx.updateServerOn(server.id)"><span class="red">启用</span></a> &nbsp;
-					<a href="" @click.prevent="ctx.deleteServer(server.id)">删除</a>
-				</template>
-			</Column>
-		</ListTable>
-
-		<Pager :data="ctx.page"></Pager>
-	</div>
 
+						<div v-if="server.userPlan != null && server.userPlan.id > 0">
+							<span style="margin-top: 1em" class=""
+								: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">
+							<ServerTrafficLimitStatusViewer v-model="server.trafficLimitStatus">
+							</ServerTrafficLimitStatusViewer>
+						</div>
+						<div v-if="server.groups.length > 0">
+							<span style="margin-top: 1em" class="grey" v-for="serverGroup in server.groups">[{{
+								serverGroup.name }}] &nbsp; </span>
+						</div>
+					</template>
+				</Column>
+				<Column header="CNAME" class="domain-column">
+					<template #body="{ data: server }">
+						{{ server.cname }}
+					</template>
+				</Column>
+				<Column header="状态" class="status-column">
+					<template #body="{ data: server }">
+						<span v-if="!server.isOn" class="grey">停用中</span>
+						<span v-else-if="server.status.isOk" class="green">正常</span>
+						<span v-else-if="server.status.message.length == 0">检查中</span>
+						<span v-else class="flex items-center gap-1" style="color: rgba(255, 67, 67, 1);">
+							<span>{{ server.status.message }}</span>&nbsp;
+							<TipIcon :content="server.status.todo"></TipIcon>
+						</span>
+					</template>
+				</Column>
+				<Column header="HTTP" class="bool-column">
+					<template #body="{ data: server }">
+						<span v-if="server.httpIsOn" class="">Y</span>
+					</template>
+				</Column>
+				<Column header="HTTPS" class="bool-column">
+					<template #body="{ data: server }">
+						<span v-if="server.httpsIsOn" class="">Y</span>
+					</template>
+				</Column>
+				<Column header="操作" class="three op" frozen align-frozen="right">
+					<template #body="{ data: server }">
+						<a :href="'/servers/server?serverId=' + server.id">管理</a> &nbsp;
+						<a href="" v-if="server.isOn" @click.prevent="ctx.updateServerOff(server.id)">停用</a><a href=""
+							v-if="!server.isOn" @click.prevent="ctx.updateServerOn(server.id)"><span
+								style="color: rgba(255, 67, 67, 1);">启用</span></a> &nbsp;
+						<a href="" @click.prevent="ctx.deleteServer(server.id)">删除</a>
+					</template>
+				</Column>
+			</ListTable>
 
+			<Pager :data="ctx.page"></Pager>
+		</div>
+	</div>
 </template>
 
 <style lang="postcss" scoped>
+.search-form {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+}
+
+.btn-search {
+	background: rgba(30, 101, 255, 1);
+	border-radius: 4px;
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 100%;
+	vertical-align: middle;
+	color: rgba(255, 255, 255, 1);
+	line-height: 35px;
+	padding: 0 14px;
+}
+
+.btn-search:hover {
+	background: rgba(29, 83, 222, 1);
+	color: rgba(255, 255, 255, 1);
+}
+
+.btn-cancel {
+	margin-right: 16px;
+	border-radius: 4px;
+	border: 1px solid rgba(229, 232, 242, 1)!important;
+	color: rgba(101, 112, 128, 1)!important;
+	font-weight: 400;
+	font-size: 14px;
+	vertical-align: middle;
+}
+
+.btn-delete {
+	border: 1px solid rgba(30, 101, 255, 1)!important;
+	color: rgba(30, 101, 255, 1)!important;
+	border-radius: 4px;
+}
+
+:deep(.p-inputtext),
+:deep(.p-inputnumber),
+:deep(.p-select) {
+	border-radius: 4px;
+	border-color: rgba(229, 232, 242, 1);
+}
+
+.table-box {
+	margin-top: 14px;
+	font-family: Source Han Sans SC;
+}
+
+.table-box :deep(.ui.table thead th) {
+	padding: 9px 16px;
+	border-color: rgba(229, 232, 242, 1);
+}
+
+.table-box :deep(.p-datatable-tbody > tr > td) {
+	vertical-align: middle;
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 22px;
+	border-color: rgba(229, 232, 242, 1);
+	padding: 9px 16px;
+}
+
+.table-box :deep(td a) {
+	color: rgba(30, 101, 255, 1);
+}
+
+.link-server-name {
+	font-weight: 400;
+	font-size: 14px;
+	color: rgba(30, 101, 255, 1);
+}
+
+:deep(.p-checkbox) {
+	width: 100%;
+	justify-content: center;
+}
+:deep(.p-checkbox-box) {
+	border-radius: 0;
+	border-color: rgba(229, 232, 242, 1);
+}
+:deep(.p-datatable-column-title) {
+	color: rgba(49, 49, 49, 1);
+}
 </style>

+ 13 - 4
src/views/servers/server/settings/@setting_menu.vue

@@ -1,7 +1,7 @@
 <script setup>
 import ServerConfigCopyLink from "@/components/server/ServerConfigCopyLink.vue";
 import {ref} from "vue";
-import TDivider from "@/components/ui/TDivider.vue";
+// import TDivider from "@/components/ui/TDivider.vue";
 import TBreadcrumb from "@/components/ui/TBreadcrumb.vue";
 
 const props = defineProps(["ctx"])
@@ -39,7 +39,7 @@ if (props.ctx.leftMenuActiveItem != null) {
 			<template #item="{item}">
 				<span class="flex">
 					<a :href="item.url" class="p-breadcrumb-item-link">
-						<span class="p-breadcrumb-item-icon" v-if="item.icon" :class="item.icon" data-pc-section="itemicon"></span>
+						<!-- <span class="p-breadcrumb-item-icon" v-if="item.icon" :class="item.icon" data-pc-section="itemicon"></span> -->
 						<span class="p-breadcrumb-item-label">{{ item.name }}</span>
 					</a>
 
@@ -50,10 +50,19 @@ if (props.ctx.leftMenuActiveItem != null) {
 				</span>
 			</template>
 		</TBreadcrumb>
-		<TDivider></TDivider>
+		<!-- <TDivider></TDivider> -->
 	</div>
 </template>
 
 <style scoped>
-
+:deep(.p-breadcrumb) {
+	background-color: #edeff4;
+	padding: 0;
+	margin-bottom: 12px;
+	color: rgba(101, 112, 128, 1);
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 16px;
+	line-height: 24px;
+}
 </style>

+ 4 - 3
src/views/servers/server/settings/cc/index.vue

@@ -126,7 +126,9 @@ const ctx = ctxRef(new Context())
 
 				<HTTPCCConfigBox :v-cc-config="ctx.ccConfig" :default-thresholds="ctx.defaultThresholds"></HTTPCCConfigBox>
 
-				<SubmitButton class="mt-4"></SubmitButton>
+				<div class="submit-button">
+					<SubmitButton class="mt-4"></SubmitButton>
+				</div>
 			</PostForm>
 		</div>
 		<div v-if="!ctx.featureIsOn">
@@ -135,5 +137,4 @@ const ctx = ctxRef(new Context())
 	</ServerSettingLayout>
 </template>
 
-<style lang="postcss" scoped>
-</style>
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>

+ 29 - 5
src/views/servers/server/settings/http/index.vue

@@ -26,13 +26,13 @@ const ctx = ctxRef(new Context())
 				<tr>
 					<td class="title">启用HTTP</td>
 					<td>
-						<TCheckboxBinary name="isOn" value="1" v-model="ctx.httpConfig.isOn"/>
+						<TCheckboxBinary name="isOn" value="1" v-model="ctx.httpConfig.isOn">{{ ctx.httpConfig.isOn ?'开启':'关闭' }}</TCheckboxBinary>
 					</td>
 				</tr>
 				</tbody>
 				<tbody v-show="ctx.httpConfig.isOn && ctx.canSpecifyPort">
 				<tr>
-					<td class="title">绑定端口 *</td>
+					<td class="title">绑定端口<span style="color: rgba(255, 67, 67, 1);">*</span></td>
 					<td>
 						<span class="red" v-if="ctx.httpConfig.isOn && (ctx.httpConfig.addresses == null || ctx.httpConfig.addresses.length == 0)">还没有添加端口绑定,会导致HTTP服务无法访问。</span>
 						<NetworkAddressesBox
@@ -41,8 +41,15 @@ const ctx = ctxRef(new Context())
 							:v-protocol="'http'"
 							:min-port="ctx.minPort"
 							:max-port="ctx.maxPort"></NetworkAddressesBox>
-						<p class="comment">
-							<span v-if="ctx.conflictingPorts.length > 0" class="red">配置错误:<span v-for="(port, index) in ctx.conflictingPorts">{{ port }}<span v-if="index != ctx.conflictingPorts.length - 1">、</span></span><span v-if="ctx.conflictingPorts.length > 1">等</span>端口同HTTPS设置的端口冲突,请删除HTTP或HTTPS中的相关端口。</span>
+						<p class="comment" v-if="ctx.conflictingPorts.length > 0">
+							<span v-if="ctx.conflictingPorts.length > 0" class="red">
+								配置错误:
+								<span v-for="(port, index) in ctx.conflictingPorts">{{ port }}
+									<span v-if="index != ctx.conflictingPorts.length - 1">、</span>
+								</span>
+								<span v-if="ctx.conflictingPorts.length > 1">等</span>
+								端口同HTTPS设置的端口冲突,请删除HTTP或HTTPS中的相关端口。
+							</span>
 						</p>
 					</td>
 				</tr>
@@ -56,10 +63,27 @@ const ctx = ctxRef(new Context())
 				</tr>
 				</tbody>
 			</DefinitionTable>
-			<SubmitButton></SubmitButton>
+			<div class="submit-button">
+				<SubmitButton></SubmitButton>
+			</div>
 		</PostForm>
 	</ServerSettingLayout>
 </template>
 
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>
 <style lang="postcss" scoped>
+:deep(.ui.definition.table > tr:first-child > td) {
+	border-top: unset!important;
+}
+
+:deep(.ui.definition.table > tr > td:first-child:not(.ignored)) {
+	width: 110px;
+	min-width: unset;
+	padding: 12px 8px;
+	background-color: rgba(250, 250, 250, 1);
+}
+
+:deep(.ui.definition.table > tr > td:nth-child(2)) {
+	padding: 12px 8px;
+}
 </style>

+ 2 - 4
src/views/servers/server/settings/reverseProxy/@menu.vue

@@ -10,11 +10,9 @@ const props = defineProps(["ctx"])
 		<template #tabs>
 			<NavTab :href="'/servers/server/settings/reverseProxy?serverId=' + ctx.serverId" value="index" name="源站列表"></NavTab>
 			<NavTab :href="'/servers/server/settings/reverseProxy/scheduling?serverId=' + ctx.serverId" value="scheduling" name="调度算法"></NavTab>
-			<NavTab :href="'/servers/server/settings/reverseProxy/setting?serverId=' + ctx.serverId" value="setting" name="更多设置" action-setting></NavTab>
+			<NavTab :href="'/servers/server/settings/reverseProxy/setting?serverId=' + ctx.serverId" value="setting" name="更多设置"></NavTab>
 		</template>
 	</Navbar>
 </template>
 
-<style scoped lang="postcss">
-
-</style>
+<style scoped lang="postcss" src="@/views/servers/style/server.pcss"></style>

+ 1 - 2
src/views/servers/server/settings/reverseProxy/scheduling.vue

@@ -19,5 +19,4 @@ const ctx = ctxRef(new Context())
 	</ServerSettingLayout>
 </template>
 
-<style lang="postcss" scoped>
-</style>
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>

+ 13 - 12
src/views/servers/server/settings/serverNames/index.vue

@@ -17,14 +17,14 @@ const ctx = ctxRef(new Context())
 
 <template>
 	<ServerSettingLayout :ctx="ctx">
-		<!-- 审核中 -->
+        <!-- 审核中 -->
 		<div v-show="ctx.isAuditing">
 			<WarningMessage>当前网站域名正在审核中,暂时不能访问,请耐心等待管理员审核。</WarningMessage>
 		</div>
 
 		<!-- 审核不通过 -->
-		<div class="mb-4">
-			<TMessage error="" v-if="!ctx.isAuditing && !ctx.auditingResult.isOk">
+		<div class="mb-4" v-if="!ctx.isAuditing && !ctx.auditingResult.isOk">
+			<TMessage error="">
 				审核不通过,原因:{{ ctx.auditingResult.reason }} ({{ ctx.auditingResult.createdTime }}),请修改后重新提交。
 			</TMessage>
 		</div>
@@ -35,19 +35,20 @@ const ctx = ctxRef(new Context())
 				<input type="hidden" name="serverId" :value="ctx.serverId"/>
 				<DefinitionTable>
 					<tbody>
-					<tr>
-						<td class="title">已绑定的域名</td>
-						<td>
-							<ServerNameBox :v-server-names="ctx.serverNames"></ServerNameBox>
-						</td>
-					</tr>
+						<tr>
+							<td class="title">已绑定的域名</td>
+							<td>
+								<ServerNameBox :v-server-names="ctx.serverNames"></ServerNameBox>
+							</td>
+						</tr>
 					</tbody>
 				</DefinitionTable>
-				<SubmitButton></SubmitButton>
+				<div class="submit-button">
+					<SubmitButton></SubmitButton>
+				</div>
 			</PostForm>
 		</div>
 	</ServerSettingLayout>
 </template>
 
-<style lang="postcss" scoped>
-</style>
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>

+ 4 - 3
src/views/servers/server/settings/uam/index.vue

@@ -21,7 +21,9 @@ const ctx = ctxRef(new Context())
 
 				<UAMConfigBox :v-uam-config="ctx.uamConfig"></UAMConfigBox>
 
-				<SubmitButton class="mt-4"></SubmitButton>
+				<div class="submit-button">
+					<SubmitButton class="mt-4"></SubmitButton>
+				</div>
 			</PostForm>
 		</div>
 		<div v-if="!ctx.featureIsOn">
@@ -30,5 +32,4 @@ const ctx = ctxRef(new Context())
 	</ServerSettingLayout>
 </template>
 
-<style lang="postcss" scoped>
-</style>
+<style lang="postcss" scoped src="@/views/servers/style/server.pcss"></style>

+ 86 - 0
src/views/servers/style/server.pcss

@@ -0,0 +1,86 @@
+:deep(.p-tab){
+	color: rgba(101, 112, 128, 1);
+	font-family: Source Han Sans SC;
+	font-weight: 500;
+	font-style: Medium;
+	font-size: 14px;
+	line-height: 20px;
+	margin-right: 40px;
+	padding-left: 0;
+	padding-right: 0;
+}
+:deep(.p-tab-active){
+	color: rgba(30, 101, 255, 1);
+}
+/* .wrapper {
+	padding-bottom: 20px!important;
+} */
+:deep(.wrapper){
+	/* padding-bottom: 20px; */
+	padding-bottom: 20px!important;
+}
+
+:deep(.p-chip.outlined) {
+	background-color: rgba(238, 242, 250, 1);
+	color: rgba(101, 112, 128, 1);
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 14px;
+	border: 1px solid rgba(238, 242, 250, 1);
+	height: 34px;
+	padding: 0 12px;
+}
+
+:deep(.ui.table) {
+	border-radius: 0;
+	margin-bottom: 30px;
+}
+
+:deep(.ui.table td) {
+	padding: 14.5px 20px;
+	font-weight: 400;
+	font-size: 14px;
+}
+
+:deep(.ui.definition.table > tbody > tr > td:nth-child(2)) {
+	padding: 14.5px 30px;
+}
+
+:deep(table.definition > tbody > tr > td:first-child) {
+	width: 160px;
+}
+
+:deep(.ui.definition.table > tbody > tr > td:first-child:not(.ignored)) {
+	background-color: rgba(250, 250, 250, 1);
+}
+
+.submit-button :deep(.p-button) {
+	background-color: rgba(30, 101, 255, 1);
+	width: 60px;
+	height: 34px;
+	border-radius: 4px;
+	font-family: Source Han Sans SC;
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 100%;
+	letter-spacing: 0%;
+	color: rgba(255, 255, 255, 1);
+    margin-top: 0;
+}
+
+.comment {
+	margin-bottom: 0;
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 14px;
+
+	margin-top: 5px;
+}
+
+:deep(.p-inputgroupaddon) {
+	color: rgba(101, 112, 128, 1);
+	font-weight: 400;
+	font-size: 12px;
+	line-height: 14px;
+}