Compare commits

..

1 Commits

21 changed files with 80 additions and 80 deletions

View File

@ -97,7 +97,7 @@ frp also offers a P2P connect mode.
* [Client Plugins](#client-plugins) * [Client Plugins](#client-plugins)
* [Server Manage Plugins](#server-manage-plugins) * [Server Manage Plugins](#server-manage-plugins)
* [SSH Tunnel Gateway](#ssh-tunnel-gateway) * [SSH Tunnel Gateway](#ssh-tunnel-gateway)
* [Related Projects](#related-projects) * [Releated Projects](#releated-projects)
* [Contributing](#contributing) * [Contributing](#contributing)
* [Donation](#donation) * [Donation](#donation)
* [GitHub Sponsors](#github-sponsors) * [GitHub Sponsors](#github-sponsors)
@ -1260,7 +1260,7 @@ frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote
Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information. Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information.
## Related Projects ## Releated Projects
* [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios. * [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios.
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources. * [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources.

View File

@ -8,7 +8,7 @@ import (
var ErrPayloadType = errors.New("error payload type") var ErrPayloadType = errors.New("error payload type")
type Handler func(payload any) error type Handler func(payload interface{}) error
type StartProxyPayload struct { type StartProxyPayload struct {
NewProxyMsg *msg.NewProxy NewProxyMsg *msg.NewProxy

View File

@ -96,7 +96,7 @@ func (pm *Manager) HandleWorkConn(name string, workConn net.Conn, m *msg.StartWo
} }
} }
func (pm *Manager) HandleEvent(payload any) error { func (pm *Manager) HandleEvent(payload interface{}) error {
var m msg.Message var m msg.Message
switch e := payload.(type) { switch e := payload.(type) {
case *event.StartProxyPayload: case *event.StartProxyPayload:

View File

@ -170,7 +170,7 @@ type ClientCommonConf struct {
} }
// Supported sources including: string(file path), []byte, Reader interface. // Supported sources including: string(file path), []byte, Reader interface.
func UnmarshalClientConfFromIni(source any) (ClientCommonConf, error) { func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,
@ -203,7 +203,7 @@ func UnmarshalClientConfFromIni(source any) (ClientCommonConf, error) {
// otherwise just start proxies in startProxy map // otherwise just start proxies in startProxy map
func LoadAllProxyConfsFromIni( func LoadAllProxyConfsFromIni(
prefix string, prefix string,
source any, source interface{},
start []string, start []string,
) (map[string]ProxyConf, map[string]VisitorConf, error) { ) (map[string]ProxyConf, map[string]VisitorConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{

View File

@ -217,7 +217,7 @@ func GetDefaultServerConf() ServerCommonConf {
} }
} }
func UnmarshalServerConfFromIni(source any) (ServerCommonConf, error) { func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,

View File

@ -118,7 +118,7 @@ func LoadConfigure(b []byte, c any, strict bool) error {
defer v1.DisallowUnknownFieldsMu.Unlock() defer v1.DisallowUnknownFieldsMu.Unlock()
v1.DisallowUnknownFields = strict v1.DisallowUnknownFields = strict
var tomlObj any var tomlObj interface{}
// Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML). // Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML).
if err := toml.Unmarshal(b, &tomlObj); err == nil { if err := toml.Unmarshal(b, &tomlObj); err == nil {
b, err = json.Marshal(&tomlObj) b, err = json.Marshal(&tomlObj)

View File

@ -39,6 +39,6 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) {
return msgCtl.ReadMsgInto(c, msg) return msgCtl.ReadMsgInto(c, msg)
} }
func WriteMsg(c io.Writer, msg any) (err error) { func WriteMsg(c io.Writer, msg interface{}) (err error) {
return msgCtl.WriteMsg(c, msg) return msgCtl.WriteMsg(c, msg)
} }

View File

@ -40,7 +40,7 @@ const (
TypeNatHoleReport = '6' TypeNatHoleReport = '6'
) )
var msgTypeMap = map[byte]any{ var msgTypeMap = map[byte]interface{}{
TypeLogin: Login{}, TypeLogin: Login{},
TypeLoginResp: LoginResp{}, TypeLoginResp: LoginResp{},
TypeNewProxy: NewProxy{}, TypeNewProxy: NewProxy{},

View File

@ -72,7 +72,7 @@ func (p *httpPlugin) IsSupport(op string) bool {
return false return false
} }
func (p *httpPlugin) Handle(ctx context.Context, op string, content any) (*Response, any, error) { func (p *httpPlugin) Handle(ctx context.Context, op string, content interface{}) (*Response, interface{}, error) {
r := &Request{ r := &Request{
Version: APIVersion, Version: APIVersion,
Op: op, Op: op,

View File

@ -75,7 +75,7 @@ func (m *Manager) Login(content *LoginContent) (*LoginContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent any retContent interface{}
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@ -109,7 +109,7 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent any retContent interface{}
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@ -168,7 +168,7 @@ func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent any retContent interface{}
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@ -202,7 +202,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent,
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent any retContent interface{}
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@ -236,7 +236,7 @@ func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent,
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent any retContent interface{}
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()

View File

@ -32,5 +32,5 @@ const (
type Plugin interface { type Plugin interface {
Name() string Name() string
IsSupport(op string) bool IsSupport(op string) bool
Handle(ctx context.Context, op string, content any) (res *Response, retContent any, err error) Handle(ctx context.Context, op string, content interface{}) (res *Response, retContent interface{}, err error)
} }

View File

@ -19,16 +19,16 @@ import (
) )
type Request struct { type Request struct {
Version string `json:"version"` Version string `json:"version"`
Op string `json:"op"` Op string `json:"op"`
Content any `json:"content"` Content interface{} `json:"content"`
} }
type Response struct { type Response struct {
Reject bool `json:"reject"` Reject bool `json:"reject"`
RejectReason string `json:"reject_reason"` RejectReason string `json:"reject_reason"`
Unchange bool `json:"unchange"` Unchange bool `json:"unchange"`
Content any `json:"content"` Content interface{} `json:"content"`
} }
type LoginContent struct { type LoginContent struct {

View File

@ -67,27 +67,27 @@ func InitLogger(logPath string, levelStr string, maxDays int, disableLogColor bo
Logger = Logger.WithOptions(options...) Logger = Logger.WithOptions(options...)
} }
func Errorf(format string, v ...any) { func Errorf(format string, v ...interface{}) {
Logger.Errorf(format, v...) Logger.Errorf(format, v...)
} }
func Warnf(format string, v ...any) { func Warnf(format string, v ...interface{}) {
Logger.Warnf(format, v...) Logger.Warnf(format, v...)
} }
func Infof(format string, v ...any) { func Infof(format string, v ...interface{}) {
Logger.Infof(format, v...) Logger.Infof(format, v...)
} }
func Debugf(format string, v ...any) { func Debugf(format string, v ...interface{}) {
Logger.Debugf(format, v...) Logger.Debugf(format, v...)
} }
func Tracef(format string, v ...any) { func Tracef(format string, v ...interface{}) {
Logger.Tracef(format, v...) Logger.Tracef(format, v...)
} }
func Logf(level log.Level, offset int, format string, v ...any) { func Logf(level log.Level, offset int, format string, v ...interface{}) {
Logger.Logf(level, offset, format, v...) Logger.Logf(level, offset, format, v...)
} }

View File

@ -24,7 +24,7 @@ type Router struct {
httpUser string httpUser string
// store any object here // store any object here
payload any payload interface{}
} }
func NewRouters() *Routers { func NewRouters() *Routers {
@ -33,7 +33,7 @@ func NewRouters() *Routers {
} }
} }
func (r *Routers) Add(domain, location, httpUser string, payload any) error { func (r *Routers) Add(domain, location, httpUser string, payload interface{}) error {
domain = strings.ToLower(domain) domain = strings.ToLower(domain)
r.mutex.Lock() r.mutex.Lock()

View File

@ -94,22 +94,22 @@ func (l *Logger) Spawn() *Logger {
return nl return nl
} }
func (l *Logger) Errorf(format string, v ...any) { func (l *Logger) Errorf(format string, v ...interface{}) {
log.Logger.Errorf(l.prefixString+format, v...) log.Logger.Errorf(l.prefixString+format, v...)
} }
func (l *Logger) Warnf(format string, v ...any) { func (l *Logger) Warnf(format string, v ...interface{}) {
log.Logger.Warnf(l.prefixString+format, v...) log.Logger.Warnf(l.prefixString+format, v...)
} }
func (l *Logger) Infof(format string, v ...any) { func (l *Logger) Infof(format string, v ...interface{}) {
log.Logger.Infof(l.prefixString+format, v...) log.Logger.Infof(l.prefixString+format, v...)
} }
func (l *Logger) Debugf(format string, v ...any) { func (l *Logger) Debugf(format string, v ...interface{}) {
log.Logger.Debugf(l.prefixString+format, v...) log.Logger.Debugf(l.prefixString+format, v...)
} }
func (l *Logger) Tracef(format string, v ...any) { func (l *Logger) Tracef(format string, v ...interface{}) {
log.Logger.Tracef(l.prefixString+format, v...) log.Logger.Tracef(l.prefixString+format, v...)
} }

View File

@ -196,15 +196,15 @@ func getConfByType(proxyType string) any {
// Get proxy info. // Get proxy info.
type ProxyStatsInfo struct { type ProxyStatsInfo struct {
Name string `json:"name"` Name string `json:"name"`
Conf any `json:"conf"` Conf interface{} `json:"conf"`
ClientVersion string `json:"clientVersion,omitempty"` ClientVersion string `json:"clientVersion,omitempty"`
TodayTrafficIn int64 `json:"todayTrafficIn"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"todayTrafficOut"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"curConns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"lastStartTime"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"lastCloseTime"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
type GetProxyInfoResp struct { type GetProxyInfoResp struct {
@ -272,14 +272,14 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
// Get proxy info by name. // Get proxy info by name.
type GetProxyStatsResp struct { type GetProxyStatsResp struct {
Name string `json:"name"` Name string `json:"name"`
Conf any `json:"conf"` Conf interface{} `json:"conf"`
TodayTrafficIn int64 `json:"todayTrafficIn"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"todayTrafficOut"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"curConns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"lastStartTime"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"lastCloseTime"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
// /api/proxy/:type/:name // /api/proxy/:type/:name

View File

@ -5,75 +5,75 @@ import (
) )
// ExpectEqual expects the specified two are the same, otherwise an exception raises // ExpectEqual expects the specified two are the same, otherwise an exception raises
func ExpectEqual(actual any, extra any, explain ...any) { func ExpectEqual(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.Equal(extra), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.Equal(extra), explain...)
} }
// ExpectEqualValues expects the specified two are the same, it not strict about type // ExpectEqualValues expects the specified two are the same, it not strict about type
func ExpectEqualValues(actual any, extra any, explain ...any) { func ExpectEqualValues(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.BeEquivalentTo(extra), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.BeEquivalentTo(extra), explain...)
} }
func ExpectEqualValuesWithOffset(offset int, actual any, extra any, explain ...any) { func ExpectEqualValuesWithOffset(offset int, actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1+offset, actual).To(gomega.BeEquivalentTo(extra), explain...) gomega.ExpectWithOffset(1+offset, actual).To(gomega.BeEquivalentTo(extra), explain...)
} }
// ExpectNotEqual expects the specified two are not the same, otherwise an exception raises // ExpectNotEqual expects the specified two are not the same, otherwise an exception raises
func ExpectNotEqual(actual any, extra any, explain ...any) { func ExpectNotEqual(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).NotTo(gomega.Equal(extra), explain...) gomega.ExpectWithOffset(1, actual).NotTo(gomega.Equal(extra), explain...)
} }
// ExpectError expects an error happens, otherwise an exception raises // ExpectError expects an error happens, otherwise an exception raises
func ExpectError(err error, explain ...any) { func ExpectError(err error, explain ...interface{}) {
gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...) gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...)
} }
func ExpectErrorWithOffset(offset int, err error, explain ...any) { func ExpectErrorWithOffset(offset int, err error, explain ...interface{}) {
gomega.ExpectWithOffset(1+offset, err).To(gomega.HaveOccurred(), explain...) gomega.ExpectWithOffset(1+offset, err).To(gomega.HaveOccurred(), explain...)
} }
// ExpectNoError checks if "err" is set, and if so, fails assertion while logging the error. // ExpectNoError checks if "err" is set, and if so, fails assertion while logging the error.
func ExpectNoError(err error, explain ...any) { func ExpectNoError(err error, explain ...interface{}) {
ExpectNoErrorWithOffset(1, err, explain...) ExpectNoErrorWithOffset(1, err, explain...)
} }
// ExpectNoErrorWithOffset checks if "err" is set, and if so, fails assertion while logging the error at "offset" levels above its caller // ExpectNoErrorWithOffset checks if "err" is set, and if so, fails assertion while logging the error at "offset" levels above its caller
// (for example, for call chain f -> g -> ExpectNoErrorWithOffset(1, ...) error would be logged for "f"). // (for example, for call chain f -> g -> ExpectNoErrorWithOffset(1, ...) error would be logged for "f").
func ExpectNoErrorWithOffset(offset int, err error, explain ...any) { func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) {
gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...) gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...)
} }
func ExpectContainSubstring(actual, substr string, explain ...any) { func ExpectContainSubstring(actual, substr string, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.ContainSubstring(substr), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.ContainSubstring(substr), explain...)
} }
// ExpectConsistOf expects actual contains precisely the extra elements. The ordering of the elements does not matter. // ExpectConsistOf expects actual contains precisely the extra elements. The ordering of the elements does not matter.
func ExpectConsistOf(actual any, extra any, explain ...any) { func ExpectConsistOf(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.ConsistOf(extra), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.ConsistOf(extra), explain...)
} }
func ExpectContainElements(actual any, extra any, explain ...any) { func ExpectContainElements(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.ContainElements(extra), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.ContainElements(extra), explain...)
} }
func ExpectNotContainElements(actual any, extra any, explain ...any) { func ExpectNotContainElements(actual interface{}, extra interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainElements(extra), explain...) gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainElements(extra), explain...)
} }
// ExpectHaveKey expects the actual map has the key in the keyset // ExpectHaveKey expects the actual map has the key in the keyset
func ExpectHaveKey(actual any, key any, explain ...any) { func ExpectHaveKey(actual interface{}, key interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.HaveKey(key), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.HaveKey(key), explain...)
} }
// ExpectEmpty expects actual is empty // ExpectEmpty expects actual is empty
func ExpectEmpty(actual any, explain ...any) { func ExpectEmpty(actual interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.BeEmpty(), explain...) gomega.ExpectWithOffset(1, actual).To(gomega.BeEmpty(), explain...)
} }
func ExpectTrue(actual any, explain ...any) { func ExpectTrue(actual interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).Should(gomega.BeTrue(), explain...) gomega.ExpectWithOffset(1, actual).Should(gomega.BeTrue(), explain...)
} }
func ExpectTrueWithOffset(offset int, actual any, explain ...any) { func ExpectTrueWithOffset(offset int, actual interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1+offset, actual).Should(gomega.BeTrue(), explain...) gomega.ExpectWithOffset(1+offset, actual).Should(gomega.BeTrue(), explain...)
} }

View File

@ -11,18 +11,18 @@ func nowStamp() string {
return time.Now().Format(time.StampMilli) return time.Now().Format(time.StampMilli)
} }
func log(level string, format string, args ...any) { func log(level string, format string, args ...interface{}) {
fmt.Fprintf(ginkgo.GinkgoWriter, nowStamp()+": "+level+": "+format+"\n", args...) fmt.Fprintf(ginkgo.GinkgoWriter, nowStamp()+": "+level+": "+format+"\n", args...)
} }
// Logf logs the info. // Logf logs the info.
func Logf(format string, args ...any) { func Logf(format string, args ...interface{}) {
log("INFO", format, args...) log("INFO", format, args...)
} }
// Failf logs the fail info, including a stack trace starts with its direct caller // Failf logs the fail info, including a stack trace starts with its direct caller
// (for example, for call chain f -> g -> Failf("foo", ...) error would be logged for "g"). // (for example, for call chain f -> g -> Failf("foo", ...) error would be logged for "g").
func Failf(format string, args ...any) { func Failf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...) msg := fmt.Sprintf(format, args...)
skip := 1 skip := 1
ginkgo.Fail(msg, skip) ginkgo.Fail(msg, skip)

View File

@ -67,8 +67,8 @@ func (m *MockServers) Close() {
os.Remove(m.udsEchoServer.BindAddr()) os.Remove(m.udsEchoServer.BindAddr())
} }
func (m *MockServers) GetTemplateParams() map[string]any { func (m *MockServers) GetTemplateParams() map[string]interface{} {
ret := make(map[string]any) ret := make(map[string]interface{})
ret[TCPEchoServerPort] = m.tcpEchoServer.BindPort() ret[TCPEchoServerPort] = m.tcpEchoServer.BindPort()
ret[UDPEchoServerPort] = m.udpEchoServer.BindPort() ret[UDPEchoServerPort] = m.udpEchoServer.BindPort()
ret[UDSEchoServerAddr] = m.udsEchoServer.BindAddr() ret[UDSEchoServerAddr] = m.udsEchoServer.BindAddr()
@ -76,7 +76,7 @@ func (m *MockServers) GetTemplateParams() map[string]any {
return ret return ret
} }
func (m *MockServers) GetParam(key string) any { func (m *MockServers) GetParam(key string) interface{} {
params := m.GetTemplateParams() params := m.GetTemplateParams()
if v, ok := params[key]; ok { if v, ok := params[key]; ok {
return v return v

View File

@ -42,7 +42,7 @@ type RequestExpect struct {
f *Framework f *Framework
expectResp []byte expectResp []byte
expectError bool expectError bool
explain []any explain []interface{}
} }
func NewRequestExpect(f *Framework) *RequestExpect { func NewRequestExpect(f *Framework) *RequestExpect {
@ -51,7 +51,7 @@ func NewRequestExpect(f *Framework) *RequestExpect {
f: f, f: f,
expectResp: []byte(consts.TestString), expectResp: []byte(consts.TestString),
expectError: false, expectError: false,
explain: make([]any, 0), explain: make([]interface{}, 0),
} }
} }
@ -94,7 +94,7 @@ func (e *RequestExpect) ExpectError(expectErr bool) *RequestExpect {
return e return e
} }
func (e *RequestExpect) Explain(explain ...any) *RequestExpect { func (e *RequestExpect) Explain(explain ...interface{}) *RequestExpect {
e.explain = explain e.explain = explain
return e return e
} }

View File

@ -8,7 +8,7 @@
type="textarea" type="textarea"
autosize autosize
v-model="textarea" v-model="textarea"
placeholder="frpc configure file, can not be empty..." placeholder="frpc configrue file, can not be empty..."
></el-input> ></el-input>
</div> </div>
</template> </template>