<script setup>

import "@/lib/array.js"
import useUtils from "@/utils/utils.js"
import {inject, onMounted, ref, watch} from "vue"
import TOption from "@/components/ui/TOption.vue";
import TSelect from "@/components/ui/TSelect.vue";
import TButton from "@/components/ui/TButton.vue";
import TInputText from "@/components/ui/TInputText.vue";
import ValuesBox from "@/components/common/ValuesBox.vue";
import TTextarea from "@/components/ui/TTextarea.vue";
import TCheckboxBinary from "@/components/ui/TCheckboxBinary.vue";
import TLabel from "@/components/ui/TLabel.vue";
import TInputGroup from "@/components/ui/TInputGroup.vue";
import TInputGroupAddon from "@/components/ui/TInputGroupAddon.vue";
import TDivider from "@/components/ui/TDivider.vue";
import PlusButton from "@/components/common/PlusButton.vue";
import Sortable from "sortablejs";

const utils = inject("$utils")

const Tea = inject("$Tea")

const props = defineProps(["v-actions", "v-firewall-policy", "v-action-configs", "v-group-type"])

const actionsBoxRef = ref()

const {
	id,
	actions,
	configs,
	isAdding,
	editingIndex,
	action,
	actionCode,
	actionOptions, // IPList相关
	ipListLevels,
	allowScope,
	blockTimeout,
	blockTimeoutMax,
	blockScope,
	captchaLife,
	captchaMaxFails,
	captchaFailBlockTimeout,
	get302Life,
	post307Life,
	recordIPType,
	recordIPLevel,
	recordIPTimeout,
	recordIPListId,
	recordIPListName,
	tagTags,
	pageUseDefault,
	pageStatus,
	pageBody,
	defaultPageBody,
	redirectStatus,
	redirectURL,
	goGroupName,
	goGroupId,
	goGroup,
	goSetId,
	goSetName,
	jsCookieLife,
	jsCookieMaxFails,
	jsCookieFailBlockTimeout,
	statusOptions
} = (function () {
	if (props.vFirewallPolicy.inbound == null) {
		props.vFirewallPolicy.inbound = {}
	}
	if (props.vFirewallPolicy.inbound.groups == null) {
		props.vFirewallPolicy.inbound.groups = []
	}

	if (props.vFirewallPolicy.outbound == null) {
		props.vFirewallPolicy.outbound = {}
	}
	if (props.vFirewallPolicy.outbound.groups == null) {
		props.vFirewallPolicy.outbound.groups = []
	}

	let id = 0
	let configs = []
	if (props.vActionConfigs != null) {
		configs = props.vActionConfigs
		configs.forEach(function (v) {
			v.id = (id++)
		})
	}

	var defaultPageBody = `<!DOCTYPE html>
<html lang="en">
<head>
\t<title>403 Forbidden</title>
\t<style>
\t\taddress { line-height: 1.8; }
\t</style>
</head>
<body>
<h1>403 Forbidden</h1>
<address>Connection: \${remoteAddr} (Client) -&gt; \${serverAddr} (Server)</address>
<address>Request ID: \${requestId}</address>
</body>
</html>`

	return {
		id: ref(id),

		actions: ref(props.vActions),
		configs: ref(configs),
		isAdding: ref(false),
		editingIndex: ref(-1),

		action: ref(null),
		actionCode: ref(""),
		actionOptions: ref({}),

		// IPList相关
		ipListLevels: ref([]),

		// 动作参数
		allowScope: ref("global"),

		blockTimeout: ref(""),
		blockTimeoutMax: ref(""),
		blockScope: ref("global"),

		captchaLife: ref(""),
		captchaMaxFails: ref(""),
		captchaFailBlockTimeout: ref(""),

		get302Life: ref(""),

		post307Life: ref(""),

		recordIPType: ref("black"),
		recordIPLevel: ref("critical"),
		recordIPTimeout: ref(""),
		recordIPListId: ref(0),
		recordIPListName: ref(""),

		tagTags: ref([]),

		pageUseDefault: ref(true),
		pageStatus: ref(403),
		pageBody: ref(defaultPageBody),
		defaultPageBody: ref(defaultPageBody),

		redirectStatus: ref(307),
		redirectURL: ref(""),

		goGroupName: ref(""),
		goGroupId: ref(0),
		goGroup: ref(null),

		goSetId: ref(0),
		goSetName: ref(""),

		jsCookieLife: ref(""),
		jsCookieMaxFails: ref(""),
		jsCookieFailBlockTimeout: ref(""),

		statusOptions: ref([
			{"code": 301, "text": "Moved Permanently"},
			{"code": 308, "text": "Permanent Redirect"},
			{"code": 302, "text": "Found"},
			{"code": 303, "text": "See Other"},
			{"code": 307, "text": "Temporary Redirect"}
		])
	}
})()

const add = function () {
	action.value = null
	actionCode.value = "page"
	isAdding.value = true
	actionOptions.value = {}

	// 动作参数
	allowScope.value = "global"

	blockTimeout.value = ""
	blockTimeoutMax.value = ""
	blockScope.value = "global"

	captchaLife.value = ""
	captchaMaxFails.value = ""
	captchaFailBlockTimeout.value = ""

	jsCookieLife.value = ""
	jsCookieMaxFails.value = ""
	jsCookieFailBlockTimeout.value = ""

	get302Life.value = ""

	post307Life.value = ""

	recordIPLevel.value = "critical"
	recordIPType.value = "black"
	recordIPTimeout.value = ""
	recordIPListId.value = 0
	recordIPListName.value = ""

	tagTags.value = []

	pageUseDefault.value = true
	pageStatus.value = 403
	pageBody.value = defaultPageBody.value

	redirectStatus.value = 307
	redirectURL.value = ""

	goGroupName.value = ""
	goGroupId.value = 0
	goGroup.value = null

	goSetId.value = 0
	goSetName.value = ""

	action.value = props.vActions.$find(function (k, v) {
		return v.code == actionCode.value
	})

	// 滚到界面底部
	scroll()
}

const remove = function (index) {
	isAdding.value = false
	editingIndex.value = -1
	configs.value.$remove(index)
}

const update = function (index, config) {
	if (isAdding.value && editingIndex.value == index) {
		cancel()
		return
	}

	add()

	isAdding.value = true
	editingIndex.value = index

	actionCode.value = config.code
	action.value = actions.value.$find(function (k, v) {
		return v.code == config.code
	})

	switch (config.code) {
		case "block":
			blockTimeout.value = ""
			blockTimeoutMax.value = ""
			if (config.options.timeout != null || config.options.timeout > 0) {
				blockTimeout.value = config.options.timeout.toString()
			}
			if (config.options.timeoutMax != null || config.options.timeoutMax > 0) {
				blockTimeoutMax.value = config.options.timeoutMax.toString()
			}
			if (config.options.scope != null && config.options.scope.length > 0) {
				blockScope.value = config.options.scope
			} else {
				blockScope.value = "global" // 兼容先前版本遗留的默认值
			}
			break
		case "allow":
			if (config.options != null && config.options.scope != null && config.options.scope.length > 0) {
				allowScope.value = config.options.scope
			} else {
				allowScope.value = "global"
			}
			break
		case "log":
			break
		case "captcha":
			captchaLife.value = ""
			if (config.options.life != null || config.options.life > 0) {
				captchaLife.value = config.options.life.toString()
			}
			captchaMaxFails.value = ""
			if (config.options.maxFails != null || config.options.maxFails > 0) {
				captchaMaxFails.value = config.options.maxFails.toString()
			}
			captchaFailBlockTimeout.value = ""
			if (config.options.failBlockTimeout != null || config.options.failBlockTimeout > 0) {
				captchaFailBlockTimeout.value = config.options.failBlockTimeout.toString()
			}
			break
		case "js_cookie":
			jsCookieLife.value = ""
			if (config.options.life != null || config.options.life > 0) {
				jsCookieLife.value = config.options.life.toString()
			}
			jsCookieMaxFails.value = ""
			if (config.options.maxFails != null || config.options.maxFails > 0) {
				jsCookieMaxFails.value = config.options.maxFails.toString()
			}
			jsCookieFailBlockTimeout.value = ""
			if (config.options.failBlockTimeout != null || config.options.failBlockTimeout > 0) {
				jsCookieFailBlockTimeout.value = config.options.failBlockTimeout.toString()
			}
			break
		case "notify":
			break
		case "get_302":
			get302Life.value = ""
			if (config.options.life != null || config.options.life > 0) {
				get302Life.value = config.options.life.toString()
			}
			break
		case "post_307":
			post307Life.value = ""
			if (config.options.life != null || config.options.life > 0) {
				post307Life.value = config.options.life.toString()
			}
			break;
		case "record_ip":
			if (config.options != null) {
				recordIPLevel.value = config.options.level
				recordIPType.value = config.options.type
				if (config.options.timeout > 0) {
					recordIPTimeout.value = config.options.timeout.toString()
				}

				// VUE需要在函数执行完之后才会调用watch函数，这样会导致设置的值被覆盖，所以这里使用setTimeout
				setTimeout(function () {
					recordIPListId.value = config.options.ipListId
					recordIPListName.value = config.options.ipListName
				})
			}
			break
		case "tag":
			tagTags.value = []
			if (config.options.tags != null) {
				tagTags.value = config.options.tags
			}
			break
		case "page":
			pageUseDefault.value = true
			pageStatus.value = 403
			pageBody.value = defaultPageBody.value
			if (typeof config.options.useDefault === "boolean") {
				pageUseDefault.value = config.options.useDefault
			} else {
				pageUseDefault.value = false
			}
			if (config.options.status != null) {
				pageStatus.value = config.options.status
			}
			if (config.options.body != null) {
				pageBody.value = config.options.body
			}
			break
		case "redirect":
			redirectStatus.value = 307
			redirectURL.value = ""
			if (config.options.status != null) {
				redirectStatus.value = config.options.status
			}
			if (config.options.url != null) {
				redirectURL.value = config.options.url
			}
			break
		case "go_group":
			if (config.options != null) {
				goGroupName.value = config.options.groupName
				goGroupId.value = config.options.groupId
				goGroup.value = props.vFirewallPolicy.inbound.groups.$find(function (k, v) {
					return v.id == config.options.groupId
				})
			}
			break
		case "go_set":
			if (config.options != null) {
				goGroupName.value = config.options.groupName
				goGroupId.value = config.options.groupId
				goGroup.value = props.vFirewallPolicy.inbound.groups.$find(function (k, v) {
					return v.id == config.options.groupId
				})

				// VUE需要在函数执行完之后才会调用watch函数，这样会导致设置的值被覆盖，所以这里使用setTimeout
				setTimeout(function () {
					goSetId.value = config.options.setId
					if (goGroup.value != null) {
						let set = goGroup.value.sets.$find(function (k, v) {
							return v.id == config.options.setId
						})
						if (set != null) {
							goSetName.value = set.name
						}
					}
				})
			}
			break
	}

	// 滚到界面底部
	scroll()
}

const cancel = function () {
	isAdding.value = false
	editingIndex.value = -1
}

const confirm = function () {
	if (action.value == null) {
		return
	}

	if (actionOptions.value == null) {
		actionOptions.value = {}
	}

	// record_ip
	if (actionCode.value == "record_ip") {
		let timeout = parseInt(recordIPTimeout.value)
		if (isNaN(timeout)) {
			timeout = 0
		}
		if (recordIPListId.value < 0) {
			return
		}

		// recordIPListId can be 0

		actionOptions.value = {
			type: recordIPType.value,
			level: recordIPLevel.value,
			timeout: timeout,
			ipListId: recordIPListId.value,
			ipListName: recordIPListName.value
		}
	} else if (actionCode.value == "tag") { // tag
		if (tagTags.value == null || tagTags.value.length == 0) {
			return
		}
		actionOptions.value = {
			tags: tagTags.value
		}
	} else if (actionCode.value == "page") {
		let _pageStatus = pageStatus.value.toString()
		if (!_pageStatus.match(/^\d{3}$/)) {
			_pageStatus = 403
		} else {
			_pageStatus = parseInt(_pageStatus)
		}

		actionOptions.value = {
			useDefault: pageUseDefault.value,
			status: _pageStatus,
			body: pageBody.value
		}
	} else if (actionCode.value == "redirect") {
		let _redirectStatus = redirectStatus.value.toString()
		if (!_redirectStatus.match(/^\d{3}$/)) {
			_redirectStatus = 307
		} else {
			_redirectStatus = parseInt(_redirectStatus)
		}

		if (redirectURL.value.length == 0) {
			utils.warn("请输入跳转到URL")
			return
		}

		actionOptions.value = {
			status: _redirectStatus,
			url: redirectURL.value
		}
	} else if (actionCode.value == "go_group") { // go_group
		let groupId = goGroupId.value
		if (typeof (groupId) == "string") {
			groupId = parseInt(groupId)
			if (isNaN(groupId)) {
				groupId = 0
			}
		}
		if (groupId <= 0) {
			return
		}
		actionOptions.value = {
			groupId: groupId.toString(),
			groupName: goGroupName.value
		}
	} else if (actionCode.value == "go_set") { // go_set
		let _groupId = goGroupId.value
		if (typeof (_groupId) == "string") {
			_groupId = parseInt(_groupId)
			if (isNaN(_groupId)) {
				_groupId = 0
			}
		}

		let _setId = goSetId.value
		if (typeof (_setId) == "string") {
			_setId = parseInt(_setId)
			if (isNaN(_setId)) {
				_setId = 0
			}
		}
		if (_setId <= 0) {
			return
		}
		actionOptions.value = {
			groupId: _groupId.toString(),
			groupName: goGroupName.value,
			setId: _setId.toString(),
			setName: goSetName.value
		}
	}

	let options = {}
	for (let k in actionOptions.value) {
		if (actionOptions.value.hasOwnProperty(k)) {
			options[k] = actionOptions.value[k]
		}
	}
	if (editingIndex.value > -1) {
		configs.value[editingIndex.value] = {
			id: configs.value[editingIndex.value].id,
			code: actionCode.value,
			name: action.value.name,
			options: options
		}
	} else {
		configs.value.push({
			id: (id.value++),
			code: actionCode.value,
			name: action.value.name,
			options: options
		})
	}

	cancel()
}

const removeRecordIPList = function () {
	recordIPListId.value = 0
}

const selectRecordIPList = function () {
	utils.popup("/servers/iplists/selectPopup?type=" + recordIPType.value, {
		width: "50em",
		callback: function (resp) {
			recordIPListId.value = resp.data.list.id
			recordIPListName.value = resp.data.list.name
		}
	})
}

const changeTags = function (tags) {
	tagTags.value = tags
}

const scroll = function () {
	// TODO 重新实现，滚动到 “执行动作“ 一栏
}

watch(actionCode, function (code) {
	action.value = actions.value.$find(function (k, v) {
		return v.code == code
	})
	actionOptions.value = {}
})

watch(allowScope, function (v) {
	actionOptions.value["scope"] = v
})

watch(blockTimeout, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["timeout"] = 0
	} else {
		actionOptions.value["timeout"] = v
	}
})

watch(blockTimeoutMax, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["timeoutMax"] = 0
	} else {
		actionOptions.value["timeoutMax"] = v
	}
})

watch(blockScope, function (v) {
	actionOptions.value["scope"] = v
})

watch(captchaLife, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["life"] = 0
	} else {
		actionOptions.value["life"] = v
	}
})

watch(captchaMaxFails, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["maxFails"] = 0
	} else {
		actionOptions.value["maxFails"] = v
	}
})

watch(captchaFailBlockTimeout, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["failBlockTimeout"] = 0
	} else {
		actionOptions.value["failBlockTimeout"] = v
	}
})

watch(get302Life, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["life"] = 0
	} else {
		actionOptions.value["life"] = v
	}
})

watch(post307Life, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["life"] = 0
	} else {
		actionOptions.value["life"] = v
	}
})

watch(recordIPType, function (v) {
	recordIPListId.value = 0
})

watch(recordIPTimeout, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["timeout"] = 0
	} else {
		actionOptions.value["timeout"] = v
	}
})

watch(goGroupId, function (groupId) {
	let group = props.vFirewallPolicy.inbound.groups.$find(function (k, v) {
		return v.id == groupId
	})
	goGroup.value = group
	if (group == null) {
		// search outbound groups
		group = props.vFirewallPolicy.outbound.groups.$find(function (k, v) {
			return v.id == groupId
		})
		if (group == null) {
			goGroupName.value = ""
		} else {
			goGroup.value = group
			goGroupName.value = group.name
		}
	} else {
		goGroupName.value = group.name
	}
	goSetId.value = 0
	goSetName.value = ""
})

watch(goSetId, function (setId) {
	if (goGroup.value == null) {
		return
	}
	let set = goGroup.value.sets.$find(function (k, v) {
		return v.id == setId
	})
	if (set == null) {
		goSetId.value = 0
		goSetName.value = ""
	} else {
		goSetName.value = set.name
	}
})

watch(jsCookieLife, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["life"] = 0
	} else {
		actionOptions.value["life"] = v
	}
})

watch(jsCookieMaxFails, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["maxFails"] = 0
	} else {
		actionOptions.value["maxFails"] = v
	}
})

watch(jsCookieFailBlockTimeout, function (v) {
	v = parseInt(v)
	if (isNaN(v)) {
		actionOptions.value["failBlockTimeout"] = 0
	} else {
		actionOptions.value["failBlockTimeout"] = v
	}
})

onMounted(() => {
	Tea.action("/servers/iplists/levelOptions")
		.success(function (resp) {
			ipListLevels.value = resp.data.levels
		})
		.post()

	Sortable.create(actionsBoxRef.value, {
		draggable: ".sort-label",
		handle: ".sort-handle",
		onUpdate: function (event) {
			utils.moveElement(configs.value, event.oldDraggableIndex, event.newDraggableIndex)
		}
	})
})


</script>

<template>
	<div>
		<input type="hidden" name="actionsJSON" :value="JSON.stringify(configs)"/>
		<div v-show="configs.length > 0" class="label-group" ref="actionsBoxRef">
			<TLabel outlined="" v-for="(config, index) in configs" :data-index="index" :key="config.id" class="sort-label" :class="{blue: index == editingIndex}">
				{{ config.name }} <span class="small">({{ config.code.toUpperCase() }})</span>

				<!-- allow -->
				<span class="small" v-if="config.code == 'allow' && config.options != null && config.options.scope != null && config.options.scope.length > 0">
				<span v-if="config.options.scope == 'group'">[分组]</span>
				<span v-if="config.options.scope == 'server'">[网站]</span>
				<span v-if="config.options.scope == 'global'">[网站和策略]</span>
			</span>

				<!-- block -->
				<span v-if="config.code == 'block' && config.options.timeout > 0">：封禁时长{{ config.options.timeout }}<span v-if="config.options.timeoutMax > config.options.timeout">-{{ config.options.timeoutMax }}</span>秒</span>

				<!-- captcha -->
				<span v-if="config.code == 'captcha' && config.options.life > 0">：有效期{{ config.options.life }}秒
				<span v-if="config.options.maxFails > 0"> / 最多失败{{ config.options.maxFails }}次</span>
			</span>

				<!-- js cookie -->
				<span v-if="config.code == 'js_cookie' && config.options.life > 0">：有效期{{ config.options.life }}秒
				<span v-if="config.options.maxFails > 0"> / 最多失败{{ config.options.maxFails }}次</span>
			</span>

				<!-- get 302 -->
				<span v-if="config.code == 'get_302' && config.options.life > 0">：有效期{{ config.options.life }}秒</span>

				<!-- post 307 -->
				<span v-if="config.code == 'post_307' && config.options.life > 0">：有效期{{ config.options.life }}秒</span>

				<!-- record_ip -->
				<span v-if="config.code == 'record_ip'">：<span :class="{red: config.options.ipListIsDeleted}">{{ config.options.ipListName }}</span></span>

				<!-- tag -->
				<span v-if="config.code == 'tag'">：{{ config.options.tags.join(", ") }}</span>

				<!-- page -->
				<span v-if="config.code == 'page'">：[{{ config.options.status }}]<span v-if="config.options.useDefault">&nbsp; [默认页面]</span></span>

				<!-- redirect -->
				<span v-if="config.code == 'redirect'">：{{ config.options.url }}</span>

				<!-- go_group -->
				<span v-if="config.code == 'go_group'">：{{ config.options.groupName }}</span>

				<!-- go_set -->
				<span v-if="config.code == 'go_set'">：{{ config.options.groupName }} / {{ config.options.setName }}</span>

				<!-- 范围 -->
				<span v-if="config.code != 'allow' && config.options.scope != null && config.options.scope.length > 0" class="small grey">
				&nbsp; 
				<span v-if="config.options.scope == 'global'">[所有网站]</span>
				<span v-if="config.options.scope == 'service'">[当前网站]</span>
			</span>

				<!-- 操作按钮 -->
				&nbsp; <a href="" title="修改" @click.prevent="update(index, config)"><i class="icon pencil small"></i></a> &nbsp;
				<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a> &nbsp;
				<a href="" title="拖动改变顺序"><i class="icon bars sort-handle"></i></a>
			</TLabel>
			<TDivider></TDivider>
		</div>
		<div style="margin-bottom: 0.5em" v-if="isAdding">
			<table class="ui table definition" :class="{blue: editingIndex > -1}">
				<tr>
					<td class="title">动作类型 *</td>
					<td>
						<TSelect v-model="actionCode">
							<TOption v-for="action in actions" :value="action.code">{{ action.name }} ({{ action.code.toUpperCase() }})</TOption>
						</TSelect>
						<p class="comment" v-if="action != null && action.description.length > 0">{{ action.description }}</p>
					</td>
				</tr>

				<!-- allow -->
				<tr v-if="actionCode == 'allow'">
					<td>有效范围</td>
					<td>
						<TSelect v-model="allowScope">
							<TOption value="group">分组</TOption>
							<TOption value="server">网站</TOption>
							<TOption value="global">网站和策略</TOption>
						</TSelect>
						<p class="comment" v-if="allowScope == 'group'">跳过当前分组其他规则集，继续执行其他分组的规则集。</p>
						<p class="comment" v-if="allowScope == 'server'">跳过当前网站所有的规则集。</p>
						<p class="comment" v-if="allowScope =='global'">跳过当前网站和网站对应WAF策略所有的规则集。</p>
					</td>
				</tr>

				<!-- block -->
				<tr v-if="actionCode == 'block'">
					<td>封禁范围</td>
					<td>
						<TSelect v-model="blockScope">
							<TOption value="service">当前网站</TOption>
							<TOption value="global">所有网站</TOption>
						</TSelect>
						<p class="comment" v-if="blockScope == 'service'">只封禁用户对当前网站的访问，其他网站不受影响。</p>
						<p class="comment" v-if="blockScope =='global'">封禁用户对所有网站的访问。</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'block'">
					<td>封禁时长</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="blockTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
					</td>
				</tr>
				<tr v-if="actionCode == 'block'">
					<td>最大封禁时长</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="blockTimeoutMax" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">选填项。如果同时填写了封禁时长和最大封禁时长，则会在两者之间随机选择一个数字作为最终的封禁时长。</p>
					</td>
				</tr>

				<!-- captcha -->
				<tr v-if="actionCode == 'captcha'">
					<td>有效时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="captchaLife" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">验证通过后在这个时间内不再验证；如果为空或者为0表示默认。</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'captcha'">
					<td>最多失败次数</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="captchaMaxFails" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>次</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">
							<span v-if="captchaMaxFails > 0 && captchaMaxFails < 5" class="red">建议填入一个不小于5的数字，以减少误判几率。</span>允许用户失败尝试的最多次数，超过这个次数将被自动加入黑名单；如果为空或者为0表示默认。
						</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'captcha'">
					<td>失败拦截时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="captchaFailBlockTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">在达到最多失败次数（大于0）时，自动拦截的时间；如果为空或者为0表示默认。</p>
					</td>
				</tr>

				<!-- js cookie -->
				<tr v-if="actionCode == 'js_cookie'">
					<td>有效时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="jsCookieLife" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">验证通过后在这个时间内不再验证；如果为空或者为0表示默认。</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'js_cookie'">
					<td>最多失败次数</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="jsCookieMaxFails" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>次</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">允许用户失败尝试的最多次数，超过这个次数将被自动加入黑名单；如果为空或者为0表示默认。</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'js_cookie'">
					<td>失败拦截时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="jsCookieFailBlockTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">在达到最多失败次数（大于0）时，自动拦截的时间；如果为空或者为0表示默认。</p>
					</td>
				</tr>

				<!-- get_302 -->
				<tr v-if="actionCode == 'get_302'">
					<td>有效时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="get302Life" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">验证通过后在这个时间内不再验证。</p>
					</td>
				</tr>

				<!-- post_307 -->
				<tr v-if="actionCode == 'post_307'">
					<td>有效时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 5em" maxlength="9" v-model="post307Life" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">验证通过后在这个时间内不再验证。</p>
					</td>
				</tr>

				<!-- record_ip -->
				<tr v-if="actionCode == 'record_ip'">
					<td>IP名单类型 *</td>
					<td>
						<TSelect v-model="recordIPType">
							<TOption value="black">黑名单</TOption>
							<TOption value="white">白名单</TOption>
							<TOption value="grey">灰名单</TOption>
						</TSelect>
					</td>
				</tr>
				<tr v-if="actionCode == 'record_ip'">
					<td>选择IP名单</td>
					<td>
						<div v-if="recordIPListId > 0" class="mb-2">
							<TLabel outlined="">{{ recordIPListName }}
								<a href="" @click.prevent="removeRecordIPList"><i class="icon remove small"></i></a>
							</TLabel>
						</div>
						<PlusButton size="small" @click.prevent="selectRecordIPList">+</PlusButton>
						<p class="comment">如不选择，则自动添加到当前策略的IP名单中。</p>
					</td>
				</tr>
				<tr v-if="actionCode == 'record_ip'">
					<td>级别</td>
					<td>
						<TSelect v-model="recordIPLevel">
							<TOption v-for="level in ipListLevels" :value="level.code">{{ level.name }}</TOption>
						</TSelect>
					</td>
				</tr>
				<tr v-if="actionCode == 'record_ip'">
					<td>超时时间</td>
					<td>
						<TInputGroup>
							<TInputText type="text" style="width: 6em" maxlength="9" v-model="recordIPTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
							<TInputGroupAddon>
								<span>秒</span>
							</TInputGroupAddon>
						</TInputGroup>
						<p class="comment">0表示不超时。</p>
					</td>
				</tr>

				<!-- tag -->
				<tr v-if="actionCode == 'tag'">
					<td>标签 *</td>
					<td>
						<ValuesBox @change="changeTags" :values="tagTags"></ValuesBox>
					</td>
				</tr>

				<!-- page -->
				<tr v-if="actionCode == 'page'">
					<td>使用默认提示</td>
					<td>
						<TCheckboxBinary v-model="pageUseDefault"></TCheckboxBinary>
					</td>
				</tr>
				<tr v-if="actionCode == 'page' && !pageUseDefault">
					<td class="color-border">状态码 *</td>
					<td>
						<TInputText type="text" style="width: 4em" maxlength="3" v-model="pageStatus" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
					</td>
				</tr>
				<tr v-if="actionCode == 'page' && !pageUseDefault">
					<td class="color-border">网页内容</td>
					<td>
						<TTextarea v-model="pageBody" class="w-full" rows="5"></TTextarea>
					</td>
				</tr>

				<!-- redirect -->
				<tr v-if="actionCode == 'redirect'">
					<td>状态码 *</td>
					<td>
						<TSelect v-model="redirectStatus">
							<TOption v-for="status in statusOptions" :value="status.code">{{ status.code }} {{ status.text }}</TOption>
						</TSelect>
					</td>
				</tr>
				<tr v-if="actionCode == 'redirect'">
					<td>跳转到URL</td>
					<td>
						<TInputText type="text" v-model="redirectURL" class="w-full" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
					</td>
				</tr>

				<!-- 规则分组 -->
				<tr v-if="actionCode == 'go_group'">
					<td>下一个分组 *</td>
					<td>
						<TSelect v-model="goGroupId">
							<TOption value="0">[选择分组]</TOption>
							<TOption v-if="vFirewallPolicy.inbound != null && vFirewallPolicy.inbound.groups != null" v-for="group in vFirewallPolicy.inbound.groups" :value="group.id">入站：{{ group.name }}</TOption>
							<TOption v-if="vGroupType == 'outbound' && vFirewallPolicy.outbound != null && vFirewallPolicy.outbound.groups != null" v-for="group in vFirewallPolicy.outbound.groups" :value="group.id">出站：{{ group.name }}</TOption>
						</TSelect>
					</td>
				</tr>

				<!-- 规则集 -->
				<tr v-if="actionCode == 'go_set'">
					<td>下一个分组 *</td>
					<td>
						<TSelect v-model="goGroupId">
							<TOption value="0">[选择分组]</TOption>
							<TOption v-if="vFirewallPolicy.inbound != null && vFirewallPolicy.inbound.groups != null" v-for="group in vFirewallPolicy.inbound.groups" :value="group.id">入站：{{ group.name }}</TOption>
							<TOption v-if="vGroupType == 'outbound' && vFirewallPolicy.outbound != null && vFirewallPolicy.outbound.groups != null" v-for="group in vFirewallPolicy.outbound.groups" :value="group.id">出站：{{ group.name }}</TOption>
						</TSelect>
					</td>
				</tr>
				<tr v-if="actionCode == 'go_set' && goGroup != null">
					<td>下一个规则集 *</td>
					<td>
						<TSelect v-model="goSetId">
							<TOption value="0">[选择规则集]</TOption>
							<TOption v-for="set in goGroup.sets" :value="set.id">{{ set.name }}</TOption>
						</TSelect>
					</td>
				</tr>
			</table>
			<TButton secondary="" size="small" type="button" @click.prevent="confirm">确定</TButton> &nbsp;
			<a href="" @click.prevent="cancel" title="取消"><i class="icon remove small"></i></a>
		</div>
		<div v-if="!isAdding">
			<PlusButton size="small" @click.prevent="add"></PlusButton>
		</div>
		<p class="comment">系统总是会先执行记录日志、标签等不会修改请求的动作，再执行阻止、验证码等可能改变请求的动作。</p>
	</div>
</template>

<style scoped>
</style>
