mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 13:10:26 +08:00 
			
		
		
		
	优化WAF区域/省份封禁:增加仅允许、增加中国香港澳台、内地等特殊区域
This commit is contained in:
		@@ -7,13 +7,12 @@ import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ChinaCountryId = 1
 | 
			
		||||
 | 
			
		||||
type ProvincesAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
@@ -43,7 +42,7 @@ func (this *ProvincesAction) RunGet(params struct {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
 | 
			
		||||
		RegionCountryId: int64(ChinaCountryId),
 | 
			
		||||
		RegionCountryId: regionconfigs.RegionChinaId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,6 @@ import (
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ChinaCountryId = 1
 | 
			
		||||
 | 
			
		||||
type ProvincesAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,8 @@ func init() {
 | 
			
		||||
			Get("/ipadmin/allowList", new(ipadmin.AllowListAction)).
 | 
			
		||||
			Get("/ipadmin/denyList", new(ipadmin.DenyListAction)).
 | 
			
		||||
			GetPost("/ipadmin/countries", new(ipadmin.CountriesAction)).
 | 
			
		||||
			Get("/ipadmin/selectCountriesPopup", new(ipadmin.SelectCountriesPopupAction)).
 | 
			
		||||
			Get("/ipadmin/selectProvincesPopup", new(ipadmin.SelectProvincesPopupAction)).
 | 
			
		||||
			GetPost("/ipadmin/provinces", new(ipadmin.ProvincesAction)).
 | 
			
		||||
			GetPost("/ipadmin/updateIPPopup", new(ipadmin.UpdateIPPopupAction)).
 | 
			
		||||
			Post("/ipadmin/deleteIP", new(ipadmin.DeleteIPAction)).
 | 
			
		||||
 
 | 
			
		||||
@@ -42,9 +42,11 @@ func (this *CountriesAction) RunGet(params struct {
 | 
			
		||||
		this.NotFound("firewallPolicy", params.FirewallPolicyId)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var selectedCountryIds = []int64{}
 | 
			
		||||
	var deniedCountryIds = []int64{}
 | 
			
		||||
	var allowedCountryIds = []int64{}
 | 
			
		||||
	if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
 | 
			
		||||
		selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
 | 
			
		||||
		deniedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
 | 
			
		||||
		allowedCountryIds = policyConfig.Inbound.Region.AllowCountryIds
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
 | 
			
		||||
@@ -52,16 +54,23 @@ func (this *CountriesAction) RunGet(params struct {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var countryMaps = []maps.Map{}
 | 
			
		||||
	var deniesCountryMaps = []maps.Map{}
 | 
			
		||||
	var allowedCountryMaps = []maps.Map{}
 | 
			
		||||
	for _, country := range countriesResp.RegionCountries {
 | 
			
		||||
		countryMaps = append(countryMaps, maps.Map{
 | 
			
		||||
			"id":        country.Id,
 | 
			
		||||
			"name":      country.DisplayName,
 | 
			
		||||
			"letter":    strings.ToUpper(string(country.Pinyin[0][0])),
 | 
			
		||||
			"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
 | 
			
		||||
		})
 | 
			
		||||
		var countryMap = maps.Map{
 | 
			
		||||
			"id":     country.Id,
 | 
			
		||||
			"name":   country.DisplayName,
 | 
			
		||||
			"letter": strings.ToUpper(string(country.Pinyin[0][0])),
 | 
			
		||||
		}
 | 
			
		||||
		if lists.ContainsInt64(deniedCountryIds, country.Id) {
 | 
			
		||||
			deniesCountryMaps = append(deniesCountryMaps, countryMap)
 | 
			
		||||
		}
 | 
			
		||||
		if lists.ContainsInt64(allowedCountryIds, country.Id) {
 | 
			
		||||
			allowedCountryMaps = append(allowedCountryMaps, countryMap)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countries"] = countryMaps
 | 
			
		||||
	this.Data["deniedCountries"] = deniesCountryMaps
 | 
			
		||||
	this.Data["allowedCountries"] = allowedCountryMaps
 | 
			
		||||
 | 
			
		||||
	// except & only URL Patterns
 | 
			
		||||
	this.Data["exceptURLPatterns"] = []*shared.URLPattern{}
 | 
			
		||||
@@ -88,7 +97,8 @@ func (this *CountriesAction) RunGet(params struct {
 | 
			
		||||
 | 
			
		||||
func (this *CountriesAction) RunPost(params struct {
 | 
			
		||||
	FirewallPolicyId int64
 | 
			
		||||
	CountryIds       []int64
 | 
			
		||||
	DenyCountryIds   []int64
 | 
			
		||||
	AllowCountryIds  []int64
 | 
			
		||||
 | 
			
		||||
	ExceptURLPatternsJSON []byte
 | 
			
		||||
	OnlyURLPatternsJSON   []byte
 | 
			
		||||
@@ -98,6 +108,8 @@ func (this *CountriesAction) RunPost(params struct {
 | 
			
		||||
	// 日志
 | 
			
		||||
	defer this.CreateLogInfo(codes.WAF_LogUpdateForbiddenCountries, params.FirewallPolicyId)
 | 
			
		||||
 | 
			
		||||
	// TODO validate denied and allowed countries
 | 
			
		||||
 | 
			
		||||
	policyConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyConfig(this.AdminContext(), params.FirewallPolicyId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
@@ -116,7 +128,8 @@ func (this *CountriesAction) RunPost(params struct {
 | 
			
		||||
			IsOn: true,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	policyConfig.Inbound.Region.DenyCountryIds = params.CountryIds
 | 
			
		||||
	policyConfig.Inbound.Region.DenyCountryIds = params.DenyCountryIds
 | 
			
		||||
	policyConfig.Inbound.Region.AllowCountryIds = params.AllowCountryIds
 | 
			
		||||
 | 
			
		||||
	// 例外URL
 | 
			
		||||
	var exceptURLPatterns = []*shared.URLPattern{}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,14 +7,13 @@ import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ChinaCountryId = 1
 | 
			
		||||
 | 
			
		||||
type ProvincesAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
@@ -42,27 +41,36 @@ func (this *ProvincesAction) RunGet(params struct {
 | 
			
		||||
		this.NotFound("firewallPolicy", params.FirewallPolicyId)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var selectedProvinceIds = []int64{}
 | 
			
		||||
	var deniedProvinceIds = []int64{}
 | 
			
		||||
	var allowedProvinceIds = []int64{}
 | 
			
		||||
	if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
 | 
			
		||||
		selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
 | 
			
		||||
		deniedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
 | 
			
		||||
		allowedProvinceIds = policyConfig.Inbound.Region.AllowProvinceIds
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
 | 
			
		||||
		RegionCountryId: int64(ChinaCountryId),
 | 
			
		||||
		RegionCountryId: regionconfigs.RegionChinaId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var provinceMaps = []maps.Map{}
 | 
			
		||||
	var deniedProvinceMaps = []maps.Map{}
 | 
			
		||||
	var allowedProvinceMaps = []maps.Map{}
 | 
			
		||||
	for _, province := range provincesResp.RegionProvinces {
 | 
			
		||||
		provinceMaps = append(provinceMaps, maps.Map{
 | 
			
		||||
			"id":        province.Id,
 | 
			
		||||
			"name":      province.DisplayName,
 | 
			
		||||
			"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
 | 
			
		||||
		})
 | 
			
		||||
		var provinceMap = maps.Map{
 | 
			
		||||
			"id":   province.Id,
 | 
			
		||||
			"name": province.DisplayName,
 | 
			
		||||
		}
 | 
			
		||||
		if lists.ContainsInt64(deniedProvinceIds, province.Id) {
 | 
			
		||||
			deniedProvinceMaps = append(deniedProvinceMaps, provinceMap)
 | 
			
		||||
		}
 | 
			
		||||
		if lists.ContainsInt64(allowedProvinceIds, province.Id) {
 | 
			
		||||
			allowedProvinceMaps = append(allowedProvinceMaps, provinceMap)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["provinces"] = provinceMaps
 | 
			
		||||
	this.Data["deniedProvinces"] = deniedProvinceMaps
 | 
			
		||||
	this.Data["allowedProvinces"] = allowedProvinceMaps
 | 
			
		||||
 | 
			
		||||
	// except & only URL Patterns
 | 
			
		||||
	this.Data["exceptURLPatterns"] = []*shared.URLPattern{}
 | 
			
		||||
@@ -89,7 +97,8 @@ func (this *ProvincesAction) RunGet(params struct {
 | 
			
		||||
 | 
			
		||||
func (this *ProvincesAction) RunPost(params struct {
 | 
			
		||||
	FirewallPolicyId int64
 | 
			
		||||
	ProvinceIds      []int64
 | 
			
		||||
	DenyProvinceIds  []int64
 | 
			
		||||
	AllowProvinceIds []int64
 | 
			
		||||
 | 
			
		||||
	ExceptURLPatternsJSON []byte
 | 
			
		||||
	OnlyURLPatternsJSON   []byte
 | 
			
		||||
@@ -117,7 +126,8 @@ func (this *ProvincesAction) RunPost(params struct {
 | 
			
		||||
			IsOn: true,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	policyConfig.Inbound.Region.DenyProvinceIds = params.ProvinceIds
 | 
			
		||||
	policyConfig.Inbound.Region.DenyProvinceIds = params.DenyProvinceIds
 | 
			
		||||
	policyConfig.Inbound.Region.AllowProvinceIds = params.AllowProvinceIds
 | 
			
		||||
 | 
			
		||||
	// 例外URL
 | 
			
		||||
	var exceptURLPatterns = []*shared.URLPattern{}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package ipadmin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SelectCountriesPopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *SelectCountriesPopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *SelectCountriesPopupAction) RunGet(params struct {
 | 
			
		||||
	Type               string
 | 
			
		||||
	SelectedCountryIds string
 | 
			
		||||
}) {
 | 
			
		||||
	this.Data["type"] = params.Type
 | 
			
		||||
 | 
			
		||||
	var selectedCountryIds = utils.SplitNumbers(params.SelectedCountryIds)
 | 
			
		||||
 | 
			
		||||
	countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// special regions
 | 
			
		||||
 | 
			
		||||
	var countryMaps = []maps.Map{}
 | 
			
		||||
	for _, country := range countriesResp.RegionCountries {
 | 
			
		||||
		countryMaps = append(countryMaps, maps.Map{
 | 
			
		||||
			"id":        country.Id,
 | 
			
		||||
			"name":      country.DisplayName,
 | 
			
		||||
			"letter":    strings.ToUpper(string(country.Pinyin[0][0])),
 | 
			
		||||
			"pinyin":    country.Pinyin,
 | 
			
		||||
			"codes":     country.Codes,
 | 
			
		||||
			"isCommon":  country.IsCommon,
 | 
			
		||||
			"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countries"] = countryMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package ipadmin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SelectProvincesPopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *SelectProvincesPopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *SelectProvincesPopupAction) RunGet(params struct {
 | 
			
		||||
	Type                string
 | 
			
		||||
	SelectedProvinceIds string
 | 
			
		||||
}) {
 | 
			
		||||
	this.Data["type"] = params.Type
 | 
			
		||||
 | 
			
		||||
	var selectedProvinceIds = utils.SplitNumbers(params.SelectedProvinceIds)
 | 
			
		||||
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
 | 
			
		||||
		RegionCountryId: regionconfigs.RegionChinaId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var provinceMaps = []maps.Map{}
 | 
			
		||||
	for _, province := range provincesResp.RegionProvinces {
 | 
			
		||||
		provinceMaps = append(provinceMaps, maps.Map{
 | 
			
		||||
			"id":        province.Id,
 | 
			
		||||
			"name":      province.DisplayName,
 | 
			
		||||
			"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["provinces"] = provinceMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ package ui
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -13,7 +14,7 @@ type ProvinceOptionsAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *ProvinceOptionsAction) RunPost(params struct{}) {
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: ChinaCountryId})
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: regionconfigs.RegionChinaId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,12 @@ import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ChinaCountryId = 1
 | 
			
		||||
 | 
			
		||||
type SelectProvincesPopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
@@ -24,7 +23,7 @@ func (this *SelectProvincesPopupAction) RunGet(params struct {
 | 
			
		||||
}) {
 | 
			
		||||
	var selectedProvinceIds = utils.SplitNumbers(params.ProvinceIds)
 | 
			
		||||
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: ChinaCountryId})
 | 
			
		||||
	provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: regionconfigs.RegionChinaId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								web/public/js/components/common/search-box.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								web/public/js/components/common/search-box.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
Vue.component("search-box", {
 | 
			
		||||
	props: ["placeholder", "width"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let width = this.width
 | 
			
		||||
		if (width == null) {
 | 
			
		||||
			width = "10em"
 | 
			
		||||
		}
 | 
			
		||||
		return {
 | 
			
		||||
			realWidth: width,
 | 
			
		||||
			realValue: ""
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onInput: function () {
 | 
			
		||||
			this.$emit("input", { value: this.realValue})
 | 
			
		||||
			this.$emit("change", { value: this.realValue})
 | 
			
		||||
		},
 | 
			
		||||
		clearValue: function () {
 | 
			
		||||
			this.realValue = ""
 | 
			
		||||
			this.focus()
 | 
			
		||||
			this.onInput()
 | 
			
		||||
		},
 | 
			
		||||
		focus: function () {
 | 
			
		||||
			this.$refs.valueRef.focus()
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<div class="ui input small" :class="{'right labeled': realValue.length > 0}">
 | 
			
		||||
		<input type="text" :placeholder="placeholder" :style="{width: realWidth}" @input="onInput" v-model="realValue" ref="valueRef"/>
 | 
			
		||||
		<a href="" class="ui label blue" v-if="realValue.length > 0" @click.prevent="clearValue" style="padding-right: 0"><i class="icon remove"></i></a>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
Vue.component("http-firewall-province-selector", {
 | 
			
		||||
	props: ["v-type", "v-provinces"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let provinces = this.vProvinces
 | 
			
		||||
		if (provinces == null) {
 | 
			
		||||
			provinces = []
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			listType: this.vType,
 | 
			
		||||
			provinces: provinces
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		addProvince: function () {
 | 
			
		||||
			let selectedProvinceIds = this.provinces.map(function (province) {
 | 
			
		||||
				return province.id
 | 
			
		||||
			})
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.popup("/servers/server/settings/waf/ipadmin/selectProvincesPopup?type=" + this.listType + "&selectedProvinceIds=" + selectedProvinceIds.join(","), {
 | 
			
		||||
				width: "50em",
 | 
			
		||||
				height: "26em",
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					that.provinces = resp.data.selectedProvinces
 | 
			
		||||
					that.$forceUpdate()
 | 
			
		||||
					that.notifyChange()
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
		removeProvince: function (index) {
 | 
			
		||||
			this.provinces.$remove(index)
 | 
			
		||||
			this.notifyChange()
 | 
			
		||||
		},
 | 
			
		||||
		resetProvinces: function () {
 | 
			
		||||
			this.provinces = []
 | 
			
		||||
			this.notifyChange()
 | 
			
		||||
		},
 | 
			
		||||
		notifyChange: function () {
 | 
			
		||||
			this.$emit("change", {
 | 
			
		||||
				"provinces": this.provinces
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<span v-if="provinces.length == 0" class="disabled">暂时没有选择<span v-if="listType =='allow'">允许</span><span v-else>封禁</span>的省份。</span>
 | 
			
		||||
	<div v-show="provinces.length > 0">
 | 
			
		||||
		<div class="ui label tiny basic" v-for="(province, index) in provinces" style="margin-bottom: 0.5em">
 | 
			
		||||
			<input type="hidden" :name="listType + 'ProvinceIds'" :value="province.id"/>
 | 
			
		||||
			{{province.name}} <a href="" @click.prevent="removeProvince(index)" title="删除"><i class="icon remove"></i></a>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="ui divider"></div>
 | 
			
		||||
	<button type="button" class="ui button tiny" @click.prevent="addProvince">修改</button>   <button type="button" class="ui button tiny" v-show="provinces.length > 0" @click.prevent="resetProvinces">清空</button>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
Vue.component("http-firewall-region-selector", {
 | 
			
		||||
	props: ["v-type", "v-countries"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let countries = this.vCountries
 | 
			
		||||
		if (countries == null) {
 | 
			
		||||
			countries = []
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			listType: this.vType,
 | 
			
		||||
			countries: countries
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		addCountry: function () {
 | 
			
		||||
			let selectedCountryIds = this.countries.map(function (country) {
 | 
			
		||||
				return country.id
 | 
			
		||||
			})
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.popup("/servers/server/settings/waf/ipadmin/selectCountriesPopup?type=" + this.listType + "&selectedCountryIds=" + selectedCountryIds.join(","), {
 | 
			
		||||
				width: "52em",
 | 
			
		||||
				height: "30em",
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					that.countries = resp.data.selectedCountries
 | 
			
		||||
					that.$forceUpdate()
 | 
			
		||||
					that.notifyChange()
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
		removeCountry: function (index) {
 | 
			
		||||
			this.countries.$remove(index)
 | 
			
		||||
			this.notifyChange()
 | 
			
		||||
		},
 | 
			
		||||
		resetCountries: function () {
 | 
			
		||||
			this.countries = []
 | 
			
		||||
			this.notifyChange()
 | 
			
		||||
		},
 | 
			
		||||
		notifyChange: function () {
 | 
			
		||||
			this.$emit("change", {
 | 
			
		||||
				"countries": this.countries
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<span v-if="countries.length == 0" class="disabled">暂时没有选择<span v-if="listType =='allow'">允许</span><span v-else>封禁</span>的区域。</span>
 | 
			
		||||
	<div v-show="countries.length > 0">
 | 
			
		||||
		<div class="ui label tiny basic" v-for="(country, index) in countries" style="margin-bottom: 0.5em">
 | 
			
		||||
			<input type="hidden" :name="listType + 'CountryIds'" :value="country.id"/>
 | 
			
		||||
			({{country.letter}}){{country.name}} <a href="" @click.prevent="removeCountry(index)" title="删除"><i class="icon remove"></i></a>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="ui divider"></div>
 | 
			
		||||
	<button type="button" class="ui button tiny" @click.prevent="addCountry">修改</button>   <button type="button" class="ui button tiny" v-show="countries.length > 0" @click.prevent="resetCountries">清空</button>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
.region-letter-group .item {
 | 
			
		||||
  padding-left: 1em !important;
 | 
			
		||||
  padding-right: 1em !important;
 | 
			
		||||
}
 | 
			
		||||
.country-group {
 | 
			
		||||
  padding-bottom: 1em;
 | 
			
		||||
}
 | 
			
		||||
.country-group .country-list .item {
 | 
			
		||||
  float: left;
 | 
			
		||||
  width: 12em;
 | 
			
		||||
  margin-bottom: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
.country-group .country-list .item .checkbox label {
 | 
			
		||||
  font-size: 12px !important;
 | 
			
		||||
  cursor: pointer !important;
 | 
			
		||||
}
 | 
			
		||||
/*# sourceMappingURL=countries.css.map */
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
{"version":3,"sources":["countries.less"],"names":[],"mappings":"AAAA,oBACC;EACC,4BAAA;EACA,6BAAA;;AAIF;EAcC,mBAAA;;AAdD,cACC,cACC;EACC,WAAA;EACA,WAAA;EACA,oBAAA;;AALH,cACC,cACC,MAKC,UAAU;EACT,0BAAA;EACA,0BAAA","file":"countries.css"}
 | 
			
		||||
@@ -15,54 +15,32 @@
 | 
			
		||||
        <input type="hidden" name="exceptURLPatternsJSON" :value="JSON.stringify(exceptURLPatterns)"/>
 | 
			
		||||
        <input type="hidden" name="onlyURLPatternsJSON" :value="JSON.stringify(onlyURLPatterns)"/>
 | 
			
		||||
		<table class="ui table selectable definition">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">已封禁</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<span v-if="countSelectedCountries == 0" class="disabled">暂时没有选择封禁区域。</span>
 | 
			
		||||
					<div class="ui label tiny basic" v-for="country in countries" v-if="country.isChecked" style="margin-bottom: 0.5em">
 | 
			
		||||
						<input type="hidden" name="countryIds" :value="country.id"/>
 | 
			
		||||
						({{country.letter}}){{country.name}} <a href="" @click.prevent="deselectCountry(country)" title="取消封禁"><i class="icon remove"></i></a>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>选择封禁区域 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<more-options-indicator><span v-if="!moreOptionsVisible">选择区域</span><span v-else>完成选择</span></more-options-indicator>
 | 
			
		||||
 | 
			
		||||
					<div class="ui menu tabular tiny region-letter-group" v-show="moreOptionsVisible">
 | 
			
		||||
						<a href="" v-for="group in letterGroups" class="item" :class="{active: group == selectedGroup}" @click.prevent="selectGroup(group)">{{group}}</a>
 | 
			
		||||
						<div class="item right">
 | 
			
		||||
							<div class="ui checkbox" @click.prevent="checkAll">
 | 
			
		||||
								<input type="checkbox" v-model="isCheckingAll"/>
 | 
			
		||||
								<label>全选</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div v-for="group in letterGroups"  v-show="moreOptionsVisible">
 | 
			
		||||
						<div v-for="letter in group" v-if="letterCountries[letter] != null && group == selectedGroup" class="country-group">
 | 
			
		||||
							<h4>{{letter}}</h4>
 | 
			
		||||
							<div class="country-list">
 | 
			
		||||
								<div class="item" v-for="country in letterCountries[letter]">
 | 
			
		||||
									<div class="ui checkbox" @click.prevent="selectCountry(country)">
 | 
			
		||||
										<input type="checkbox" v-model="country.isChecked"/>
 | 
			
		||||
										<label>{{country.name}}</label>
 | 
			
		||||
									</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="clear"></div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>例外URL  <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
 | 
			
		||||
                <td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                <td class="title">仅允许的区域</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <http-firewall-region-selector :v-countries="allowedCountries" :v-type="'allow'" @change="changeAllowedCountries"></http-firewall-region-selector>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>限制URL  <tip-icon content="只对这些URL做限制。"></tip-icon></td>
 | 
			
		||||
                <td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                <td class="title">仅封禁的区域</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <p class="comment" v-if="allowedCountries.length > 0">由于你已设置"仅允许的区域",所以不需要再设置封禁区域。</p>
 | 
			
		||||
                    <http-firewall-region-selector :v-countries="deniedCountries" :v-type="'deny'" v-show="allowedCountries.length == 0"></http-firewall-region-selector>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tbody v-show="moreOptionsVisible">
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>例外URL  <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
 | 
			
		||||
                    <td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>限制URL  <tip-icon content="只对这些URL做限制。"></tip-icon></td>
 | 
			
		||||
                    <td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn></submit-btn>
 | 
			
		||||
	</form>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,11 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.letterGroups = [
 | 
			
		||||
		"ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VWX", "YZ"
 | 
			
		||||
	];
 | 
			
		||||
	this.selectedGroup = "ABC"
 | 
			
		||||
	this.letterCountries = {}
 | 
			
		||||
	let that = this
 | 
			
		||||
	this.countSelectedCountries = this.countries.$count(function (k, country) {
 | 
			
		||||
		return country.isChecked
 | 
			
		||||
	})
 | 
			
		||||
	this.countries.forEach(function (country) {
 | 
			
		||||
		if (typeof (that.letterCountries[country.letter]) == "undefined") {
 | 
			
		||||
			that.letterCountries[country.letter] = []
 | 
			
		||||
		}
 | 
			
		||||
		that.letterCountries[country.letter].push(country)
 | 
			
		||||
	})
 | 
			
		||||
	this.isCheckingAll = false
 | 
			
		||||
 | 
			
		||||
	this.selectGroup = function (group) {
 | 
			
		||||
		this.selectedGroup = group
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.selectCountry = function (country) {
 | 
			
		||||
		country.isChecked = !country.isChecked
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.deselectCountry = function (country) {
 | 
			
		||||
		country.isChecked = false
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.checkAll = function () {
 | 
			
		||||
		this.isCheckingAll = !this.isCheckingAll
 | 
			
		||||
 | 
			
		||||
		this.countries.forEach(function (country) {
 | 
			
		||||
			country.isChecked = that.isCheckingAll
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.success = function () {
 | 
			
		||||
		teaweb.success("保存成功", function () {
 | 
			
		||||
			teaweb.reload()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.change = function () {
 | 
			
		||||
		this.countSelectedCountries = this.countries.$count(function (k, country) {
 | 
			
		||||
			return country.isChecked
 | 
			
		||||
		})
 | 
			
		||||
	this.changeAllowedCountries = function (event) {
 | 
			
		||||
		this.allowedCountries = event.countries
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
.region-letter-group {
 | 
			
		||||
	.item {
 | 
			
		||||
		padding-left: 1em !important;
 | 
			
		||||
		padding-right: 1em !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.country-group {
 | 
			
		||||
	.country-list {
 | 
			
		||||
		.item {
 | 
			
		||||
			float: left;
 | 
			
		||||
			width: 12em;
 | 
			
		||||
			margin-bottom: 0.5em;
 | 
			
		||||
 | 
			
		||||
			.checkbox label {
 | 
			
		||||
				font-size: 12px !important;
 | 
			
		||||
				cursor: pointer !important;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	padding-bottom: 1em;
 | 
			
		||||
}
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
{"version":3,"sources":["provinces.less"],"names":[],"mappings":"AAAA,cACC;EACC,WAAA;EACA,WAAA;EACA,oBAAA;;AAJF,cACC,MAKC,UAAU;EACT,0BAAA;EACA,0BAAA","file":"provinces.css"}
 | 
			
		||||
@@ -15,49 +15,32 @@
 | 
			
		||||
        <input type="hidden" name="exceptURLPatternsJSON" :value="JSON.stringify(exceptURLPatterns)"/>
 | 
			
		||||
        <input type="hidden" name="onlyURLPatternsJSON" :value="JSON.stringify(onlyURLPatterns)"/>
 | 
			
		||||
		<table class="ui table selectable definition">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">已封禁</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<span v-if="countSelectedProvinces == 0" class="disabled">暂时没有选择封禁省份。</span>
 | 
			
		||||
					<div class="ui label tiny basic" v-for="province in provinces" v-if="province.isChecked" style="margin-bottom: 0.5em">
 | 
			
		||||
						<input type="hidden" name="provinceIds" :value="province.id"/>
 | 
			
		||||
						{{province.name}} <a href="" @click.prevent="deselectProvince(province)" title="取消封禁"><i class="icon remove"></i></a>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>选择封禁区域</td>
 | 
			
		||||
				<td>
 | 
			
		||||
 | 
			
		||||
					<first-menu>
 | 
			
		||||
						<menu-item><more-options-indicator><span v-if="!moreOptionsVisible">选择省份/自治区</span><span v-else>完成选择</span></more-options-indicator></menu-item>
 | 
			
		||||
						<div class="item right" v-show="moreOptionsVisible">
 | 
			
		||||
							<div class="ui checkbox" @click.prevent="checkAll">
 | 
			
		||||
								<input type="checkbox" v-model="isCheckingAll"/>
 | 
			
		||||
								<label>全选</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</first-menu>
 | 
			
		||||
 | 
			
		||||
					<div class="province-list" v-show="moreOptionsVisible" style="margin-top:0.5em">
 | 
			
		||||
						<div class="item" v-for="province in provinces">
 | 
			
		||||
							<div class="ui checkbox" @click.prevent="selectProvince(province)">
 | 
			
		||||
								<input type="checkbox" v-model="province.isChecked"/>
 | 
			
		||||
								<label>{{province.name}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="clear"></div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>例外URL  <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
 | 
			
		||||
                <td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                <td class="title">仅允许的省份</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <http-firewall-province-selector :v-provinces="allowedProvinces" :v-type="'allow'" @change="changeAllowedProvinces"></http-firewall-province-selector>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>限制URL  <tip-icon content="只对这些URL做限制。"></tip-icon></td>
 | 
			
		||||
                <td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                <td class="title">仅封禁的省份</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <p class="comment" v-if="allowedProvinces.length > 0">由于你已设置"仅允许的省份",所以不需要再设置封禁省份。</p>
 | 
			
		||||
                    <http-firewall-province-selector :v-provinces="deniedProvinces" :v-type="'deny'" v-show="allowedProvinces.length == 0"></http-firewall-province-selector>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tbody v-show="moreOptionsVisible">
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>例外URL  <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
 | 
			
		||||
                    <td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>限制URL  <tip-icon content="只对这些URL做限制。"></tip-icon></td>
 | 
			
		||||
                    <td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn></submit-btn>
 | 
			
		||||
	</form>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,11 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.isCheckingAll = false
 | 
			
		||||
 | 
			
		||||
	this.countSelectedProvinces = this.provinces.$count(function (k, province) {
 | 
			
		||||
		return province.isChecked
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	this.selectProvince = function (province) {
 | 
			
		||||
		province.isChecked = !province.isChecked
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.deselectProvince = function (province) {
 | 
			
		||||
		province.isChecked = false
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.checkAll = function () {
 | 
			
		||||
		this.isCheckingAll = !this.isCheckingAll
 | 
			
		||||
		let that = this
 | 
			
		||||
		this.provinces.forEach(function (province) {
 | 
			
		||||
			province.isChecked = that.isCheckingAll
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.success = function () {
 | 
			
		||||
		teaweb.success("保存成功", function () {
 | 
			
		||||
			teaweb.reload()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this.change = function () {
 | 
			
		||||
		this.countSelectedProvinces = this.provinces.$count(function (k, province) {
 | 
			
		||||
			return province.isChecked
 | 
			
		||||
		})
 | 
			
		||||
	this.changeAllowedProvinces = function (event) {
 | 
			
		||||
		this.allowedProvinces = event.provinces
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
.region-letter-group .item {
 | 
			
		||||
  padding-left: 0.8em !important;
 | 
			
		||||
  padding-right: 0.8em !important;
 | 
			
		||||
}
 | 
			
		||||
.region-letter-group .item .count {
 | 
			
		||||
  font-size: 0.8em;
 | 
			
		||||
  color: grey;
 | 
			
		||||
}
 | 
			
		||||
.country-groups {
 | 
			
		||||
  max-height: 23em;
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
}
 | 
			
		||||
.country-groups .country-group {
 | 
			
		||||
  padding-bottom: 1em;
 | 
			
		||||
}
 | 
			
		||||
.country-groups .country-group .country-list .item {
 | 
			
		||||
  float: left;
 | 
			
		||||
  width: 9em;
 | 
			
		||||
  margin-bottom: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
.country-groups .country-group .country-list .item .checkbox label {
 | 
			
		||||
  font-size: 12px !important;
 | 
			
		||||
  cursor: pointer !important;
 | 
			
		||||
}
 | 
			
		||||
.country-groups::-webkit-scrollbar {
 | 
			
		||||
  width: 4px;
 | 
			
		||||
}
 | 
			
		||||
/*# sourceMappingURL=selectCountriesPopup.css.map */
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"sources":["selectCountriesPopup.less"],"names":[],"mappings":"AAAA,oBACC;EACC,mBAAA;EACA,oBAAA;;AAHF,oBACC,MAIC;EACC,gBAAA;EACA,WAAA;;AAKH;EACC,gBAAA;EACA,gBAAA;;AAFD,eAIC;EACC,mBAAA;;AALF,eAIC,eAGC,cACC;EACC,WAAA;EACA,UAAA;EACA,oBAAA;;AAXJ,eAIC,eAGC,cACC,MAKC,UAAU;EACT,0BAAA;EACA,0BAAA;;AAOL,eAAe;EACd,UAAA","file":"selectCountriesPopup.css"}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3 v-show="type == 'allow'">选择允许的区域</h3>
 | 
			
		||||
<h3 v-show="type == 'deny'">选择封禁的区域</h3>
 | 
			
		||||
<form class="ui form">
 | 
			
		||||
    <div class="ui menu tabular tiny region-letter-group attached">
 | 
			
		||||
        <a href="" v-for="group in letterGroups" class="item" :class="{active: group.code == selectedGroup, disabled: group.countMatched == 0}" @click.prevent="selectGroup(group)">{{group.code}}<span v-if="group.count > 0" class="count"> ({{group.count}})</span></a>
 | 
			
		||||
        <div class="item right">
 | 
			
		||||
            <div class="ui checkbox" @click.prevent="checkAll">
 | 
			
		||||
                <input type="checkbox" v-model="isCheckingAll"/>
 | 
			
		||||
                <label>全选</label>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="country-groups ui segment attached">
 | 
			
		||||
        <div v-for="group in letterGroups">
 | 
			
		||||
            <div v-if="group.code == commonGroupName && group.code == selectedGroup">
 | 
			
		||||
                <div class="country-group">
 | 
			
		||||
                    <div class="country-list">
 | 
			
		||||
                        <div class="item" v-for="country in letterCountries[commonGroupName]">
 | 
			
		||||
                            <div class="ui checkbox" @click.prevent="selectCountry(country)">
 | 
			
		||||
                                <input type="checkbox" v-model="country.isChecked"/>
 | 
			
		||||
                                <label><span :class="{blue: country.isMatched}">{{country.name}}</span></label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="clear"></div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div v-else>
 | 
			
		||||
                <div v-for="letter in group.code" v-if="letterCountries[letter] != null && group.code == selectedGroup" class="country-group">
 | 
			
		||||
                    <h4>{{letter}}</h4>
 | 
			
		||||
                    <div class="country-list">
 | 
			
		||||
                        <div class="item" v-for="country in letterCountries[letter]">
 | 
			
		||||
                            <div class="ui checkbox" @click.prevent="selectCountry(country)">
 | 
			
		||||
                                <input type="checkbox" v-model="country.isChecked"/>
 | 
			
		||||
                                <label><span :class="{blue: country.isMatched}">{{country.name}}</span></label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="clear"></div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="margin"></div>
 | 
			
		||||
    <div class="ui menu text basic">
 | 
			
		||||
        <div class="item">
 | 
			
		||||
            <button class="ui button primary" @click.prevent="submit">确定</button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item right" v-show="!searchBoxVisible">
 | 
			
		||||
            <a href="" @click.prevent="showSearchBox"><i class="icon search"></i></a>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item right" v-show="searchBoxVisible">
 | 
			
		||||
            <search-box placeholder="关键词" ref="searchBox" @change="changeKeyword"></search-box>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -0,0 +1,197 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	var commonGroupName = "常用"
 | 
			
		||||
	this.letterGroups = [
 | 
			
		||||
		{
 | 
			
		||||
			"code": commonGroupName,
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "ABC",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "DEF",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "GHI",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "JKL",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "MNO",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "PQR",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "STU",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "VWX",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code": "YZ",
 | 
			
		||||
			"count": 0,
 | 
			
		||||
			"countMatched": 0
 | 
			
		||||
		}
 | 
			
		||||
	]
 | 
			
		||||
	this.commonGroupName = commonGroupName
 | 
			
		||||
	this.selectedGroup = commonGroupName
 | 
			
		||||
	this.letterCountries = {}
 | 
			
		||||
	let that = this
 | 
			
		||||
	this.countSelectedCountries = this.countries.$count(function (k, country) {
 | 
			
		||||
		return country.isChecked
 | 
			
		||||
	})
 | 
			
		||||
	this.countries.forEach(function (country) {
 | 
			
		||||
		// letter
 | 
			
		||||
		if (typeof (that.letterCountries[country.letter]) == "undefined") {
 | 
			
		||||
			that.letterCountries[country.letter] = []
 | 
			
		||||
		}
 | 
			
		||||
		that.letterCountries[country.letter].push(country)
 | 
			
		||||
 | 
			
		||||
		// common
 | 
			
		||||
		if (country.isCommon) {
 | 
			
		||||
			if (typeof that.letterCountries[commonGroupName] == "undefined") {
 | 
			
		||||
				that.letterCountries[commonGroupName] = []
 | 
			
		||||
			}
 | 
			
		||||
			that.letterCountries[commonGroupName].push(country)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	this.isCheckingAll = false
 | 
			
		||||
 | 
			
		||||
	this.$delay(function () {
 | 
			
		||||
		this.change()
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	this.checkAll = function () {
 | 
			
		||||
		this.isCheckingAll = !this.isCheckingAll
 | 
			
		||||
 | 
			
		||||
		this.countries.forEach(function (country) {
 | 
			
		||||
			country.isChecked = that.isCheckingAll
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.selectGroup = function (group) {
 | 
			
		||||
		this.selectedGroup = group.code
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.selectCountry = function (country) {
 | 
			
		||||
		country.isChecked = !country.isChecked
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.deselectCountry = function (country) {
 | 
			
		||||
		country.isChecked = false
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.change = function () {
 | 
			
		||||
		let that = this
 | 
			
		||||
		this.letterGroups.forEach(function (group) {
 | 
			
		||||
			group.count = 0
 | 
			
		||||
			group.countMatched = 0
 | 
			
		||||
		})
 | 
			
		||||
		this.countries.forEach(function (country) {
 | 
			
		||||
			that.letterGroups.forEach(function (group) {
 | 
			
		||||
				if (group.code.indexOf(country.letter) >= 0 || (group.code == commonGroupName && country.isCommon)) {
 | 
			
		||||
					if (country.isChecked) {
 | 
			
		||||
						group.count++
 | 
			
		||||
					}
 | 
			
		||||
					if (that.matchCountry(country)) {
 | 
			
		||||
						country.isMatched = (that.keyword.length > 0)
 | 
			
		||||
						group.countMatched++
 | 
			
		||||
					} else {
 | 
			
		||||
						country.isMatched = false
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.submit = function () {
 | 
			
		||||
		let selectedCountries = []
 | 
			
		||||
		this.countries.forEach(function (country) {
 | 
			
		||||
			if (country.isChecked) {
 | 
			
		||||
				selectedCountries.push(country)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
		NotifyPopup({
 | 
			
		||||
			code: 200,
 | 
			
		||||
			data: {
 | 
			
		||||
				selectedCountries: selectedCountries
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * searching
 | 
			
		||||
	 */
 | 
			
		||||
	this.searchBoxVisible = false
 | 
			
		||||
	this.keyword = ""
 | 
			
		||||
 | 
			
		||||
	this.showSearchBox = function () {
 | 
			
		||||
		this.searchBoxVisible = true
 | 
			
		||||
		this.$delay(function () {
 | 
			
		||||
			this.$refs.searchBox.focus()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.changeKeyword = function (event) {
 | 
			
		||||
		this.keyword = event.value.trim()
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.matchCountry = function (country) {
 | 
			
		||||
		if (this.keyword.length == 0) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (teaweb.match(country.name, this.keyword)) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if (country.pinyin != null && country.pinyin.length > 0) {
 | 
			
		||||
			let matched = false
 | 
			
		||||
			let that = this
 | 
			
		||||
			country.pinyin.forEach(function (code) {
 | 
			
		||||
				if (teaweb.match(code, that.keyword)) {
 | 
			
		||||
					matched = true
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
			if (matched) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (country.codes != null && country.codes.length > 0) {
 | 
			
		||||
			let matched = false
 | 
			
		||||
			let that = this
 | 
			
		||||
			country.codes.forEach(function (code) {
 | 
			
		||||
				if (teaweb.match(code, that.keyword)) {
 | 
			
		||||
					matched = true
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
			if (matched) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
.region-letter-group {
 | 
			
		||||
	.item {
 | 
			
		||||
		padding-left: 0.8em !important;
 | 
			
		||||
		padding-right: 0.8em !important;
 | 
			
		||||
 | 
			
		||||
		.count {
 | 
			
		||||
			font-size: 0.8em;
 | 
			
		||||
			color: grey;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.country-groups {
 | 
			
		||||
	max-height: 23em;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
 | 
			
		||||
	.country-group {
 | 
			
		||||
		padding-bottom: 1em;
 | 
			
		||||
 | 
			
		||||
		.country-list {
 | 
			
		||||
			.item {
 | 
			
		||||
				float: left;
 | 
			
		||||
				width: 9em;
 | 
			
		||||
				margin-bottom: 0.5em;
 | 
			
		||||
 | 
			
		||||
				.checkbox label {
 | 
			
		||||
					font-size: 12px !important;
 | 
			
		||||
					cursor: pointer !important;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.country-groups::-webkit-scrollbar {
 | 
			
		||||
	width: 4px;
 | 
			
		||||
}
 | 
			
		||||
@@ -7,4 +7,4 @@
 | 
			
		||||
  font-size: 12px !important;
 | 
			
		||||
  cursor: pointer !important;
 | 
			
		||||
}
 | 
			
		||||
/*# sourceMappingURL=provinces.css.map */
 | 
			
		||||
/*# sourceMappingURL=selectProvincesPopup.css.map */
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"sources":["selectProvincesPopup.less"],"names":[],"mappings":"AAAA,cACC;EACC,WAAA;EACA,WAAA;EACA,oBAAA;;AAJF,cACC,MAKC,UAAU;EACT,0BAAA;EACA,0BAAA","file":"selectProvincesPopup.css"}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3 v-show="type == 'allow'">选择允许的省份</h3>
 | 
			
		||||
<h3 v-show="type == 'deny'">选择封禁的省份</h3>
 | 
			
		||||
 | 
			
		||||
<form class="ui form">
 | 
			
		||||
    <table class="ui table">
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>
 | 
			
		||||
                <first-menu>
 | 
			
		||||
                    <div class="item right">
 | 
			
		||||
                        <div class="ui checkbox" @click.prevent="checkAll">
 | 
			
		||||
                            <input type="checkbox" v-model="isCheckingAll"/>
 | 
			
		||||
                            <label>全选</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </first-menu>
 | 
			
		||||
 | 
			
		||||
                <div class="province-list" style="margin-top:0.5em">
 | 
			
		||||
                    <div class="item" v-for="province in provinces">
 | 
			
		||||
                        <div class="ui checkbox" @click.prevent="selectProvince(province)">
 | 
			
		||||
                            <input type="checkbox" v-model="province.isChecked"/>
 | 
			
		||||
                            <label>{{province.name}}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="clear"></div>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
    </table>
 | 
			
		||||
    <button class="ui button primary" type="button" @click.prevent="submit">确定</button>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.isCheckingAll = false
 | 
			
		||||
 | 
			
		||||
	this.countSelectedProvinces = this.provinces.$count(function (k, province) {
 | 
			
		||||
		return province.isChecked
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	this.selectProvince = function (province) {
 | 
			
		||||
		province.isChecked = !province.isChecked
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.deselectProvince = function (province) {
 | 
			
		||||
		province.isChecked = false
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.checkAll = function () {
 | 
			
		||||
		this.isCheckingAll = !this.isCheckingAll
 | 
			
		||||
		let that = this
 | 
			
		||||
		this.provinces.forEach(function (province) {
 | 
			
		||||
			province.isChecked = that.isCheckingAll
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		this.change()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.change = function () {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.submit = function () {
 | 
			
		||||
		let selectedProvinces = []
 | 
			
		||||
		this.provinces.forEach(function (province) {
 | 
			
		||||
			if (province.isChecked) {
 | 
			
		||||
				selectedProvinces.push(province)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
		NotifyPopup({
 | 
			
		||||
			code: 200,
 | 
			
		||||
			data: {
 | 
			
		||||
				selectedProvinces: selectedProvinces
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
		Reference in New Issue
	
	Block a user