from flask_wtf import FlaskForm from wtforms import IntegerField, PasswordField, SelectField, StringField, SubmitField from wtforms.validators import DataRequired, NumberRange, Optional, ValidationError class LoginForm(FlaskForm): username = StringField("用户名", validators=[DataRequired(message="请输入用户名")]) password = PasswordField("密码", validators=[DataRequired(message="请输入密码")]) submit = SubmitField("登录") class GroupForm(FlaskForm): name = StringField("分组名称", validators=[DataRequired(message="请输入分组名称")]) sort_order = IntegerField( "排序(越小越靠前)", validators=[Optional(), NumberRange(min=-10**6, max=10**6)], default=0, ) submit = SubmitField("保存") class ServiceForm(FlaskForm): name = StringField("服务名称", validators=[DataRequired(message="请输入服务名称")]) scheme = SelectField( "协议", choices=[("http", "HTTP"), ("https", "HTTPS")], default="http", validators=[DataRequired(message="请选择协议")], ) host = StringField( "主机或域名", validators=[DataRequired(message="请输入主机或域名")], ) port = IntegerField( "端口", validators=[ DataRequired(message="请输入端口"), NumberRange(min=1, max=65535, message="端口范围 1–65535"), ], ) path = StringField("路径(可选,默认 /)", validators=[Optional()]) group_id = SelectField("分组", coerce=int, validators=[DataRequired(message="请选择分组")]) sort_order = IntegerField( "排序(越小越靠前)", validators=[Optional(), NumberRange(min=-10**6, max=10**6)], default=0, ) embed_kind = SelectField( "嵌入类型", choices=[ ("", "普通(直接打开路径)"), ("hub", "复盘中控(云端 hub,需 embed-auth 登录)"), ("gate_scout", "Gate 扫描端(iframe 代登录)"), ("gate_exec", "Gate 执行器(iframe 代登录)"), ], default="", validators=[Optional()], ) submit = SubmitField("保存") def validate_path(self, field): v = (field.data or "").strip() if v and not v.startswith("/"): raise ValidationError("路径需以 / 开头,例如 /admin")