mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	优化编译脚本
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function build() {
 | 
					function build() {
 | 
				
			||||||
	ROOT=$(dirname $0)
 | 
						ROOT=$(dirname "$0")
 | 
				
			||||||
	JS_ROOT=$ROOT/../web/public/js
 | 
						JS_ROOT=$ROOT/../web/public/js
 | 
				
			||||||
	NAME="edge-admin"
 | 
						NAME="edge-admin"
 | 
				
			||||||
	DIST=$ROOT/"../dist/${NAME}"
 | 
						DIST=$ROOT/"../dist/${NAME}"
 | 
				
			||||||
@@ -9,15 +9,15 @@ function build() {
 | 
				
			|||||||
	ARCH=${2}
 | 
						ARCH=${2}
 | 
				
			||||||
	TAG=${3}
 | 
						TAG=${3}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if [ -z $OS ]; then
 | 
						if [ -z "$OS" ]; then
 | 
				
			||||||
		echo "usage: build.sh OS ARCH"
 | 
							echo "usage: build.sh OS ARCH"
 | 
				
			||||||
		exit
 | 
							exit
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
	if [ -z $ARCH ]; then
 | 
						if [ -z "$ARCH" ]; then
 | 
				
			||||||
		echo "usage: build.sh OS ARCH"
 | 
							echo "usage: build.sh OS ARCH"
 | 
				
			||||||
		exit
 | 
							exit
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
	if [ -z $TAG ]; then
 | 
						if [ -z "$TAG" ]; then
 | 
				
			||||||
		TAG="community"
 | 
							TAG="community"
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +25,7 @@ function build() {
 | 
				
			|||||||
	echo "checking required commands ..."
 | 
						echo "checking required commands ..."
 | 
				
			||||||
	commands=("zip" "unzip" "go" "find" "sed")
 | 
						commands=("zip" "unzip" "go" "find" "sed")
 | 
				
			||||||
	for cmd in "${commands[@]}"; do
 | 
						for cmd in "${commands[@]}"; do
 | 
				
			||||||
		if [ `which ${cmd}` ]; then
 | 
							if [ "$(which "${cmd}")" ]; then
 | 
				
			||||||
			echo "checking ${cmd}: ok"
 | 
								echo "checking ${cmd}: ok"
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			echo "checking ${cmd}: not found"
 | 
								echo "checking ${cmd}: not found"
 | 
				
			||||||
@@ -33,49 +33,49 @@ function build() {
 | 
				
			|||||||
		fi
 | 
							fi
 | 
				
			||||||
	done
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VERSION=$(lookup-version $ROOT/../internal/const/const.go)
 | 
						VERSION=$(lookup-version "$ROOT"/../internal/const/const.go)
 | 
				
			||||||
	ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
 | 
						ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# build edge-api
 | 
						# build edge-api
 | 
				
			||||||
	APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go")
 | 
						APINodeVersion=$(lookup-version "$ROOT""/../../EdgeAPI/internal/const/const.go")
 | 
				
			||||||
	echo "building edge-api v${APINodeVersion} ..."
 | 
						echo "building edge-api v${APINodeVersion} ..."
 | 
				
			||||||
	EDGE_API_BUILD_SCRIPT=$ROOT"/../../EdgeAPI/build/build.sh"
 | 
						EDGE_API_BUILD_SCRIPT=$ROOT"/../../EdgeAPI/build/build.sh"
 | 
				
			||||||
	if [ ! -f $EDGE_API_BUILD_SCRIPT ]; then
 | 
						if [ ! -f "$EDGE_API_BUILD_SCRIPT" ]; then
 | 
				
			||||||
		echo "unable to find edge-api build script 'EdgeAPI/build/build.sh'"
 | 
							echo "unable to find edge-api build script 'EdgeAPI/build/build.sh'"
 | 
				
			||||||
		exit
 | 
							exit
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cd $ROOT"/../../EdgeAPI/build"
 | 
						cd "$ROOT""/../../EdgeAPI/build" || exit
 | 
				
			||||||
	echo "=============================="
 | 
						echo "=============================="
 | 
				
			||||||
	./build.sh $OS $ARCH $TAG
 | 
						./build.sh "$OS" "$ARCH" $TAG
 | 
				
			||||||
	echo "=============================="
 | 
						echo "=============================="
 | 
				
			||||||
	cd -
 | 
						cd - || exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # generate files
 | 
					    # generate files
 | 
				
			||||||
    echo "generating files ..."
 | 
					    echo "generating files ..."
 | 
				
			||||||
	go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate
 | 
						go run -tags $TAG "$ROOT"/../cmd/edge-admin/main.go generate
 | 
				
			||||||
	if [ `which uglifyjs` ]; then
 | 
						if [ "$(which uglifyjs)" ]; then
 | 
				
			||||||
    	echo "compress to component.js ..."
 | 
					    	echo "compress to component.js ..."
 | 
				
			||||||
    	uglifyjs --compress --mangle -- ${JS_ROOT}/components.src.js > ${JS_ROOT}/components.js
 | 
					    	uglifyjs --compress --mangle -- "${JS_ROOT}"/components.src.js > "${JS_ROOT}"/components.js
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    	echo "copy to component.js ..."
 | 
					    	echo "copy to component.js ..."
 | 
				
			||||||
    	cp ${JS_ROOT}/components.src.js ${JS_ROOT}/components.js
 | 
					    	cp "${JS_ROOT}"/components.src.js "${JS_ROOT}"/components.js
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# create dir & copy files
 | 
						# create dir & copy files
 | 
				
			||||||
	echo "copying ..."
 | 
						echo "copying ..."
 | 
				
			||||||
	if [ ! -d $DIST ]; then
 | 
						if [ ! -d "$DIST" ]; then
 | 
				
			||||||
		mkdir $DIST
 | 
							mkdir "$DIST"
 | 
				
			||||||
		mkdir $DIST/bin
 | 
							mkdir "$DIST"/bin
 | 
				
			||||||
		mkdir $DIST/configs
 | 
							mkdir "$DIST"/configs
 | 
				
			||||||
		mkdir $DIST/logs
 | 
							mkdir "$DIST"/logs
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cp -R $ROOT/../web $DIST/
 | 
						cp -R "$ROOT"/../web "$DIST"/
 | 
				
			||||||
	rm -f $DIST/web/tmp/*
 | 
						rm -f "$DIST"/web/tmp/*
 | 
				
			||||||
	rm -rf $DIST/web/public/js/components
 | 
						rm -rf "$DIST"/web/public/js/components
 | 
				
			||||||
	rm -f $DIST/web/public/js/components.src.js
 | 
						rm -f "$DIST"/web/public/js/components.src.js
 | 
				
			||||||
	cp $ROOT/configs/server.template.yaml $DIST/configs/
 | 
						cp "$ROOT"/configs/server.template.yaml "$DIST"/configs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# change _plus.[ext] to .[ext]
 | 
						# change _plus.[ext] to .[ext]
 | 
				
			||||||
	if [ "${TAG}" = "plus" ]; then
 | 
						if [ "${TAG}" = "plus" ]; then
 | 
				
			||||||
@@ -83,30 +83,30 @@ function build() {
 | 
				
			|||||||
		exts=("html" "js" "css")
 | 
							exts=("html" "js" "css")
 | 
				
			||||||
		for ext in "${exts[@]}"; do
 | 
							for ext in "${exts[@]}"; do
 | 
				
			||||||
			pattern="*_plus."${ext}
 | 
								pattern="*_plus."${ext}
 | 
				
			||||||
			find $DIST/web/views -type f -name $pattern | \
 | 
								find "$DIST"/web/views -type f -name "$pattern" | \
 | 
				
			||||||
				while read filename; do
 | 
									while read filename; do
 | 
				
			||||||
					mv ${filename} "${filename/_plus."${ext}"/."${ext}"}"
 | 
										mv "${filename}" "${filename/_plus."${ext}"/."${ext}"}"
 | 
				
			||||||
				done
 | 
									done
 | 
				
			||||||
		done
 | 
							done
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip"
 | 
						EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip"
 | 
				
			||||||
	cp $EDGE_API_ZIP_FILE $DIST/
 | 
						cp "$EDGE_API_ZIP_FILE" "$DIST"/
 | 
				
			||||||
	cd $DIST/
 | 
						cd "$DIST"/ || exit
 | 
				
			||||||
	unzip -q $(basename $EDGE_API_ZIP_FILE)
 | 
						unzip -q "$(basename "$EDGE_API_ZIP_FILE")"
 | 
				
			||||||
	rm -f $(basename $EDGE_API_ZIP_FILE)
 | 
						rm -f "$(basename "$EDGE_API_ZIP_FILE")"
 | 
				
			||||||
	cd -
 | 
						cd - || exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# build
 | 
						# build
 | 
				
			||||||
	echo "building "${NAME}" ..."
 | 
						echo "building ${NAME} ..."
 | 
				
			||||||
	env GOOS=$OS GOARCH=$ARCH go build -trimpath -tags $TAG -ldflags="-s -w" -o $DIST/bin/${NAME} $ROOT/../cmd/edge-admin/main.go
 | 
						env GOOS="$OS" GOARCH="$ARCH" go build -trimpath -tags $TAG -ldflags="-s -w" -o "$DIST"/bin/${NAME} "$ROOT"/../cmd/edge-admin/main.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# delete hidden files
 | 
						# delete hidden files
 | 
				
			||||||
	find $DIST -name ".DS_Store" -delete
 | 
						find "$DIST" -name ".DS_Store" -delete
 | 
				
			||||||
	find $DIST -name ".gitignore" -delete
 | 
						find "$DIST" -name ".gitignore" -delete
 | 
				
			||||||
	find $DIST -name "*.less" -delete
 | 
						find "$DIST" -name "*.less" -delete
 | 
				
			||||||
	find $DIST -name "*.css.map" -delete
 | 
						find "$DIST" -name "*.css.map" -delete
 | 
				
			||||||
	find $DIST -name "*.js.map" -delete
 | 
						find "$DIST" -name "*.js.map" -delete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# zip
 | 
						# zip
 | 
				
			||||||
	echo "zip files ..."
 | 
						echo "zip files ..."
 | 
				
			||||||
@@ -123,15 +123,15 @@ function build() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function lookup-version() {
 | 
					function lookup-version() {
 | 
				
			||||||
	FILE=$1
 | 
						FILE=$1
 | 
				
			||||||
	VERSION_DATA=$(cat $FILE)
 | 
						VERSION_DATA=$(cat "$FILE")
 | 
				
			||||||
	re="Version[ ]+=[ ]+\"([0-9.]+)\""
 | 
						re="Version[ ]+=[ ]+\"([0-9.]+)\""
 | 
				
			||||||
	if [[ $VERSION_DATA =~ $re ]]; then
 | 
						if [[ $VERSION_DATA =~ $re ]]; then
 | 
				
			||||||
		VERSION=${BASH_REMATCH[1]}
 | 
							VERSION=${BASH_REMATCH[1]}
 | 
				
			||||||
		echo $VERSION
 | 
							echo "$VERSION"
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		echo "could not match version"
 | 
							echo "could not match version"
 | 
				
			||||||
		exit
 | 
							exit
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build $1 $2 $3
 | 
					build "$1" "$2" "$3"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								dist/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,2 @@
 | 
				
			|||||||
*.zip
 | 
					*.zip
 | 
				
			||||||
shield-admin
 | 
					edge-admin
 | 
				
			||||||
@@ -417,48 +417,191 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 | 
				
			|||||||
		</tbody>
 | 
							</tbody>
 | 
				
			||||||
	</table>
 | 
						</table>
 | 
				
			||||||
	<div class="margin"></div>
 | 
						<div class="margin"></div>
 | 
				
			||||||
</div>`}),Vue.component("ns-route-ranges-box",{props:["v-ranges"],data:function(){let e=this.vRanges;return{ranges:e=null==e?[]:e,isAdding:!1,isAddingBatch:!1,ipRangeFrom:"",ipRangeTo:"",batchIPRange:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipRangeFrom.focus()},100)},remove:function(e){this.ranges.$remove(e)},cancelIPRange:function(){this.isAdding=!1,this.ipRangeFrom="",this.ipRangeTo=""},confirmIPRange:function(){let e=this;this.ipRangeFrom=this.ipRangeFrom.trim(),this.validateIP(this.ipRangeFrom)?(this.ipRangeTo=this.ipRangeTo.trim(),this.validateIP(this.ipRangeTo)?(this.ranges.push({type:"ipRange",params:{ipFrom:this.ipRangeFrom,ipTo:this.ipRangeTo}}),this.cancelIPRange()):teaweb.warn("结束IP填写错误",function(){e.$refs.ipRangeTo.focus()})):teaweb.warn("开始IP填写错误",function(){e.$refs.ipRangeFrom.focus()})},addBatch:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPRange.focus()},100)},cancelBatchIPRange:function(){this.isAddingBatch=!1,this.batchIPRange=""},confirmBatchIPRange:function(){let a=this,e=this.batchIPRange;if(0==e.length)teaweb.warn("请填写要加入的IP范围",function(){a.$refs.batchIPRange.focus()});else{let n=[],o="";e.split("\n").forEach(function(t){if(0!=(t=t.trim()).length){let e=(t=t.replace(",",",")).split(",");var i,s;2!=e.length?o=t:(i=e[0].trim(),s=e[1].trim(),a.validateIP(i)&&a.validateIP(s)?n.push({type:"ipRange",params:{ipFrom:i,ipTo:s}}):o=t)}}),0<o.length?teaweb.warn("'"+o+"'格式错误",function(){a.$refs.batchIPRange.focus()}):(n.forEach(function(e){a.ranges.push(e)}),this.cancelBatchIPRange())}},validateIP:function(e){if(!e.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))return!1;let t=e.split("."),i=!0;return t.forEach(function(e){255<parseInt(e)&&(i=!1)}),i}},template:`<div>
 | 
					</div>`}),Vue.component("ns-route-ranges-box",{props:["v-ranges"],data:function(){let e=this.vRanges;return{ranges:e=null==e?[]:e,isAdding:!1,isAddingBatch:!1,rangeType:"ipRange",isReverse:!1,ipRangeFrom:"",ipRangeTo:"",batchIPRange:"",ipCIDR:"",batchIPCIDR:"",regions:[],regionType:"country"}},methods:{addIPRange:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipRangeFrom.focus()},100)},addCIDR:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipCIDR.focus()},100)},addRegions:function(){this.isAdding=!0},addRegion:function(e){this.regionType=e},remove:function(e){this.ranges.$remove(e)},cancelIPRange:function(){this.isAdding=!1,this.ipRangeFrom="",this.ipRangeTo="",this.isReverse=!1},cancelIPCIDR:function(){this.isAdding=!1,this.ipCIDR="",this.isReverse=!1},cancelRegions:function(){this.isAdding=!1,this.regions=[],this.regionType="country",this.isReverse=!1},confirmIPRange:function(){let e=this;this.ipRangeFrom=this.ipRangeFrom.trim(),this.validateIP(this.ipRangeFrom)?(this.ipRangeTo=this.ipRangeTo.trim(),this.validateIP(this.ipRangeTo)?(this.ranges.push({type:"ipRange",params:{ipFrom:this.ipRangeFrom,ipTo:this.ipRangeTo,isReverse:this.isReverse}}),this.cancelIPRange()):teaweb.warn("结束IP填写错误",function(){e.$refs.ipRangeTo.focus()})):teaweb.warn("开始IP填写错误",function(){e.$refs.ipRangeFrom.focus()})},confirmIPCIDR:function(){let e=this;0==this.ipCIDR.length?teaweb.warn("请填写CIDR",function(){e.$refs.ipCIDR.focus()}):this.validateCIDR(this.ipCIDR)?(this.ranges.push({type:"cidr",params:{cidr:this.ipCIDR,isReverse:this.isReverse}}),this.cancelIPCIDR()):teaweb.warn("请输入正确的CIDR",function(){e.$refs.ipCIDR.focus()})},confirmRegions:function(){0==this.regions.length||this.ranges.push({type:"region",params:{regions:this.regions,isReverse:this.isReverse}}),this.cancelRegions()},addBatchIPRange:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPRange.focus()},100)},addBatchCIDR:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPCIDR.focus()},100)},cancelBatchIPRange:function(){this.isAddingBatch=!1,this.batchIPRange="",this.isReverse=!1},cancelBatchIPCIDR:function(){this.isAddingBatch=!1,this.batchIPCIDR="",this.isReverse=!1},confirmBatchIPRange:function(){let a=this,e=this.batchIPRange;if(0==e.length)teaweb.warn("请填写要加入的IP范围",function(){a.$refs.batchIPRange.focus()});else{let n=[],o="";e.split("\n").forEach(function(t){if(0!=(t=t.trim()).length){let e=(t=t.replace(",",",")).split(",");var i,s;2!=e.length?o=t:(i=e[0].trim(),s=e[1].trim(),a.validateIP(i)&&a.validateIP(s)?n.push({type:"ipRange",params:{ipFrom:i,ipTo:s,isReverse:a.isReverse}}):o=t)}}),0<o.length?teaweb.warn("'"+o+"'格式错误",function(){a.$refs.batchIPRange.focus()}):(n.forEach(function(e){a.ranges.push(e)}),this.cancelBatchIPRange())}},confirmBatchIPCIDR:function(){let n=this,e=this.batchIPCIDR;if(0==e.length)teaweb.warn("请填写要加入的CIDR",function(){n.$refs.batchIPCIDR.focus()});else{let i=[],s="";e.split("\n").forEach(function(e){var t=e.trim();0!=t.length&&(n.validateCIDR(t)?i.push({type:"cidr",params:{cidr:t,isReverse:n.isReverse}}):s=e)}),0<s.length?teaweb.warn("'"+s+"'格式错误",function(){n.$refs.batchIPCIDR.focus()}):(i.forEach(function(e){n.ranges.push(e)}),this.cancelBatchIPCIDR())}},selectRegionCountry:function(e){null!=e&&(this.regions.push({type:"country",id:e.id,name:e.name}),this.$refs.regionCountryComboBox.clear())},selectRegionProvince:function(e){null!=e&&(this.regions.push({type:"province",id:e.id,name:e.name}),this.$refs.regionProvinceComboBox.clear())},selectRegionCity:function(e){null!=e&&(this.regions.push({type:"city",id:e.id,name:e.name}),this.$refs.regionCityComboBox.clear())},selectRegionProvider:function(e){null!=e&&(this.regions.push({type:"provider",id:e.id,name:e.name}),this.$refs.regionProviderComboBox.clear())},removeRegion:function(e){this.regions.$remove(e)},validateIP:function(i){if(0!=i.length){if(0<=i.indexOf(":")){let e=i.split(":");if(8<e.length)return!1;let t=!0;return e.forEach(function(e){/^[\da-fA-F]{0,4}$/.test(e)||(t=!1)}),t}if(!i.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))return!1;let e=i.split("."),t=!0;return e.forEach(function(e){255<parseInt(e)&&(t=!1)}),t}},validateCIDR:function(e){var t=e.split("/");if(2!=t.length)return!1;var i=t[0];if(!this.validateIP(i))return!1;i=t[1];return!!/^\d{1,3}$/.test(i)&&(i=parseInt(i,10),0<=e.indexOf(":")?i<=128:i<=32)},updateRangeType:function(e){this.rangeType=e}},template:`<div>
 | 
				
			||||||
	<input type="hidden" name="rangesJSON" :value="JSON.stringify(ranges)"/>
 | 
						<input type="hidden" name="rangesJSON" :value="JSON.stringify(ranges)"/>
 | 
				
			||||||
	<div v-if="ranges.length > 0">
 | 
						<div v-if="ranges.length > 0">
 | 
				
			||||||
		<div class="ui label tiny basic" v-for="(range, index) in ranges" style="margin-bottom: 0.3em">
 | 
							<div class="ui label tiny basic" v-for="(range, index) in ranges" style="margin-bottom: 0.3em">
 | 
				
			||||||
 | 
								<span class="red" v-if="range.params.isReverse">[排除]</span>
 | 
				
			||||||
			<span v-if="range.type == 'ipRange'">IP范围:</span>
 | 
								<span v-if="range.type == 'ipRange'">IP范围:</span>
 | 
				
			||||||
			{{range.params.ipFrom}} - {{range.params.ipTo}}   <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
 | 
								<span v-if="range.type == 'cidr'">CIDR:</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'region'">区域:</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'ipRange'">{{range.params.ipFrom}} - {{range.params.ipTo}}</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'cidr'">{{range.params.cidr}}</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'region'"><span v-for="(region, index) in range.params.regions">{{region.name}}<span v-if="index < range.params.regions.length - 1">,</span></span></span>
 | 
				
			||||||
 | 
								   <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="ui divider"></div>
 | 
							<div class="ui divider"></div>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<!-- 添加单个 -->
 | 
						<!-- IP范围 -->
 | 
				
			||||||
	<div style="margin-bottom: 1em" v-show="isAdding">
 | 
						<div v-if="rangeType == 'ipRange'">
 | 
				
			||||||
		<div class="ui fields inline">
 | 
							<!-- 添加单个IP范围 -->
 | 
				
			||||||
			<div class="ui field">
 | 
							<div style="margin-bottom: 1em" v-show="isAdding">
 | 
				
			||||||
				<input type="text" placeholder="开始IP" maxlength="15" size="15" v-model="ipRangeFrom" ref="ipRangeFrom"  @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
								<table class="ui table">
 | 
				
			||||||
			</div>
 | 
									<tr>
 | 
				
			||||||
			<div class="ui field">-</div>
 | 
										<td class="title">开始IP *</td>
 | 
				
			||||||
			<div class="ui field">
 | 
										<td>
 | 
				
			||||||
				<input type="text" placeholder="结束IP" maxlength="15" size="15" v-model="ipRangeTo" ref="ipRangeTo" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
											<input type="text" placeholder="开始IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeFrom" ref="ipRangeFrom"  @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
				
			||||||
			</div>
 | 
										</td>
 | 
				
			||||||
			<div class="ui field">
 | 
									</tr>
 | 
				
			||||||
				<button class="ui button tiny" type="button" @click.prevent="confirmIPRange">确定</button>  
 | 
									<tr>
 | 
				
			||||||
				<a href="" @click.prevent="cancelIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
										<td>结束IP *</td>
 | 
				
			||||||
			</div>
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="text" placeholder="结束IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeTo" ref="ipRangeTo" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmIPRange">确定</button>  
 | 
				
			||||||
 | 
										<a href="" @click.prevent="cancelIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<!-- 添加多个 -->
 | 
							<!-- 添加多个IP范围 -->
 | 
				
			||||||
	<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
							<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
				
			||||||
		<div class="ui field">
 | 
								<table class="ui table">
 | 
				
			||||||
			<textarea rows="5" ref="batchIPRange" v-model="batchIPRange"></textarea>	
 | 
									<tr>
 | 
				
			||||||
			<p class="comment">每行一条,格式为<code-label>开始IP,结束IP</code-label>,比如<code-label>192.168.1.100,192.168.1.200</code-label>。</p>	
 | 
										<td class="title">IP范围列表 *</td>
 | 
				
			||||||
		</div>
 | 
										<td>
 | 
				
			||||||
		<div class="ui field">
 | 
											<textarea rows="5" ref="batchIPRange" v-model="batchIPRange"></textarea>	
 | 
				
			||||||
 | 
											<p class="comment">每行一条,格式为<code-label>开始IP,结束IP</code-label>,比如<code-label>192.168.1.100,192.168.1.200</code-label>。</p>	
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
			<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPRange">确定</button>  
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPRange">确定</button>  
 | 
				
			||||||
			<a href="" @click.prevent="cancelBatchIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
									<a href="" @click.prevent="cancelBatchIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addIPRange">添加单个IP范围</button>  
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addBatchIPRange">批量添加IP范围</button>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<div v-if="!isAdding && !isAddingBatch">
 | 
						<!-- CIDR -->
 | 
				
			||||||
		<button class="ui button tiny" type="button" @click.prevent="add">单个添加</button>  
 | 
						<div v-if="rangeType == 'cidr'">
 | 
				
			||||||
		<button class="ui button tiny" type="button" @click.prevent="addBatch">批量添加</button>
 | 
							<!-- 添加单个IP范围 -->
 | 
				
			||||||
 | 
							<div style="margin-bottom: 1em" v-show="isAdding">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">CIDR *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="text" placeholder="IP/MASK" maxlength="40" size="40" style="width: 15em" v-model="ipCIDR" ref="ipCIDR"  @keyup.enter="confirmIPCIDR" @keypress.enter.prevent="1"/>
 | 
				
			||||||
 | 
											<p class="comment">类似于<code-label>192.168.2.1/24</code-label>。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmIPCIDR">确定</button>  
 | 
				
			||||||
 | 
										<a href="" @click.prevent="cancelIPCIDR" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<!-- 添加多个IP范围 -->
 | 
				
			||||||
 | 
							<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">IP范围列表 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<textarea rows="5" ref="batchIPCIDR" v-model="batchIPCIDR"></textarea>	
 | 
				
			||||||
 | 
											<p class="comment">每行一条,格式为<code-label>IP/MASK</code-label>,比如<code-label>192.168.2.1/24</code-label>。</p>	
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPCIDR">确定</button>  
 | 
				
			||||||
 | 
									<a href="" @click.prevent="cancelBatchIPCIDR" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addCIDR">添加单个CIDR</button>  
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addBatchCIDR">批量添加CIDR</button>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<!-- 区域 -->
 | 
				
			||||||
 | 
						<div v-if="rangeType == 'region'">
 | 
				
			||||||
 | 
							<!-- 添加区域 -->
 | 
				
			||||||
 | 
							<div v-if="isAdding">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>已添加</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<div v-for="(region, index) in regions" class="ui label small basic">
 | 
				
			||||||
 | 
												{{region.name}} <a href="" title="删除" @click.prevent="removeRegion(index)"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">添加新<span v-if="regionType == 'country'">国家/地区</span><span v-if="regionType == 'province'">省份</span><span v-if="regionType == 'city'">城市</span><span v-if="regionType == 'provider'">ISP</span>
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
										 	<!-- region country name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'country'">
 | 
				
			||||||
 | 
												<combo-box title="" width="14em" data-url="/ui/countryOptions" data-key="countries" placeholder="点这里选择国家/地区" @change="selectRegionCountry" ref="regionCountryComboBox" key="combo-box-country"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- region province name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'province'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/provinceOptions" data-key="provinces" placeholder="点这里选择省份" @change="selectRegionProvince" ref="regionProvinceComboBox" key="combo-box-province"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- region city name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'city'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/cityOptions" data-key="cities" placeholder="点这里选择城市" @change="selectRegionCity" ref="regionCityComboBox" key="combo-box-city"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- ISP Name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'provider'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/providerOptions" data-key="providers" placeholder="点这里选择ISP" @change="selectRegionProvider" ref="regionProviderComboBox" key="combo-box-isp"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											<div style="margin-top: 1em">
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'country'}" type="button" @click.prevent="addRegion('country')">添加国家/地区</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'province'}" type="button" @click.prevent="addRegion('province')">添加省份</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'city'}" type="button" @click.prevent="addRegion('city')">添加城市</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'provider'}" type="button" @click.prevent="addRegion('provider')">ISP</button>  
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</td>	
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmRegions">确定</button>  
 | 
				
			||||||
 | 
									<a href="" @click.prevent="cancelRegions" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addRegions">添加区域</button>  
 | 
				
			||||||
 | 
							</div>	
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</div>`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`<div>
 | 
					</div>`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`<div>
 | 
				
			||||||
	<div v-if="routes.length > 0">
 | 
						<div v-if="routes.length > 0">
 | 
				
			||||||
@@ -2416,7 +2559,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 | 
				
			|||||||
	</tr>
 | 
						</tr>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
<div class="ui margin"></div>
 | 
					<div class="ui margin"></div>
 | 
				
			||||||
</div>`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","deflate"],level:5,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["text/*","application/*","font/*"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],conds:null}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},watch:{"config.level":function(e){let t=parseInt(e);isNaN(t)||t<1?t=1:10<t&&(t=10),this.config.level=t}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0<e.length&&"."!=e[0]&&(i[t]="."+e)}),this.config.extensions=i},changeMimeTypes:function(e){this.config.mimeTypes=e},changeAdvancedVisible:function(){this.moreOptionsVisible=!this.moreOptionsVisible},changeConds:function(e){this.config.conds=e},changeType:function(){this.config.types=[];let t=this;this.allTypes.forEach(function(e){e.isOn&&t.config.types.push(e.code)})},initSortableTypes:function(){let s=document.querySelector("#compression-types-box"),n=this;Sortable.create(s,{draggable:".checkbox",handle:".icon.handle",onStart:function(){},onUpdate:function(e){let t=s.querySelectorAll(".checkbox"),i=[];t.forEach(function(e){e=e.getAttribute("data-code");i.push(e)}),n.config.types=i}})}},template:`<div>
 | 
					</div>`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","zstd","deflate"],level:5,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["text/*","application/*","font/*"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],conds:null}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0},{name:"ZSTD",code:"zstd",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},watch:{"config.level":function(e){let t=parseInt(e);isNaN(t)||t<1?t=1:10<t&&(t=10),this.config.level=t}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0<e.length&&"."!=e[0]&&(i[t]="."+e)}),this.config.extensions=i},changeMimeTypes:function(e){this.config.mimeTypes=e},changeAdvancedVisible:function(){this.moreOptionsVisible=!this.moreOptionsVisible},changeConds:function(e){this.config.conds=e},changeType:function(){this.config.types=[];let t=this;this.allTypes.forEach(function(e){e.isOn&&t.config.types.push(e.code)})},initSortableTypes:function(){let s=document.querySelector("#compression-types-box"),n=this;Sortable.create(s,{draggable:".checkbox",handle:".icon.handle",onStart:function(){},onUpdate:function(e){let t=s.querySelectorAll(".checkbox"),i=[];t.forEach(function(e){e=e.getAttribute("data-code");i.push(e)}),n.config.types=i}})}},template:`<div>
 | 
				
			||||||
	<input type="hidden" name="compressionJSON" :value="JSON.stringify(config)"/>
 | 
						<input type="hidden" name="compressionJSON" :value="JSON.stringify(config)"/>
 | 
				
			||||||
	<table class="ui table definition selectable">
 | 
						<table class="ui table definition selectable">
 | 
				
			||||||
		<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
 | 
							<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
 | 
				
			||||||
@@ -2463,7 +2606,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 | 
				
			|||||||
				<td>
 | 
									<td>
 | 
				
			||||||
					<div class="ui checkbox">
 | 
										<div class="ui checkbox">
 | 
				
			||||||
						<input type="checkbox" v-model="config.useDefaultTypes" id="compression-use-default"/>
 | 
											<input type="checkbox" v-model="config.useDefaultTypes" id="compression-use-default"/>
 | 
				
			||||||
						<label v-if="config.useDefaultTypes" for="compression-use-default">使用默认顺序<span class="grey small">(brotli、gzip、deflate)</span></label>
 | 
											<label v-if="config.useDefaultTypes" for="compression-use-default">使用默认顺序<span class="grey small">(brotli、gzip、 zstd、deflate)</span></label>
 | 
				
			||||||
						<label v-if="!config.useDefaultTypes" for="compression-use-default">使用默认顺序</label>
 | 
											<label v-if="!config.useDefaultTypes" for="compression-use-default">使用默认顺序</label>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<div v-show="!config.useDefaultTypes">
 | 
										<div v-show="!config.useDefaultTypes">
 | 
				
			||||||
@@ -4291,7 +4434,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 | 
				
			|||||||
	<!-- 当前选中 -->
 | 
						<!-- 当前选中 -->
 | 
				
			||||||
	<div v-if="selectedItem != null">
 | 
						<div v-if="selectedItem != null">
 | 
				
			||||||
		<input type="hidden" :name="name" :value="selectedItem.value"/>
 | 
							<input type="hidden" :name="name" :value="selectedItem.value"/>
 | 
				
			||||||
		<a href="" class="ui label basic" style="line-height: 1.4; font-weight: normal; font-size: 1em" ref="selectedLabel" @click.prevent="submitForm"><span>{{title}}:{{selectedItem.name}}</span>
 | 
							<a href="" class="ui label basic" style="line-height: 1.4; font-weight: normal; font-size: 1em" ref="selectedLabel" @click.prevent="submitForm"><span><span v-if="title != null && title.length > 0">{{title}}:</span>{{selectedItem.name}}</span>
 | 
				
			||||||
			<span title="清除" @click.prevent="reset"><i class="icon remove small"></i></span>
 | 
								<span title="清除" @click.prevent="reset"><i class="icon remove small"></i></span>
 | 
				
			||||||
		</a>
 | 
							</a>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1438,21 +1438,46 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
			isAdding: false,
 | 
								isAdding: false,
 | 
				
			||||||
			isAddingBatch: false,
 | 
								isAddingBatch: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 类型
 | 
				
			||||||
 | 
								rangeType: "ipRange",
 | 
				
			||||||
 | 
								isReverse: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// IP范围
 | 
								// IP范围
 | 
				
			||||||
			ipRangeFrom: "",
 | 
								ipRangeFrom: "",
 | 
				
			||||||
			ipRangeTo: "",
 | 
								ipRangeTo: "",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			batchIPRange: ""
 | 
								batchIPRange: "",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// CIDR
 | 
				
			||||||
 | 
								ipCIDR: "",
 | 
				
			||||||
 | 
								batchIPCIDR: "",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// region
 | 
				
			||||||
 | 
								regions: [],
 | 
				
			||||||
 | 
								regionType: "country"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		add: function () {
 | 
							addIPRange: function () {
 | 
				
			||||||
			this.isAdding = true
 | 
								this.isAdding = true
 | 
				
			||||||
			let that = this
 | 
								let that = this
 | 
				
			||||||
			setTimeout(function () {
 | 
								setTimeout(function () {
 | 
				
			||||||
				that.$refs.ipRangeFrom.focus()
 | 
									that.$refs.ipRangeFrom.focus()
 | 
				
			||||||
			}, 100)
 | 
								}, 100)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							addCIDR: function () {
 | 
				
			||||||
 | 
								this.isAdding = true
 | 
				
			||||||
 | 
								let that = this
 | 
				
			||||||
 | 
								setTimeout(function () {
 | 
				
			||||||
 | 
									that.$refs.ipCIDR.focus()
 | 
				
			||||||
 | 
								}, 100)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							addRegions: function () {
 | 
				
			||||||
 | 
								this.isAdding = true
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							addRegion: function (regionType) {
 | 
				
			||||||
 | 
								this.regionType = regionType
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		remove: function (index) {
 | 
							remove: function (index) {
 | 
				
			||||||
			this.ranges.$remove(index)
 | 
								this.ranges.$remove(index)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -1460,6 +1485,18 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
			this.isAdding = false
 | 
								this.isAdding = false
 | 
				
			||||||
			this.ipRangeFrom = ""
 | 
								this.ipRangeFrom = ""
 | 
				
			||||||
			this.ipRangeTo = ""
 | 
								this.ipRangeTo = ""
 | 
				
			||||||
 | 
								this.isReverse = false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							cancelIPCIDR: function () {
 | 
				
			||||||
 | 
								this.isAdding = false
 | 
				
			||||||
 | 
								this.ipCIDR = ""
 | 
				
			||||||
 | 
								this.isReverse = false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							cancelRegions: function () {
 | 
				
			||||||
 | 
								this.isAdding = false
 | 
				
			||||||
 | 
								this.regions = []
 | 
				
			||||||
 | 
								this.regionType = "country"
 | 
				
			||||||
 | 
								this.isReverse = false
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		confirmIPRange: function () {
 | 
							confirmIPRange: function () {
 | 
				
			||||||
			// 校验IP
 | 
								// 校验IP
 | 
				
			||||||
@@ -1484,21 +1521,74 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
				type: "ipRange",
 | 
									type: "ipRange",
 | 
				
			||||||
				params: {
 | 
									params: {
 | 
				
			||||||
					ipFrom: this.ipRangeFrom,
 | 
										ipFrom: this.ipRangeFrom,
 | 
				
			||||||
					ipTo: this.ipRangeTo
 | 
										ipTo: this.ipRangeTo,
 | 
				
			||||||
 | 
										isReverse: this.isReverse
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			this.cancelIPRange()
 | 
								this.cancelIPRange()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		addBatch: function () {
 | 
							confirmIPCIDR: function () {
 | 
				
			||||||
 | 
								let that = this
 | 
				
			||||||
 | 
								if (this.ipCIDR.length == 0) {
 | 
				
			||||||
 | 
									teaweb.warn("请填写CIDR", function () {
 | 
				
			||||||
 | 
										that.$refs.ipCIDR.focus()
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!this.validateCIDR(this.ipCIDR)) {
 | 
				
			||||||
 | 
									teaweb.warn("请输入正确的CIDR", function () {
 | 
				
			||||||
 | 
										that.$refs.ipCIDR.focus()
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this.ranges.push({
 | 
				
			||||||
 | 
									type: "cidr",
 | 
				
			||||||
 | 
									params: {
 | 
				
			||||||
 | 
										cidr: this.ipCIDR,
 | 
				
			||||||
 | 
										isReverse: this.isReverse
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.cancelIPCIDR()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							confirmRegions: function () {
 | 
				
			||||||
 | 
								if (this.regions.length == 0) {
 | 
				
			||||||
 | 
									this.cancelRegions()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.ranges.push({
 | 
				
			||||||
 | 
									type: "region",
 | 
				
			||||||
 | 
									params: {
 | 
				
			||||||
 | 
										regions: this.regions,
 | 
				
			||||||
 | 
										isReverse: this.isReverse
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.cancelRegions()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							addBatchIPRange: function () {
 | 
				
			||||||
			this.isAddingBatch = true
 | 
								this.isAddingBatch = true
 | 
				
			||||||
			let that = this
 | 
								let that = this
 | 
				
			||||||
			setTimeout(function () {
 | 
								setTimeout(function () {
 | 
				
			||||||
				that.$refs.batchIPRange.focus()
 | 
									that.$refs.batchIPRange.focus()
 | 
				
			||||||
			}, 100)
 | 
								}, 100)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							addBatchCIDR: function () {
 | 
				
			||||||
 | 
								this.isAddingBatch = true
 | 
				
			||||||
 | 
								let that = this
 | 
				
			||||||
 | 
								setTimeout(function () {
 | 
				
			||||||
 | 
									that.$refs.batchIPCIDR.focus()
 | 
				
			||||||
 | 
								}, 100)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		cancelBatchIPRange: function () {
 | 
							cancelBatchIPRange: function () {
 | 
				
			||||||
			this.isAddingBatch = false
 | 
								this.isAddingBatch = false
 | 
				
			||||||
			this.batchIPRange = ""
 | 
								this.batchIPRange = ""
 | 
				
			||||||
 | 
								this.isReverse = false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							cancelBatchIPCIDR: function () {
 | 
				
			||||||
 | 
								this.isAddingBatch = false
 | 
				
			||||||
 | 
								this.batchIPCIDR = ""
 | 
				
			||||||
 | 
								this.isReverse = false
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		confirmBatchIPRange: function () {
 | 
							confirmBatchIPRange: function () {
 | 
				
			||||||
			let that = this
 | 
								let that = this
 | 
				
			||||||
@@ -1533,7 +1623,8 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
					type: "ipRange",
 | 
										type: "ipRange",
 | 
				
			||||||
					params: {
 | 
										params: {
 | 
				
			||||||
						ipFrom: ipFrom,
 | 
											ipFrom: ipFrom,
 | 
				
			||||||
						ipTo: ipTo
 | 
											ipTo: ipTo,
 | 
				
			||||||
 | 
											isReverse: that.isReverse
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
@@ -1548,7 +1639,114 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
			})
 | 
								})
 | 
				
			||||||
			this.cancelBatchIPRange()
 | 
								this.cancelBatchIPRange()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							confirmBatchIPCIDR: function () {
 | 
				
			||||||
 | 
								let that = this
 | 
				
			||||||
 | 
								let rangesText = this.batchIPCIDR
 | 
				
			||||||
 | 
								if (rangesText.length == 0) {
 | 
				
			||||||
 | 
									teaweb.warn("请填写要加入的CIDR", function () {
 | 
				
			||||||
 | 
										that.$refs.batchIPCIDR.focus()
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let validRanges = []
 | 
				
			||||||
 | 
								let invalidLine = ""
 | 
				
			||||||
 | 
								rangesText.split("\n").forEach(function (line) {
 | 
				
			||||||
 | 
									let cidr = line.trim()
 | 
				
			||||||
 | 
									if (cidr.length == 0) {
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (!that.validateCIDR(cidr)) {
 | 
				
			||||||
 | 
										invalidLine = line
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									validRanges.push({
 | 
				
			||||||
 | 
										type: "cidr",
 | 
				
			||||||
 | 
										params: {
 | 
				
			||||||
 | 
											cidr: cidr,
 | 
				
			||||||
 | 
											isReverse: that.isReverse
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								if (invalidLine.length > 0) {
 | 
				
			||||||
 | 
									teaweb.warn("'" + invalidLine + "'格式错误", function () {
 | 
				
			||||||
 | 
										that.$refs.batchIPCIDR.focus()
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								validRanges.forEach(function (v) {
 | 
				
			||||||
 | 
									that.ranges.push(v)
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.cancelBatchIPCIDR()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							selectRegionCountry: function (country) {
 | 
				
			||||||
 | 
								if (country == null) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.regions.push({
 | 
				
			||||||
 | 
									type: "country",
 | 
				
			||||||
 | 
									id: country.id,
 | 
				
			||||||
 | 
									name: country.name
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.$refs.regionCountryComboBox.clear()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							selectRegionProvince: function (province) {
 | 
				
			||||||
 | 
								if (province == null) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.regions.push({
 | 
				
			||||||
 | 
									type: "province",
 | 
				
			||||||
 | 
									id: province.id,
 | 
				
			||||||
 | 
									name: province.name
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.$refs.regionProvinceComboBox.clear()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							selectRegionCity: function (city) {
 | 
				
			||||||
 | 
								if (city == null) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.regions.push({
 | 
				
			||||||
 | 
									type: "city",
 | 
				
			||||||
 | 
									id: city.id,
 | 
				
			||||||
 | 
									name: city.name
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.$refs.regionCityComboBox.clear()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							selectRegionProvider: function (provider) {
 | 
				
			||||||
 | 
								if (provider == null) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.regions.push({
 | 
				
			||||||
 | 
									type: "provider",
 | 
				
			||||||
 | 
									id: provider.id,
 | 
				
			||||||
 | 
									name: provider.name
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								this.$refs.regionProviderComboBox.clear()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							removeRegion: function (index) {
 | 
				
			||||||
 | 
								this.regions.$remove(index)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		validateIP: function (ip) {
 | 
							validateIP: function (ip) {
 | 
				
			||||||
 | 
								if (ip.length == 0) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// IPv6
 | 
				
			||||||
 | 
								if (ip.indexOf(":") >= 0) {
 | 
				
			||||||
 | 
									let pieces = ip.split(":")
 | 
				
			||||||
 | 
									if (pieces.length > 8) {
 | 
				
			||||||
 | 
										return false
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									let isOk = true
 | 
				
			||||||
 | 
									pieces.forEach(function (piece) {
 | 
				
			||||||
 | 
										if (!/^[\da-fA-F]{0,4}$/.test(piece)) {
 | 
				
			||||||
 | 
											isOk = false
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return isOk
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
 | 
								if (!ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -1561,50 +1759,215 @@ Vue.component("ns-route-ranges-box", {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			return isOk
 | 
								return isOk
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							validateCIDR: function (cidr) {
 | 
				
			||||||
 | 
								let pieces = cidr.split("/")
 | 
				
			||||||
 | 
								if (pieces.length != 2) {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								let ip = pieces[0]
 | 
				
			||||||
 | 
								if (!this.validateIP(ip)) {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								let mask = pieces[1]
 | 
				
			||||||
 | 
								if (!/^\d{1,3}$/.test(mask)) {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								mask = parseInt(mask, 10)
 | 
				
			||||||
 | 
								if (cidr.indexOf(":") >= 0) { // IPv6
 | 
				
			||||||
 | 
									return mask <= 128
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return mask <= 32
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							updateRangeType: function (rangeType) {
 | 
				
			||||||
 | 
								this.rangeType = rangeType
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	template: `<div>
 | 
						template: `<div>
 | 
				
			||||||
	<input type="hidden" name="rangesJSON" :value="JSON.stringify(ranges)"/>
 | 
						<input type="hidden" name="rangesJSON" :value="JSON.stringify(ranges)"/>
 | 
				
			||||||
	<div v-if="ranges.length > 0">
 | 
						<div v-if="ranges.length > 0">
 | 
				
			||||||
		<div class="ui label tiny basic" v-for="(range, index) in ranges" style="margin-bottom: 0.3em">
 | 
							<div class="ui label tiny basic" v-for="(range, index) in ranges" style="margin-bottom: 0.3em">
 | 
				
			||||||
 | 
								<span class="red" v-if="range.params.isReverse">[排除]</span>
 | 
				
			||||||
			<span v-if="range.type == 'ipRange'">IP范围:</span>
 | 
								<span v-if="range.type == 'ipRange'">IP范围:</span>
 | 
				
			||||||
			{{range.params.ipFrom}} - {{range.params.ipTo}}   <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
 | 
								<span v-if="range.type == 'cidr'">CIDR:</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'region'">区域:</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'ipRange'">{{range.params.ipFrom}} - {{range.params.ipTo}}</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'cidr'">{{range.params.cidr}}</span>
 | 
				
			||||||
 | 
								<span v-if="range.type == 'region'"><span v-for="(region, index) in range.params.regions">{{region.name}}<span v-if="index < range.params.regions.length - 1">,</span></span></span>
 | 
				
			||||||
 | 
								   <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="ui divider"></div>
 | 
							<div class="ui divider"></div>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<!-- 添加单个 -->
 | 
						<!-- IP范围 -->
 | 
				
			||||||
	<div style="margin-bottom: 1em" v-show="isAdding">
 | 
						<div v-if="rangeType == 'ipRange'">
 | 
				
			||||||
		<div class="ui fields inline">
 | 
							<!-- 添加单个IP范围 -->
 | 
				
			||||||
			<div class="ui field">
 | 
							<div style="margin-bottom: 1em" v-show="isAdding">
 | 
				
			||||||
				<input type="text" placeholder="开始IP" maxlength="15" size="15" v-model="ipRangeFrom" ref="ipRangeFrom"  @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
								<table class="ui table">
 | 
				
			||||||
			</div>
 | 
									<tr>
 | 
				
			||||||
			<div class="ui field">-</div>
 | 
										<td class="title">开始IP *</td>
 | 
				
			||||||
			<div class="ui field">
 | 
										<td>
 | 
				
			||||||
				<input type="text" placeholder="结束IP" maxlength="15" size="15" v-model="ipRangeTo" ref="ipRangeTo" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
											<input type="text" placeholder="开始IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeFrom" ref="ipRangeFrom"  @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
				
			||||||
			</div>
 | 
										</td>
 | 
				
			||||||
			<div class="ui field">
 | 
									</tr>
 | 
				
			||||||
				<button class="ui button tiny" type="button" @click.prevent="confirmIPRange">确定</button>  
 | 
									<tr>
 | 
				
			||||||
				<a href="" @click.prevent="cancelIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
										<td>结束IP *</td>
 | 
				
			||||||
			</div>
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="text" placeholder="结束IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeTo" ref="ipRangeTo" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1"/>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmIPRange">确定</button>  
 | 
				
			||||||
 | 
										<a href="" @click.prevent="cancelIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<!-- 添加多个 -->
 | 
							<!-- 添加多个IP范围 -->
 | 
				
			||||||
	<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
							<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
				
			||||||
		<div class="ui field">
 | 
								<table class="ui table">
 | 
				
			||||||
			<textarea rows="5" ref="batchIPRange" v-model="batchIPRange"></textarea>	
 | 
									<tr>
 | 
				
			||||||
			<p class="comment">每行一条,格式为<code-label>开始IP,结束IP</code-label>,比如<code-label>192.168.1.100,192.168.1.200</code-label>。</p>	
 | 
										<td class="title">IP范围列表 *</td>
 | 
				
			||||||
		</div>
 | 
										<td>
 | 
				
			||||||
		<div class="ui field">
 | 
											<textarea rows="5" ref="batchIPRange" v-model="batchIPRange"></textarea>	
 | 
				
			||||||
 | 
											<p class="comment">每行一条,格式为<code-label>开始IP,结束IP</code-label>,比如<code-label>192.168.1.100,192.168.1.200</code-label>。</p>	
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
			<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPRange">确定</button>  
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPRange">确定</button>  
 | 
				
			||||||
			<a href="" @click.prevent="cancelBatchIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
									<a href="" @click.prevent="cancelBatchIPRange" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addIPRange">添加单个IP范围</button>  
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addBatchIPRange">批量添加IP范围</button>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	<div v-if="!isAdding && !isAddingBatch">
 | 
						<!-- CIDR -->
 | 
				
			||||||
		<button class="ui button tiny" type="button" @click.prevent="add">单个添加</button>  
 | 
						<div v-if="rangeType == 'cidr'">
 | 
				
			||||||
		<button class="ui button tiny" type="button" @click.prevent="addBatch">批量添加</button>
 | 
							<!-- 添加单个IP范围 -->
 | 
				
			||||||
 | 
							<div style="margin-bottom: 1em" v-show="isAdding">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">CIDR *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="text" placeholder="IP/MASK" maxlength="40" size="40" style="width: 15em" v-model="ipCIDR" ref="ipCIDR"  @keyup.enter="confirmIPCIDR" @keypress.enter.prevent="1"/>
 | 
				
			||||||
 | 
											<p class="comment">类似于<code-label>192.168.2.1/24</code-label>。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmIPCIDR">确定</button>  
 | 
				
			||||||
 | 
										<a href="" @click.prevent="cancelIPCIDR" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<!-- 添加多个IP范围 -->
 | 
				
			||||||
 | 
							<div style="margin-bottom: 1em" v-show="isAddingBatch">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">IP范围列表 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<textarea rows="5" ref="batchIPCIDR" v-model="batchIPCIDR"></textarea>	
 | 
				
			||||||
 | 
											<p class="comment">每行一条,格式为<code-label>IP/MASK</code-label>,比如<code-label>192.168.2.1/24</code-label>。</p>	
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmBatchIPCIDR">确定</button>  
 | 
				
			||||||
 | 
									<a href="" @click.prevent="cancelBatchIPCIDR" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addCIDR">添加单个CIDR</button>  
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addBatchCIDR">批量添加CIDR</button>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<!-- 区域 -->
 | 
				
			||||||
 | 
						<div v-if="rangeType == 'region'">
 | 
				
			||||||
 | 
							<!-- 添加区域 -->
 | 
				
			||||||
 | 
							<div v-if="isAdding">
 | 
				
			||||||
 | 
								<table class="ui table">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>已添加</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<div v-for="(region, index) in regions" class="ui label small basic">
 | 
				
			||||||
 | 
												{{region.name}} <a href="" title="删除" @click.prevent="removeRegion(index)"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">添加新<span v-if="regionType == 'country'">国家/地区</span><span v-if="regionType == 'province'">省份</span><span v-if="regionType == 'city'">城市</span><span v-if="regionType == 'provider'">ISP</span>
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
										 	<!-- region country name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'country'">
 | 
				
			||||||
 | 
												<combo-box title="" width="14em" data-url="/ui/countryOptions" data-key="countries" placeholder="点这里选择国家/地区" @change="selectRegionCountry" ref="regionCountryComboBox" key="combo-box-country"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- region province name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'province'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/provinceOptions" data-key="provinces" placeholder="点这里选择省份" @change="selectRegionProvince" ref="regionProvinceComboBox" key="combo-box-province"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- region city name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'city'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/cityOptions" data-key="cities" placeholder="点这里选择城市" @change="selectRegionCity" ref="regionCityComboBox" key="combo-box-city"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
											<!-- ISP Name -->
 | 
				
			||||||
 | 
											<div v-if="regionType == 'provider'" >
 | 
				
			||||||
 | 
												<combo-box title="" data-url="/ui/providerOptions" data-key="providers" placeholder="点这里选择ISP" @change="selectRegionProvider" ref="regionProviderComboBox" key="combo-box-isp"></combo-box>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											<div style="margin-top: 1em">
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'country'}" type="button" @click.prevent="addRegion('country')">添加国家/地区</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'province'}" type="button" @click.prevent="addRegion('province')">添加省份</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'city'}" type="button" @click.prevent="addRegion('city')">添加城市</button>  
 | 
				
			||||||
 | 
												<button class="ui button tiny basic" :class="{blue: regionType == 'provider'}" type="button" @click.prevent="addRegion('provider')">ISP</button>  
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</td>	
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>排除</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<checkbox v-model="isReverse"></checkbox>
 | 
				
			||||||
 | 
											<p class="comment">选中后表示线路中排除当前条件。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="confirmRegions">确定</button>  
 | 
				
			||||||
 | 
									<a href="" @click.prevent="cancelRegions" title="取消"><i class="icon remove small"></i></a>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div v-if="!isAdding && !isAddingBatch">
 | 
				
			||||||
 | 
								<button class="ui button tiny" type="button" @click.prevent="addRegions">添加区域</button>  
 | 
				
			||||||
 | 
							</div>	
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</div>`
 | 
					</div>`
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
@@ -7237,7 +7600,7 @@ Vue.component("http-compression-config-box", {
 | 
				
			|||||||
				isPrior: false,
 | 
									isPrior: false,
 | 
				
			||||||
				isOn: false,
 | 
									isOn: false,
 | 
				
			||||||
				useDefaultTypes: true,
 | 
									useDefaultTypes: true,
 | 
				
			||||||
				types: ["brotli", "gzip", "deflate"],
 | 
									types: ["brotli", "gzip", "zstd", "deflate"],
 | 
				
			||||||
				level: 5,
 | 
									level: 5,
 | 
				
			||||||
				decompressData: false,
 | 
									decompressData: false,
 | 
				
			||||||
				gzipRef: null,
 | 
									gzipRef: null,
 | 
				
			||||||
@@ -7276,6 +7639,11 @@ Vue.component("http-compression-config-box", {
 | 
				
			|||||||
				name: "Brotli",
 | 
									name: "Brotli",
 | 
				
			||||||
				code: "brotli",
 | 
									code: "brotli",
 | 
				
			||||||
				isOn: true
 | 
									isOn: true
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									name: "ZSTD",
 | 
				
			||||||
 | 
									code: "zstd",
 | 
				
			||||||
 | 
									isOn: true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		]
 | 
							]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7412,7 +7780,7 @@ Vue.component("http-compression-config-box", {
 | 
				
			|||||||
				<td>
 | 
									<td>
 | 
				
			||||||
					<div class="ui checkbox">
 | 
										<div class="ui checkbox">
 | 
				
			||||||
						<input type="checkbox" v-model="config.useDefaultTypes" id="compression-use-default"/>
 | 
											<input type="checkbox" v-model="config.useDefaultTypes" id="compression-use-default"/>
 | 
				
			||||||
						<label v-if="config.useDefaultTypes" for="compression-use-default">使用默认顺序<span class="grey small">(brotli、gzip、deflate)</span></label>
 | 
											<label v-if="config.useDefaultTypes" for="compression-use-default">使用默认顺序<span class="grey small">(brotli、gzip、 zstd、deflate)</span></label>
 | 
				
			||||||
						<label v-if="!config.useDefaultTypes" for="compression-use-default">使用默认顺序</label>
 | 
											<label v-if="!config.useDefaultTypes" for="compression-use-default">使用默认顺序</label>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<div v-show="!config.useDefaultTypes">
 | 
										<div v-show="!config.useDefaultTypes">
 | 
				
			||||||
@@ -13092,7 +13460,7 @@ Vue.component("combo-box", {
 | 
				
			|||||||
	<!-- 当前选中 -->
 | 
						<!-- 当前选中 -->
 | 
				
			||||||
	<div v-if="selectedItem != null">
 | 
						<div v-if="selectedItem != null">
 | 
				
			||||||
		<input type="hidden" :name="name" :value="selectedItem.value"/>
 | 
							<input type="hidden" :name="name" :value="selectedItem.value"/>
 | 
				
			||||||
		<a href="" class="ui label basic" style="line-height: 1.4; font-weight: normal; font-size: 1em" ref="selectedLabel" @click.prevent="submitForm"><span>{{title}}:{{selectedItem.name}}</span>
 | 
							<a href="" class="ui label basic" style="line-height: 1.4; font-weight: normal; font-size: 1em" ref="selectedLabel" @click.prevent="submitForm"><span><span v-if="title != null && title.length > 0">{{title}}:</span>{{selectedItem.name}}</span>
 | 
				
			||||||
			<span title="清除" @click.prevent="reset"><i class="icon remove small"></i></span>
 | 
								<span title="清除" @click.prevent="reset"><i class="icon remove small"></i></span>
 | 
				
			||||||
		</a>
 | 
							</a>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user