From a8a7fadcb19c261821113015656d1ad1eed3d35b Mon Sep 17 00:00:00 2001 From: lulz1 Date: Fri, 25 Oct 2024 16:51:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=94=A8=E6=88=B7=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=90=8E=E7=AB=AF=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 34 +++++ app/http/middleware/auth/middleware.go | 52 +++++++ app/http/middleware/response/middleware.go | 13 ++ app/http/module/user/api.go | 34 +++++ app/http/module/user/api_login.go | 45 ++++++ app/http/module/user/api_logout.go | 32 +++++ app/http/module/user/api_register.go | 66 +++++++++ app/http/module/user/api_verify.go | 39 +++++ app/http/module/user/dto.go | 10 ++ app/http/module/user/mapper.go | 15 ++ app/http/route.go | 4 + app/http/swagger/docs.go | 159 +++++++++++++++++++++ app/http/swagger/swagger.json | 159 +++++++++++++++++++++ app/http/swagger/swagger.yaml | 105 ++++++++++++++ app/provider/user/contract.go | 8 -- app/provider/user/provider.go | 31 ---- app/provider/user/service.go | 16 --- config/development/app.yaml | 10 +- config/development/database.yaml | 35 +++-- go.mod | 8 +- go.sum | 8 +- package.json | 7 +- src/App.vue | 16 +-- src/main.js | 4 + src/views/404.vue | 33 +++++ src/views/layout/container.vue | 25 ++++ src/views/layout/header.vue | 65 +++++++++ src/views/login/index.vue | 94 ++++++++++++ src/views/register/index.vue | 100 +++++++++++++ webpack.config.js | 6 +- yarn.lock | 54 +++++-- 31 files changed, 1178 insertions(+), 109 deletions(-) create mode 100644 .gitignore create mode 100644 app/http/middleware/auth/middleware.go create mode 100644 app/http/middleware/response/middleware.go create mode 100644 app/http/module/user/api.go create mode 100644 app/http/module/user/api_login.go create mode 100644 app/http/module/user/api_logout.go create mode 100644 app/http/module/user/api_register.go create mode 100644 app/http/module/user/api_verify.go create mode 100644 app/http/module/user/dto.go create mode 100644 app/http/module/user/mapper.go delete mode 100644 app/provider/user/contract.go delete mode 100644 app/provider/user/provider.go delete mode 100644 app/provider/user/service.go create mode 100644 src/views/404.vue create mode 100644 src/views/layout/container.vue create mode 100644 src/views/layout/header.vue create mode 100644 src/views/login/index.vue create mode 100644 src/views/register/index.vue diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbd04d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo +*.exe +/storage +/deploy +/.idea diff --git a/app/http/middleware/auth/middleware.go b/app/http/middleware/auth/middleware.go new file mode 100644 index 0000000..1fe7fd6 --- /dev/null +++ b/app/http/middleware/auth/middleware.go @@ -0,0 +1,52 @@ +package auth + +import ( + "bbs/app/provider/user" + "github.com/Superdanda/hade/framework/contract" + "github.com/Superdanda/hade/framework/gin" + "net/http" +) + +func AuthMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + envService := c.MustMake(contract.EnvKey).(contract.Env) + userService := c.MustMake(user.UserKey).(user.Service) + // 如果在调试模式下,根据参数的user_id 获取信息 + if envService.AppEnv() == contract.EnvDevelopment { + userID, exist := c.DefaultQueryInt64("user_id", 0) + if exist { + authUser, _ := userService.GetUser(c, userID) + if authUser != nil { + c.Set("auth_user", authUser) + c.Next() + return + } + } + } + + token, err := c.Cookie("hade_bbs") + if err != nil || token == "" { + c.ISetStatus(http.StatusUnauthorized).IText("请登录后操作") + return + } + + authUser, err := userService.VerifyLogin(c, token) + if err != nil || authUser == nil { + c.ISetStatus(http.StatusUnauthorized).IText("请登录后操作") + return + } + + c.Set("auth_user", authUser) + + c.Next() + } +} + +// GetAuthUser 获取已经验证的用户 +func GetAuthUser(c *gin.Context) *user.User { + t, exist := c.Get("auth_user") + if !exist { + return nil + } + return t.(*user.User) +} diff --git a/app/http/middleware/response/middleware.go b/app/http/middleware/response/middleware.go new file mode 100644 index 0000000..a72d660 --- /dev/null +++ b/app/http/middleware/response/middleware.go @@ -0,0 +1,13 @@ +package response + +import ( + "fmt" + "github.com/Superdanda/hade/framework/gin" +) + +func ResponseHandler() gin.HandlerFunc { + return func(c *gin.Context) { + c.Next() + fmt.Println("response handler") + } +} diff --git a/app/http/module/user/api.go b/app/http/module/user/api.go new file mode 100644 index 0000000..8259cd6 --- /dev/null +++ b/app/http/module/user/api.go @@ -0,0 +1,34 @@ +package user + +import ( + "bbs/app/http/middleware/auth" + "bbs/app/http/middleware/response" + "bbs/app/provider/user" + "github.com/Superdanda/hade/framework/gin" +) + +type UserApi struct{} + +// RegisterRoutes 注册路由 +func RegisterRoutes(r *gin.Engine) error { + api := &UserApi{} + + if !r.IsBind(user.UserKey) { + r.Bind(&user.UserProvider{}) + } + + userGroup := r.Group("/user") + userGroup.Use(response.ResponseHandler()) + { + // 登录 + userGroup.POST("/login", api.Login) + // 登出 + userGroup.GET("/logout", auth.AuthMiddleware(), api.Logout) + // 注册 + userGroup.POST("/register", api.Register) + // 注册验证 + userGroup.GET("/register/verify", api.Verify) + } + + return nil +} diff --git a/app/http/module/user/api_login.go b/app/http/module/user/api_login.go new file mode 100644 index 0000000..fa230cf --- /dev/null +++ b/app/http/module/user/api_login.go @@ -0,0 +1,45 @@ +package user + +import ( + "bbs/app/provider/user" + "github.com/Superdanda/hade/framework/gin" + "net/http" +) + +type loginParam struct { + UserName string `json:"username" binding:"required"` + Password string `json:"password" binding:"required,gte=6"` +} + +// Login 代表登录 +// @Summary 用户登录 +// @accept json +// @produce json +// @Tags user +// @Param loginParam body loginParam true "login with param" +// @Success 200 string Token "token" +// @Router /user/login [post] +func (api *UserApi) Login(c *gin.Context) { + userService := c.MustMake(user.UserKey).(user.Service) + param := &loginParam{} + if err := c.ShouldBind(param); err != nil { + c.ISetStatus(http.StatusBadRequest).IText("参数错误") + return + } + + // 登录 + model := &user.User{ + UserName: param.UserName, + Password: param.Password, + } + + userWithToken, err := userService.Login(c, model) + if err != nil { + c.ISetStatus(http.StatusInternalServerError).IText(err.Error()) + return + } + + // 输出 + c.ISetOkStatus().IText(userWithToken.Token) + return +} diff --git a/app/http/module/user/api_logout.go b/app/http/module/user/api_logout.go new file mode 100644 index 0000000..c3968dd --- /dev/null +++ b/app/http/module/user/api_logout.go @@ -0,0 +1,32 @@ +package user + +import ( + "bbs/app/http/middleware/auth" + "bbs/app/provider/user" + "github.com/Superdanda/hade/framework/gin" +) + +// Logout 代表登出 +// @Summary 用户登出 +// @Description 调用表示用户登出 +// @Accept json +// @Produce json +// @Tags user +// @Success 200 {string} Message "用户登出成功" +// @Router /user/logout [get] +func (api *UserApi) Logout(c *gin.Context) { + authUser := auth.GetAuthUser(c) + if authUser == nil { + c.ISetStatus(500).IText("用户未登录") + return + } + + userService := c.MustMake(user.UserKey).(user.Service) + if err := userService.Logout(c, authUser); err != nil { + c.ISetStatus(500).IText(err.Error()) + return + } + //c.ISetOkStatus().IText("用户登出成功") + c.IRedirect("/#/login") + return +} diff --git a/app/http/module/user/api_register.go b/app/http/module/user/api_register.go new file mode 100644 index 0000000..a84e298 --- /dev/null +++ b/app/http/module/user/api_register.go @@ -0,0 +1,66 @@ +package user + +import ( + "bbs/app/provider/user" + "fmt" + "github.com/Superdanda/hade/framework/contract" + "github.com/Superdanda/hade/framework/gin" + "time" +) + +type registerParam struct { + UserName string `json:"username" binding:"required"` + Password string `json:"password" binding:"required,gte=6"` + Email string `json:"email" binding:"required,gte=6"` +} + +// Register 注册 +// @Summary 用户注册 +// @Description 用户注册接口 +// @Accept json +// @Produce json +// @Tags user +// @Param registerParam body registerParam true "注册参数" +// @Success 200 string Message "注册成功" +// @Router /user/register [post] +func (api *UserApi) Register(c *gin.Context) { + // 验证参数 + userService := c.MustMake(user.UserKey).(user.Service) + logger := c.MustMake(contract.LogKey).(contract.Log) + + param := ®isterParam{} + if err := c.ShouldBind(param); err != nil { + c.ISetStatus(400).IText("参数错误 ") + return + } + + // 登录 + model := &user.User{ + UserName: param.UserName, + Password: param.Password, + Email: param.Email, + CreatedAt: time.Now(), + } + // 注册 + userWithToken, err := userService.Register(c, model) + if err != nil { + logger.Error(c, err.Error(), map[string]interface{}{ + "stack": fmt.Sprintf("%+v", err), + }) + c.ISetStatus(500).IText(err.Error()) + return + } + if userWithToken == nil { + c.ISetStatus(500).IText("注册失败") + return + } + + if err := userService.SendRegisterMail(c, userWithToken); err != nil { + + c.ISetStatus(500).IText("发送电子邮件失败") + return + } + + c.ISetOkStatus().IText("注册成功,请前往邮箱查看邮件") + return +} diff --git a/app/http/module/user/api_verify.go b/app/http/module/user/api_verify.go new file mode 100644 index 0000000..4184de6 --- /dev/null +++ b/app/http/module/user/api_verify.go @@ -0,0 +1,39 @@ +package user + +import ( + "bbs/app/provider/user" + "github.com/Superdanda/hade/framework/gin" +) + +// Verify 代表验证注册信息 +// @Summary 验证注册信息 +// @Description 使用token验证用户注册信息 +// @Accept json +// @Produce json +// @Tags user +// @Param token query string true "注册token" +// @Success 200 {string} Message "注册成功,请进入登录页面" +// @Router /user/register/verify [get] +func (api *UserApi) Verify(c *gin.Context) { + // 验证参数 + userService := c.MustMake(user.UserKey).(user.Service) + token := c.Query("token") + if token == "" { + c.ISetStatus(400).IText("参数错误") + return + } + + verified, err := userService.VerifyRegister(c, token) + if err != nil { + c.ISetStatus(500).IText(err.Error()) + return + } + + if !verified { + c.ISetStatus(500).IText("验证错误") + return + } + + // 输出 + c.IRedirect("/#/login").IText("注册成功,请进入登录页面") +} diff --git a/app/http/module/user/dto.go b/app/http/module/user/dto.go new file mode 100644 index 0000000..0a67db5 --- /dev/null +++ b/app/http/module/user/dto.go @@ -0,0 +1,10 @@ +package user + +import "time" + +// UserDTO 表示输出到外部的用户信息 +type UserDTO struct { + ID int64 `json:"id,omitempty"` + UserName string `json:"user_name,omitempty"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/app/http/module/user/mapper.go b/app/http/module/user/mapper.go new file mode 100644 index 0000000..a60a3e4 --- /dev/null +++ b/app/http/module/user/mapper.go @@ -0,0 +1,15 @@ +package user + +import "bbs/app/provider/user" + +// ConvertUserToDTO 将user转换为UserDTO +func ConvertUserToDTO(user *user.User) *UserDTO { + if user == nil { + return nil + } + return &UserDTO{ + ID: user.ID, + UserName: user.UserName, + CreatedAt: user.CreatedAt, + } +} diff --git a/app/http/route.go b/app/http/route.go index 47ccc16..032bb29 100644 --- a/app/http/route.go +++ b/app/http/route.go @@ -2,6 +2,7 @@ package http import ( "bbs/app/http/module/demo" + "bbs/app/http/module/user" "github.com/Superdanda/hade/framework/contract" "github.com/Superdanda/hade/framework/gin" ginSwagger "github.com/Superdanda/hade/framework/middleware/gin-swagger" @@ -22,6 +23,9 @@ func Routes(core *gin.Engine) { core.Use(static.Serve("/", static.LocalFile("./dist", false))) err := demo.Register(core) + + err = user.RegisterRoutes(core) + if err != nil { return } diff --git a/app/http/swagger/docs.go b/app/http/swagger/docs.go index 05c5dc9..2d3b4b4 100644 --- a/app/http/swagger/docs.go +++ b/app/http/swagger/docs.go @@ -70,6 +70,128 @@ const docTemplate = `{ } } } + }, + "/user/login": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "login with param", + "name": "loginParam", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/user.loginParam" + } + } + ], + "responses": { + "200": { + "description": "token", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/logout": { + "get": { + "description": "调用表示用户登出", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "用户登出成功", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/register": { + "post": { + "description": "用户注册接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户注册", + "parameters": [ + { + "description": "注册参数", + "name": "registerParam", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/user.registerParam" + } + } + ], + "responses": { + "200": { + "description": "注册成功", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/register/verify": { + "get": { + "description": "使用token验证用户注册信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "验证注册信息", + "parameters": [ + { + "type": "string", + "description": "注册token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "注册成功,请进入登录页面", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { @@ -83,6 +205,43 @@ const docTemplate = `{ "type": "string" } } + }, + "user.loginParam": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "type": "string", + "minLength": 6 + }, + "username": { + "type": "string" + } + } + }, + "user.registerParam": { + "type": "object", + "required": [ + "email", + "password", + "username" + ], + "properties": { + "email": { + "type": "string", + "minLength": 6 + }, + "password": { + "type": "string", + "minLength": 6 + }, + "username": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/app/http/swagger/swagger.json b/app/http/swagger/swagger.json index 49fd507..f81c417 100644 --- a/app/http/swagger/swagger.json +++ b/app/http/swagger/swagger.json @@ -63,6 +63,128 @@ } } } + }, + "/user/login": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "login with param", + "name": "loginParam", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/user.loginParam" + } + } + ], + "responses": { + "200": { + "description": "token", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/logout": { + "get": { + "description": "调用表示用户登出", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "用户登出成功", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/register": { + "post": { + "description": "用户注册接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "用户注册", + "parameters": [ + { + "description": "注册参数", + "name": "registerParam", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/user.registerParam" + } + } + ], + "responses": { + "200": { + "description": "注册成功", + "schema": { + "type": "string" + } + } + } + } + }, + "/user/register/verify": { + "get": { + "description": "使用token验证用户注册信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "验证注册信息", + "parameters": [ + { + "type": "string", + "description": "注册token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "注册成功,请进入登录页面", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { @@ -76,6 +198,43 @@ "type": "string" } } + }, + "user.loginParam": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "type": "string", + "minLength": 6 + }, + "username": { + "type": "string" + } + } + }, + "user.registerParam": { + "type": "object", + "required": [ + "email", + "password", + "username" + ], + "properties": { + "email": { + "type": "string", + "minLength": 6 + }, + "password": { + "type": "string", + "minLength": 6 + }, + "username": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/app/http/swagger/swagger.yaml b/app/http/swagger/swagger.yaml index adaf575..9fa7424 100644 --- a/app/http/swagger/swagger.yaml +++ b/app/http/swagger/swagger.yaml @@ -7,6 +7,32 @@ definitions: name: type: string type: object + user.loginParam: + properties: + password: + minLength: 6 + type: string + username: + type: string + required: + - password + - username + type: object + user.registerParam: + properties: + email: + minLength: 6 + type: string + password: + minLength: 6 + type: string + username: + type: string + required: + - email + - password + - username + type: object info: contact: email: yejianfeng @@ -50,6 +76,85 @@ paths: summary: 获取所有学生 tags: - demo + /user/login: + post: + consumes: + - application/json + parameters: + - description: login with param + in: body + name: loginParam + required: true + schema: + $ref: '#/definitions/user.loginParam' + produces: + - application/json + responses: + "200": + description: token + schema: + type: string + summary: 用户登录 + tags: + - user + /user/logout: + get: + consumes: + - application/json + description: 调用表示用户登出 + produces: + - application/json + responses: + "200": + description: 用户登出成功 + schema: + type: string + summary: 用户登出 + tags: + - user + /user/register: + post: + consumes: + - application/json + description: 用户注册接口 + parameters: + - description: 注册参数 + in: body + name: registerParam + required: true + schema: + $ref: '#/definitions/user.registerParam' + produces: + - application/json + responses: + "200": + description: 注册成功 + schema: + type: string + summary: 用户注册 + tags: + - user + /user/register/verify: + get: + consumes: + - application/json + description: 使用token验证用户注册信息 + parameters: + - description: 注册token + in: query + name: token + required: true + type: string + produces: + - application/json + responses: + "200": + description: 注册成功,请进入登录页面 + schema: + type: string + summary: 验证注册信息 + tags: + - user securityDefinitions: ApiKeyAuth: in: header diff --git a/app/provider/user/contract.go b/app/provider/user/contract.go deleted file mode 100644 index 4c2f650..0000000 --- a/app/provider/user/contract.go +++ /dev/null @@ -1,8 +0,0 @@ -package user - -const UserKey = "user" - -type Service interface { - // 请在这里定义你的方法 - Foo() string -} diff --git a/app/provider/user/provider.go b/app/provider/user/provider.go deleted file mode 100644 index 5aca166..0000000 --- a/app/provider/user/provider.go +++ /dev/null @@ -1,31 +0,0 @@ -package user - -import ( - "github.com/Superdanda/hade/framework" -) - -type UserProvider struct { - framework.ServiceProvider - - c framework.Container -} - -func (sp *UserProvider) Name() string { - return UserKey -} - -func (sp *UserProvider) Register(c framework.Container) framework.NewInstance { - return NewUserService -} - -func (sp *UserProvider) IsDefer() bool { - return false -} - -func (sp *UserProvider) Params(c framework.Container) []interface{} { - return []interface{}{c} -} - -func (sp *UserProvider) Boot(c framework.Container) error { - return nil -} diff --git a/app/provider/user/service.go b/app/provider/user/service.go deleted file mode 100644 index cb4c62c..0000000 --- a/app/provider/user/service.go +++ /dev/null @@ -1,16 +0,0 @@ -package user - -import "github.com/Superdanda/hade/framework" - -type UserService struct { - container framework.Container -} - -func NewUserService(params ...interface{}) (interface{}, error) { - container := params[0].(framework.Container) - return &UserService{container: container}, nil -} - -func (s *UserService) Foo() string { - return "" -} diff --git a/config/development/app.yaml b/config/development/app.yaml index 7e7b3e5..eb6f06f 100644 --- a/config/development/app.yaml +++ b/config/development/app.yaml @@ -15,4 +15,12 @@ dev: # 调试模式 port: 8890 # 后端监听端口,默认8072 monitor_folder: "" # 监听文件夹地址,为空或者不填默认为AppFolder frontend: # 前端调试模式配置 - port: 8889 # 前端监听端口, 默认8071 \ No newline at end of file + port: 8889 # 前端监听端口, 默认8071 + + +smtp: + host: "smtp.126.com" + port: 25 + from: "superdanda@126.com" + username: "superdanda" + password: "A10337191315." diff --git a/config/development/database.yaml b/config/development/database.yaml index cf0d39b..ec29ade 100644 --- a/config/development/database.yaml +++ b/config/development/database.yaml @@ -1,23 +1,22 @@ conn_max_idle: 10 # 通用配置,连接池最大空闲连接数 conn_max_open: 100 # 通用配置,连接池最大连接数 conn_max_lifetime: 1h # 通用配置,连接数最大生命周期 -protocol: tcp # 通用配置,传输协议 -loc: Local # 通用配置,时区 -default: - driver: mysql # 连接驱动 - dsn: "" # dsn,如果设置了dsn, 以下的所有设置都不生效 - host: 47.97.21.20 # ip地址 - port: 3306 # 端口 - database: questionnaire # 数据库 - username: root # 用户名 - password: "kerowsqw34" # 密码 - charset: utf8mb4 # 字符集 - collation: utf8mb4_unicode_ci # 字符序 - timeout: 10s # 连接超时 - read_timeout: 2s # 读超时 - write_timeout: 2s # 写超时 - parse_time: true # 是否解析时间 - protocol: tcp # 传输协议 - loc: Local # 时区 + +driver: mysql # 连接驱动 +dsn: "" # dsn,如果设置了dsn, 以下的所有设置都不生效 +host: 47.97.21.20 # ip地址 +port: 3306 # 端口 +database: questionnaire # 数据库 +username: root # 用户名 +password: "kerowsqw34" # 密码 +charset: utf8mb4 # 字符集 +collation: utf8mb4_unicode_ci # 字符序 +timeout: 10s # 连接超时 +read_timeout: 2s # 读超时 +write_timeout: 2s # 写超时 +parse_time: true # 是否解析时间 +protocol: tcp # 传输协议 +loc: Local # 时区 + diff --git a/go.mod b/go.mod index c287034..7e0f308 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module bbs go 1.23.2 require ( - github.com/Superdanda/hade v1.0.2 + github.com/Superdanda/hade v1.0.4 github.com/swaggo/swag v1.16.4 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) require ( @@ -21,7 +22,7 @@ require ( github.com/robfig/cron/v3 v3.0.0 // indirect github.com/sevlyar/go-daemon v0.1.6 // indirect github.com/spf13/cast v1.7.0 // indirect - gorm.io/gorm v1.25.12 // indirect + gorm.io/gorm v1.25.12 ) require ( @@ -87,6 +88,7 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/term v0.25.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/clickhouse v0.6.1 // indirect @@ -126,7 +128,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.28.0 // indirect + golang.org/x/crypto v0.28.0 golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect ) diff --git a/go.sum b/go.sum index 2d36aaf..39cda03 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/Superdanda/hade v1.0.2 h1:AxlYNeUVO90j+LUHiZW6rg36DbGIXi6gUopURGVMzio= -github.com/Superdanda/hade v1.0.2/go.mod h1:z52uXdtEfX25FRCj7YeQOctw6fho9nIaIWc/picNhuA= +github.com/Superdanda/hade v1.0.4 h1:NFsH8BBbsHmbedkGHdpjGk3e49GEJtRWU4ENOxp0sfU= +github.com/Superdanda/hade v1.0.4/go.mod h1:z52uXdtEfX25FRCj7YeQOctw6fho9nIaIWc/picNhuA= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -443,11 +443,15 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/package.json b/package.json index c4938b2..3b4b439 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ }, "dependencies": { "element-ui": "^2.3.4", - "vue": "^2.5.16" + "vue": "^2.5.16", + "vue-router": "^3.5.3", + "vue-style-loader": "^4.1.3", + "vuex": "^3.6.2", + "axios": "^0.24.0", + "js-cookie": "^3.0.1" }, "engines": { "node": ">=6" diff --git a/src/App.vue b/src/App.vue index fec87a6..c314e47 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,23 +1,15 @@ diff --git a/src/main.js b/src/main.js index 80f18a4..9d6de5f 100644 --- a/src/main.js +++ b/src/main.js @@ -2,10 +2,14 @@ import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import App from './App.vue' +import store from './store' +import router from './router/index.js' Vue.use(ElementUI) new Vue({ el: '#app', + router: router, + store: store, render: h => h(App) }) diff --git a/src/views/404.vue b/src/views/404.vue new file mode 100644 index 0000000..62db721 --- /dev/null +++ b/src/views/404.vue @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/views/layout/container.vue b/src/views/layout/container.vue new file mode 100644 index 0000000..024d391 --- /dev/null +++ b/src/views/layout/container.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/src/views/layout/header.vue b/src/views/layout/header.vue new file mode 100644 index 0000000..06be2b9 --- /dev/null +++ b/src/views/layout/header.vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..03d07b1 --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,94 @@ + + + + + \ No newline at end of file diff --git a/src/views/register/index.vue b/src/views/register/index.vue new file mode 100644 index 0000000..c75dc87 --- /dev/null +++ b/src/views/register/index.vue @@ -0,0 +1,100 @@ + + + + + \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 41447d4..1866bfb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -50,16 +50,16 @@ module.exports = (options = {}) => ({ ], resolve: { alias: { - '~': resolve(__dirname, 'src') + '@': resolve(__dirname, 'src') }, extensions: ['.js', '.vue', '.json', '.css'] }, devServer: { host: '127.0.0.1', - port: 8010, + port: 8890, proxy: { '/api/': { - target: 'http://127.0.0.1:8080', + target: 'http://127.0.0.1:8890', changeOrigin: true, pathRewrite: { '^/api': '' diff --git a/yarn.lock b/yarn.lock index 15a3e88..690874a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -170,6 +170,13 @@ autoprefixer@^6.3.1, autoprefixer@^6.6.0: postcss "^5.2.16" postcss-value-parser "^3.2.3" +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.npmmirror.com/axios/-/axios-0.24.0.tgz" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + babel-code-frame@^6.11.0, babel-code-frame@^6.22.0: version "6.22.0" resolved "http://registry.npm.taobao.org/babel-code-frame/download/babel-code-frame-6.22.0.tgz" @@ -1742,6 +1749,11 @@ flatten@^1.0.2: resolved "http://registry.npm.taobao.org/flatten/download/flatten-1.0.2.tgz" integrity sha512-6u/bzbUK+6iOENlqGFkl94EqdAL/FVRhxMWbAE0OBmRsBl64BESxvVRD3CWdilAeka/3WlEZP+0MrKvtYpYFQQ== +follow-redirects@^1.14.4: + version "1.15.9" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-in@^1.0.1: version "1.0.2" resolved "http://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz" @@ -2207,6 +2219,11 @@ js-base64@^2.1.9: resolved "http://registry.npm.taobao.org/js-base64/download/js-base64-2.1.9.tgz" integrity sha512-f+5mYh8iF7FlF7zgmj/yqvvYQUHI0kAxGiLjIfNxZzqJ7RQNc4sjgp8crVJw0Kzv2O6aFGZWgMTnO71I9utHSg== +js-cookie@^3.0.1: + version "3.0.5" + resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz" + integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw== + js-tokens@^3.0.0: version "3.0.1" resolved "http://registry.npm.taobao.org/js-tokens/download/js-tokens-3.0.1.tgz" @@ -2310,16 +2327,7 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.2: - version "1.1.0" - resolved "http://registry.npm.taobao.org/loader-utils/download/loader-utils-1.1.0.tgz" - integrity sha512-gkD9aSEG9UGglyPcDJqY9YBTUtCLKaBK6ihD2VP1d1X60lTfFspNZNulGBBbUZLkPygy4LySYHyxBpq+VhjObQ== - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - -loader-utils@^1.1.0: +loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "http://registry.npm.taobao.org/loader-utils/download/loader-utils-1.1.0.tgz" integrity sha512-gkD9aSEG9UGglyPcDJqY9YBTUtCLKaBK6ihD2VP1d1X60lTfFspNZNulGBBbUZLkPygy4LySYHyxBpq+VhjObQ== @@ -4000,10 +4008,23 @@ vue-loader@^13.3.0: vue-style-loader "^3.0.0" vue-template-es2015-compiler "^1.6.0" +vue-router@^3.5.3: + version "3.6.5" + resolved "https://registry.npmmirror.com/vue-router/-/vue-router-3.6.5.tgz" + integrity sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ== + vue-style-loader@^3.0.0: - version "3.0.1" - resolved "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-3.0.1.tgz" - integrity sha512-SjeCPpS6yWZwBOXsjayw8F2rqtFmjgmRsSMJQOTBZmaJVt1c+vLN6dBppeiIiQ4BGahYGiBvLfbCBoiKMoxJAQ== + version "3.1.2" + resolved "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-3.1.2.tgz" + integrity sha512-ICtVdK/p+qXWpdSs2alWtsXt9YnDoYjQe0w5616j9+/EhjoxZkbun34uWgsMFnC1MhrMMwaWiImz3K2jK1Yp2Q== + dependencies: + hash-sum "^1.0.2" + loader-utils "^1.0.2" + +vue-style-loader@^4.1.3: + version "4.1.3" + resolved "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz" + integrity sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg== dependencies: hash-sum "^1.0.2" loader-utils "^1.0.2" @@ -4021,11 +4042,16 @@ vue-template-es2015-compiler@^1.6.0: resolved "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz" integrity sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg== -vue@^2.5.16, vue@^2.5.2: +vue@^2.0.0, vue@^2.5.16, vue@^2.5.2: version "2.5.16" resolved "https://registry.npmmirror.com/vue/-/vue-2.5.16.tgz" integrity sha512-/ffmsiVuPC8PsWcFkZngdpas19ABm5mh2wA7iDqcltyCTwlgZjHGeJYOXkBMo422iPwIcviOtrTCUpSfXmToLQ== +vuex@^3.6.2: + version "3.6.2" + resolved "https://registry.npmmirror.com/vuex/-/vuex-3.6.2.tgz" + integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw== + watchpack@^1.3.1: version "1.3.1" resolved "http://registry.npm.taobao.org/watchpack/download/watchpack-1.3.1.tgz"