2 Commits
a7e8fab444
...
9c53f8a0a5
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
9c53f8a0a5 |
Merge branch 'zhouxinzhong/feature-20260327150147-学习笔记' into milestone-20260325-学习笔记
|
2 weeks ago |
|
|
17957b228e |
4.1提交笔记和代码
|
2 weeks ago |
96 changed files with 10335 additions and 0 deletions
-
1周新忠学习笔记/4.1/gf_demo_02/.gitattributes
-
19周新忠学习笔记/4.1/gf_demo_02/.gitignore
-
7周新忠学习笔记/4.1/gf_demo_02/Makefile
-
6周新忠学习笔记/4.1/gf_demo_02/README.MD
-
57周新忠学习笔记/4.1/gf_demo_02/api/user/v1/user.go
-
38周新忠学习笔记/4.1/gf_demo_02/go.mod
-
70周新忠学习笔记/4.1/gf_demo_02/go.sum
-
13周新忠学习笔记/4.1/gf_demo_02/hack/config.yaml
-
20周新忠学习笔记/4.1/gf_demo_02/hack/hack-cli.mk
-
75周新忠学习笔记/4.1/gf_demo_02/hack/hack.mk
-
30周新忠学习笔记/4.1/gf_demo_02/internal/cmd/cmd.go
-
3周新忠学习笔记/4.1/gf_demo_02/internal/consts/consts.go
-
98周新忠学习笔记/4.1/gf_demo_02/internal/controller/user/user.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/dao/.gitkeep
-
27周新忠学习笔记/4.1/gf_demo_02/internal/dao/course.go
-
83周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/course.go
-
83周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/stock.go
-
85周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user.go
-
75周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user_course.go
-
27周新忠学习笔记/4.1/gf_demo_02/internal/dao/stock.go
-
27周新忠学习笔记/4.1/gf_demo_02/internal/dao/user.go
-
27周新忠学习笔记/4.1/gf_demo_02/internal/dao/user_course.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/logic/.gitkeep
-
12周新忠学习笔记/4.1/gf_demo_02/internal/logic/course/course.go
-
9周新忠学习笔记/4.1/gf_demo_02/internal/logic/logic.go
-
143周新忠学习笔记/4.1/gf_demo_02/internal/logic/user/user.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/model/.gitkeep
-
9周新忠学习笔记/4.1/gf_demo_02/internal/model/claim.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/model/do/.gitkeep
-
21周新忠学习笔记/4.1/gf_demo_02/internal/model/do/course.go
-
21周新忠学习笔记/4.1/gf_demo_02/internal/model/do/stock.go
-
22周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user.go
-
16周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user_course.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/.gitkeep
-
19周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/course.go
-
19周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/stock.go
-
20周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user.go
-
11周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user_course.go
-
16周新忠学习笔记/4.1/gf_demo_02/internal/model/models.go
-
1周新忠学习笔记/4.1/gf_demo_02/internal/packed/packed.go
-
0周新忠学习笔记/4.1/gf_demo_02/internal/service/.gitkeep
-
65周新忠学习笔记/4.1/gf_demo_02/internal/service/JWTMiddleware.go
-
21周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass.go
-
7周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass_test.go
-
40周新忠学习笔记/4.1/gf_demo_02/internal/service/user.go
-
BIN周新忠学习笔记/4.1/gf_demo_02/main.exe~
-
17周新忠学习笔记/4.1/gf_demo_02/main.go
-
21周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/deployment.yaml
-
8周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/kustomization.yaml
-
12周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/service.yaml
-
14周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/configmap.yaml
-
10周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/deployment.yaml
-
14周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/kustomization.yaml
-
16周新忠学习笔记/4.1/gf_demo_02/manifest/docker/Dockerfile
-
8周新忠学习笔记/4.1/gf_demo_02/manifest/docker/docker.sh
-
0周新忠学习笔记/4.1/gf_demo_02/manifest/i18n/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/manifest/protobuf/.keep-if-necessary
-
0周新忠学习笔记/4.1/gf_demo_02/resource/public/html/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/resource/public/plugin/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/css/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/image/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/js/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/resource/template/.gitkeep
-
0周新忠学习笔记/4.1/gf_demo_02/utility/.gitkeep
-
8周新忠学习笔记/4.1/vue_prj/.editorconfig
-
1周新忠学习笔记/4.1/vue_prj/.gitattributes
-
42周新忠学习笔记/4.1/vue_prj/.gitignore
-
10周新忠学习笔记/4.1/vue_prj/.oxlintrc.json
-
6周新忠学习笔记/4.1/vue_prj/.prettierrc.json
-
11周新忠学习笔记/4.1/vue_prj/.vscode/extensions.json
-
73周新忠学习笔记/4.1/vue_prj/README.md
-
4周新忠学习笔记/4.1/vue_prj/e2e/tsconfig.json
-
8周新忠学习笔记/4.1/vue_prj/e2e/vue.spec.ts
-
1周新忠学习笔记/4.1/vue_prj/env.d.ts
-
38周新忠学习笔记/4.1/vue_prj/eslint.config.ts
-
13周新忠学习笔记/4.1/vue_prj/index.html
-
7739周新忠学习笔记/4.1/vue_prj/package-lock.json
-
60周新忠学习笔记/4.1/vue_prj/package.json
-
110周新忠学习笔记/4.1/vue_prj/playwright.config.ts
-
BIN周新忠学习笔记/4.1/vue_prj/public/favicon.ico
-
3周新忠学习笔记/4.1/vue_prj/src/App.vue
-
11周新忠学习笔记/4.1/vue_prj/src/__tests__/App.spec.ts
-
32周新忠学习笔记/4.1/vue_prj/src/api/service.ts
-
156周新忠学习笔记/4.1/vue_prj/src/components/Home.vue
-
116周新忠学习笔记/4.1/vue_prj/src/components/LoginPage.vue
-
193周新忠学习笔记/4.1/vue_prj/src/components/User.vue
-
21周新忠学习笔记/4.1/vue_prj/src/main.ts
-
20周新忠学习笔记/4.1/vue_prj/src/router/index.ts
-
12周新忠学习笔记/4.1/vue_prj/src/stores/counter.ts
-
18周新忠学习笔记/4.1/vue_prj/tsconfig.app.json
-
14周新忠学习笔记/4.1/vue_prj/tsconfig.json
-
27周新忠学习笔记/4.1/vue_prj/tsconfig.node.json
-
19周新忠学习笔记/4.1/vue_prj/tsconfig.vitest.json
-
29周新忠学习笔记/4.1/vue_prj/vite.config.ts
-
14周新忠学习笔记/4.1/vue_prj/vitest.config.ts
-
63周新忠学习笔记/4.1/周新忠4月1日学习笔记.md
@ -0,0 +1 @@ |
|||
* linguist-language=GO |
|||
@ -0,0 +1,19 @@ |
|||
.buildpath |
|||
.hgignore.swp |
|||
.project |
|||
.orig |
|||
.swp |
|||
.idea/ |
|||
.settings/ |
|||
.vscode/ |
|||
bin/ |
|||
**/.DS_Store |
|||
gf |
|||
main |
|||
main.exe |
|||
output/ |
|||
manifest/output/ |
|||
temp/ |
|||
temp.yaml |
|||
bin |
|||
**/config/config.yaml |
|||
@ -0,0 +1,7 @@ |
|||
ROOT_DIR = $(shell pwd) |
|||
NAMESPACE = "default" |
|||
DEPLOY_NAME = "template-single" |
|||
DOCKER_NAME = "template-single" |
|||
|
|||
include ./hack/hack-cli.mk |
|||
include ./hack/hack.mk |
|||
@ -0,0 +1,6 @@ |
|||
# GoFrame Template For SingleRepo |
|||
|
|||
Quick Start: |
|||
- https://goframe.org/quick |
|||
|
|||
没做规范化处理目前!! |
|||
@ -0,0 +1,57 @@ |
|||
package user |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/model/entity" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
type LoginReq struct { |
|||
g.Meta `path:"/login" method:"post"` |
|||
Username string |
|||
Password string |
|||
} |
|||
|
|||
type LoginRes struct { |
|||
Token string `json:"token"` //token加签后的字符串
|
|||
} |
|||
|
|||
type GetUserListReq struct { |
|||
g.Meta `path:"/getUsers" method:"get"` |
|||
} |
|||
|
|||
type GetUserListRes struct { |
|||
Users []entity.User `json:"users"` |
|||
} |
|||
|
|||
type EditUserReq struct { |
|||
g.Meta `path:"/admin/user/editUser" method:"post"` |
|||
Id uint `json:"id"` |
|||
Name string `json:"name" v:"required"` |
|||
Property uint `json:"property" v:"between:1,5 #权限必须为1-5"` |
|||
Pass string `json:"pass"` |
|||
} |
|||
|
|||
type EditUserRes struct { |
|||
} |
|||
|
|||
type DeleteUserReq struct { |
|||
g.Meta `path:"/admin/user/delete" method:"delete"` |
|||
Id uint `json:"id" v:"required#缺少用户id"` |
|||
} |
|||
type DeleteUserRes struct{} |
|||
|
|||
type GetSelfReq struct { |
|||
g.Meta `path:"/admin/user/getSelf" method:"get"` |
|||
} |
|||
type GetSelfRes struct { |
|||
User entity.User `json:"user"` |
|||
} |
|||
|
|||
type SearchUserReq struct { |
|||
g.Meta `path:"/admin/user/search" method:"get"` |
|||
Keyword string `json:"keyword" p:"keyword"` |
|||
} |
|||
|
|||
type SearchUserRes struct { |
|||
Users []entity.User `json:"users"` |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
module gf_demo_02 |
|||
|
|||
go 1.21 |
|||
|
|||
toolchain go1.21.13 |
|||
|
|||
require ( |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible |
|||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.0 |
|||
github.com/gogf/gf/v2 v2.7.0 |
|||
github.com/golang-jwt/jwt/v5 v5.3.1 |
|||
golang.org/x/crypto v0.21.0 |
|||
) |
|||
|
|||
require ( |
|||
github.com/BurntSushi/toml v1.3.2 // indirect |
|||
github.com/clbanning/mxj/v2 v2.7.0 // indirect |
|||
github.com/fatih/color v1.16.0 // indirect |
|||
github.com/fsnotify/fsnotify v1.7.0 // indirect |
|||
github.com/go-logr/logr v1.2.4 // indirect |
|||
github.com/go-logr/stdr v1.2.2 // indirect |
|||
github.com/go-sql-driver/mysql v1.7.1 // indirect |
|||
github.com/gorilla/websocket v1.5.1 // indirect |
|||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect |
|||
github.com/magiconair/properties v1.8.7 // indirect |
|||
github.com/mattn/go-colorable v0.1.13 // indirect |
|||
github.com/mattn/go-isatty v0.0.20 // indirect |
|||
github.com/mattn/go-runewidth v0.0.15 // indirect |
|||
github.com/olekukonko/tablewriter v0.0.5 // indirect |
|||
github.com/rivo/uniseg v0.4.4 // indirect |
|||
go.opentelemetry.io/otel v1.14.0 // indirect |
|||
go.opentelemetry.io/otel/sdk v1.14.0 // indirect |
|||
go.opentelemetry.io/otel/trace v1.14.0 // indirect |
|||
golang.org/x/net v0.23.0 // indirect |
|||
golang.org/x/sys v0.19.0 // indirect |
|||
golang.org/x/text v0.14.0 // indirect |
|||
gopkg.in/yaml.v3 v3.0.1 // indirect |
|||
) |
|||
@ -0,0 +1,70 @@ |
|||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= |
|||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= |
|||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= |
|||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= |
|||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= |
|||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= |
|||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= |
|||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= |
|||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= |
|||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= |
|||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= |
|||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= |
|||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= |
|||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= |
|||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= |
|||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.0 h1:5Igvtz4gy5UMvH+Ut4kLIpwSzggV9ZgDVBsIiOctH5E= |
|||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.0/go.mod h1:0+flZ0clMKjtH1sTI7YD2KG4FPr8xz0L9h1WMd5M2Z8= |
|||
github.com/gogf/gf/v2 v2.7.0 h1:CjxhbMiE7oqf6K8ZtGuKt3dQEwK4vL6LhiI+dI7tJGU= |
|||
github.com/gogf/gf/v2 v2.7.0/go.mod h1:Qu8nimKt9aupJQcdUL85tWF4Mfxocz97zUt8UC4abVI= |
|||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= |
|||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= |
|||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= |
|||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= |
|||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= |
|||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= |
|||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= |
|||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= |
|||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= |
|||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= |
|||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= |
|||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= |
|||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= |
|||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= |
|||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= |
|||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= |
|||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= |
|||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= |
|||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= |
|||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= |
|||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= |
|||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= |
|||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= |
|||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= |
|||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= |
|||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= |
|||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= |
|||
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= |
|||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= |
|||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= |
|||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= |
|||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= |
|||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= |
|||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= |
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
|||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= |
|||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
|||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= |
|||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
@ -0,0 +1,13 @@ |
|||
|
|||
# CLI tool, only in development environment. |
|||
# https://goframe.org/docs/cli |
|||
gfcli: |
|||
gen: |
|||
dao: |
|||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" |
|||
descriptionTag: true |
|||
|
|||
docker: |
|||
build: "-a amd64 -s linux -p temp -ew" |
|||
tagPrefixes: |
|||
- my.image.pub/my-app |
|||
@ -0,0 +1,20 @@ |
|||
|
|||
# Install/Update to the latest CLI tool.
|
|||
.PHONY: cli |
|||
cli: |
|||
@set -e; \
|
|||
wget -O gf \
|
|||
https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \
|
|||
chmod +x gf && \
|
|||
./gf install -y && \
|
|||
rm ./gf |
|||
|
|||
|
|||
# Check and install CLI tool.
|
|||
.PHONY: cli.install |
|||
cli.install: |
|||
@set -e; \
|
|||
gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \
|
|||
echo "GoFame CLI is not installed, start proceeding auto installation..."; \
|
|||
make cli; \
|
|||
fi; |
|||
@ -0,0 +1,75 @@ |
|||
.DEFAULT_GOAL := build |
|||
|
|||
# Update GoFrame and its CLI to latest stable version.
|
|||
.PHONY: up |
|||
up: cli.install |
|||
@gf up -a |
|||
|
|||
# Build binary using configuration from hack/config.yaml.
|
|||
.PHONY: build |
|||
build: cli.install |
|||
@gf build -ew |
|||
|
|||
# Parse api and generate controller/sdk.
|
|||
.PHONY: ctrl |
|||
ctrl: cli.install |
|||
@gf gen ctrl |
|||
|
|||
# Generate Go files for DAO/DO/Entity.
|
|||
.PHONY: dao |
|||
dao: cli.install |
|||
@gf gen dao |
|||
|
|||
# Parse current project go files and generate enums go file.
|
|||
.PHONY: enums |
|||
enums: cli.install |
|||
@gf gen enums |
|||
|
|||
# Generate Go files for Service.
|
|||
.PHONY: service |
|||
service: cli.install |
|||
@gf gen service |
|||
|
|||
|
|||
# Build docker image.
|
|||
.PHONY: image |
|||
image: cli.install |
|||
$(eval _TAG = $(shell git rev-parse --short HEAD)) |
|||
ifneq (, $(shell git status --porcelain 2>/dev/null)) |
|||
$(eval _TAG = $(_TAG).dirty) |
|||
endif |
|||
$(eval _TAG = $(if ${TAG}, ${TAG}, $(_TAG))) |
|||
$(eval _PUSH = $(if ${PUSH}, ${PUSH}, )) |
|||
@gf docker ${_PUSH} -tn $(DOCKER_NAME):${_TAG}; |
|||
|
|||
|
|||
# Build docker image and automatically push to docker repo.
|
|||
.PHONY: image.push |
|||
image.push: cli.install |
|||
@make image PUSH=-p; |
|||
|
|||
|
|||
# Deploy image and yaml to current kubectl environment.
|
|||
.PHONY: deploy |
|||
deploy: cli.install |
|||
$(eval _TAG = $(if ${TAG}, ${TAG}, develop)) |
|||
|
|||
@set -e; \
|
|||
mkdir -p $(ROOT_DIR)/temp/kustomize;\
|
|||
cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\
|
|||
kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\
|
|||
kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \
|
|||
if [ $(DEPLOY_NAME) != "" ]; then \
|
|||
kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; \
|
|||
fi; |
|||
|
|||
|
|||
# Parsing protobuf files and generating go files.
|
|||
.PHONY: pb |
|||
pb: cli.install |
|||
@gf gen pb |
|||
|
|||
# Generate protobuf files for database tables.
|
|||
.PHONY: pbentity |
|||
pbentity: cli.install |
|||
@gf gen pbentity |
|||
@ -0,0 +1,30 @@ |
|||
package cmd |
|||
|
|||
import ( |
|||
"context" |
|||
"gf_demo_02/internal/controller/user" |
|||
"gf_demo_02/internal/service" |
|||
|
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/net/ghttp" |
|||
"github.com/gogf/gf/v2/os/gcmd" |
|||
) |
|||
|
|||
var ( |
|||
Main = gcmd.Command{ |
|||
Name: "main", |
|||
Usage: "main", |
|||
Brief: "start http server", |
|||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { |
|||
s := g.Server() |
|||
s.Group("/", func(group *ghttp.RouterGroup) { |
|||
group.Middleware(service.CorsMiddleware) |
|||
group.Middleware(ghttp.MiddlewareHandlerResponse) |
|||
group.Middleware(service.JWTMiddleware) |
|||
group.Bind(user.CUser{}) |
|||
}) |
|||
s.Run() |
|||
return nil |
|||
}, |
|||
} |
|||
) |
|||
@ -0,0 +1,3 @@ |
|||
package consts |
|||
|
|||
const TOKEN_KEY = "55558888" |
|||
@ -0,0 +1,98 @@ |
|||
package user |
|||
|
|||
import ( |
|||
"context" |
|||
"gf_demo_02/api/user/v1" |
|||
"gf_demo_02/internal/consts" |
|||
m "gf_demo_02/internal/model" |
|||
"gf_demo_02/internal/model/entity" |
|||
"gf_demo_02/internal/service" |
|||
"github.com/gogf/gf/v2/errors/gcode" |
|||
"github.com/gogf/gf/v2/errors/gerror" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
jwt "github.com/golang-jwt/jwt/v5" |
|||
"golang.org/x/crypto/bcrypt" |
|||
"time" |
|||
) |
|||
|
|||
type CUser struct{} |
|||
|
|||
func (*CUser) Login(ctx context.Context, req *user.LoginReq) (res *user.LoginRes, err error) { |
|||
model := g.DB().Model("user") |
|||
u := new(entity.User) |
|||
res = new(user.LoginRes) |
|||
err = model.Where("name", req.Username).Scan(&u) |
|||
if err != nil || u.Id == 0 { |
|||
return nil, gerror.NewCode(gcode.New(451, "用户名不存在", nil), "用户名不存在") |
|||
} |
|||
if bcrypt.CompareHashAndPassword([]byte(u.Pass), []byte(req.Password)) != nil { |
|||
return nil, gerror.NewCode(gcode.New(450, "密码错误", nil), "密码错误") |
|||
} |
|||
claims := m.UserClaim{ |
|||
UserId: u.Id, |
|||
UserName: u.Name, |
|||
RegisteredClaims: jwt.RegisteredClaims{ |
|||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), |
|||
IssuedAt: jwt.NewNumericDate(time.Now()), |
|||
NotBefore: jwt.NewNumericDate(time.Now()), |
|||
Issuer: "我"}, |
|||
} |
|||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
|||
tokenStr, err := token.SignedString([]byte(consts.TOKEN_KEY)) |
|||
res.Token = tokenStr |
|||
return res, nil |
|||
} |
|||
|
|||
func (*CUser) GetUserList(ctx context.Context, req *user.GetUserListReq) (res *user.GetUserListRes, err error) { |
|||
users, err := service.User().GetUserList(ctx) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
res = new(user.GetUserListRes) |
|||
res.Users = users |
|||
return res, nil |
|||
} |
|||
|
|||
func (*CUser) EditUser(ctx context.Context, req *user.EditUserReq) (res *user.EditUserRes, err error) { |
|||
res = new(user.EditUserRes) |
|||
if req.Id == 0 { |
|||
err = service.User().AddUser(ctx, req) |
|||
} else { |
|||
err = service.User().UpdateUser(ctx, req) |
|||
} |
|||
if err != nil { |
|||
return res, err |
|||
} |
|||
return res, nil |
|||
} |
|||
|
|||
func (*CUser) DeleteUser(ctx context.Context, req *user.DeleteUserReq) (res *user.DeleteUserRes, err error) { |
|||
return nil, service.User().DeleteUser(ctx, req) |
|||
} |
|||
|
|||
func (*CUser) GetSelf(ctx context.Context, req *user.GetSelfReq) (res *user.GetSelfRes, err error) { |
|||
r := g.RequestFromCtx(ctx) |
|||
u := r.GetCtxVar("user") |
|||
res = new(user.GetSelfRes) |
|||
err = u.Struct(&res.User) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return res, nil |
|||
} |
|||
|
|||
func (*CUser) SearchUser(ctx context.Context, req *user.SearchUserReq) (res *user.SearchUserRes, err error) { |
|||
res = new(user.SearchUserRes) |
|||
if g.IsEmpty(req.Keyword) { |
|||
res.Users, err = service.User().GetUserList(ctx) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return res, nil |
|||
} |
|||
res.Users, err = service.User().SearchUser(ctx, req.Keyword) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return res, nil |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
// =================================================================================
|
|||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
|||
// =================================================================================
|
|||
|
|||
package dao |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/dao/internal" |
|||
) |
|||
|
|||
// internalCourseDao is internal type for wrapping internal DAO implements.
|
|||
type internalCourseDao = *internal.CourseDao |
|||
|
|||
// courseDao is the data access object for table course.
|
|||
// You can define custom methods on it to extend its functionality as you wish.
|
|||
type courseDao struct { |
|||
internalCourseDao |
|||
} |
|||
|
|||
var ( |
|||
// Course is globally public accessible object for table course operations.
|
|||
Course = courseDao{ |
|||
internal.NewCourseDao(), |
|||
} |
|||
) |
|||
|
|||
// Fill with you ideas below.
|
|||
@ -0,0 +1,83 @@ |
|||
// ==========================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// ==========================================================================
|
|||
|
|||
package internal |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/gogf/gf/v2/database/gdb" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
// CourseDao is the data access object for table course.
|
|||
type CourseDao struct { |
|||
table string // table is the underlying table name of the DAO.
|
|||
group string // group is the database configuration group name of current DAO.
|
|||
columns CourseColumns // columns contains all the column names of Table for convenient usage.
|
|||
} |
|||
|
|||
// CourseColumns defines and stores column names for table course.
|
|||
type CourseColumns struct { |
|||
Id string //
|
|||
Name string //
|
|||
Day string //
|
|||
CreateAt string //
|
|||
UpdateAt string //
|
|||
DeleteAt string //
|
|||
} |
|||
|
|||
// courseColumns holds the columns for table course.
|
|||
var courseColumns = CourseColumns{ |
|||
Id: "id", |
|||
Name: "name", |
|||
Day: "day", |
|||
CreateAt: "create_at", |
|||
UpdateAt: "update_at", |
|||
DeleteAt: "delete_at", |
|||
} |
|||
|
|||
// NewCourseDao creates and returns a new DAO object for table data access.
|
|||
func NewCourseDao() *CourseDao { |
|||
return &CourseDao{ |
|||
group: "default", |
|||
table: "course", |
|||
columns: courseColumns, |
|||
} |
|||
} |
|||
|
|||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
|||
func (dao *CourseDao) DB() gdb.DB { |
|||
return g.DB(dao.group) |
|||
} |
|||
|
|||
// Table returns the table name of current dao.
|
|||
func (dao *CourseDao) Table() string { |
|||
return dao.table |
|||
} |
|||
|
|||
// Columns returns all column names of current dao.
|
|||
func (dao *CourseDao) Columns() CourseColumns { |
|||
return dao.columns |
|||
} |
|||
|
|||
// Group returns the configuration group name of database of current dao.
|
|||
func (dao *CourseDao) Group() string { |
|||
return dao.group |
|||
} |
|||
|
|||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
|||
func (dao *CourseDao) Ctx(ctx context.Context) *gdb.Model { |
|||
return dao.DB().Model(dao.table).Safe().Ctx(ctx) |
|||
} |
|||
|
|||
// Transaction wraps the transaction logic using function f.
|
|||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
|||
// It commits the transaction and returns nil if function f returns nil.
|
|||
//
|
|||
// Note that, you should not Commit or Rollback the transaction in function f
|
|||
// as it is automatically handled by this function.
|
|||
func (dao *CourseDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { |
|||
return dao.Ctx(ctx).Transaction(ctx, f) |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
// ==========================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// ==========================================================================
|
|||
|
|||
package internal |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/gogf/gf/v2/database/gdb" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
// StockDao is the data access object for table stock.
|
|||
type StockDao struct { |
|||
table string // table is the underlying table name of the DAO.
|
|||
group string // group is the database configuration group name of current DAO.
|
|||
columns StockColumns // columns contains all the column names of Table for convenient usage.
|
|||
} |
|||
|
|||
// StockColumns defines and stores column names for table stock.
|
|||
type StockColumns struct { |
|||
Id string //
|
|||
Name string //
|
|||
Num string //
|
|||
CreateAt string //
|
|||
UpdateAt string //
|
|||
DeleteAt string //
|
|||
} |
|||
|
|||
// stockColumns holds the columns for table stock.
|
|||
var stockColumns = StockColumns{ |
|||
Id: "id", |
|||
Name: "name", |
|||
Num: "num", |
|||
CreateAt: "create_at", |
|||
UpdateAt: "update_at", |
|||
DeleteAt: "delete_at", |
|||
} |
|||
|
|||
// NewStockDao creates and returns a new DAO object for table data access.
|
|||
func NewStockDao() *StockDao { |
|||
return &StockDao{ |
|||
group: "default", |
|||
table: "stock", |
|||
columns: stockColumns, |
|||
} |
|||
} |
|||
|
|||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
|||
func (dao *StockDao) DB() gdb.DB { |
|||
return g.DB(dao.group) |
|||
} |
|||
|
|||
// Table returns the table name of current dao.
|
|||
func (dao *StockDao) Table() string { |
|||
return dao.table |
|||
} |
|||
|
|||
// Columns returns all column names of current dao.
|
|||
func (dao *StockDao) Columns() StockColumns { |
|||
return dao.columns |
|||
} |
|||
|
|||
// Group returns the configuration group name of database of current dao.
|
|||
func (dao *StockDao) Group() string { |
|||
return dao.group |
|||
} |
|||
|
|||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
|||
func (dao *StockDao) Ctx(ctx context.Context) *gdb.Model { |
|||
return dao.DB().Model(dao.table).Safe().Ctx(ctx) |
|||
} |
|||
|
|||
// Transaction wraps the transaction logic using function f.
|
|||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
|||
// It commits the transaction and returns nil if function f returns nil.
|
|||
//
|
|||
// Note that, you should not Commit or Rollback the transaction in function f
|
|||
// as it is automatically handled by this function.
|
|||
func (dao *StockDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { |
|||
return dao.Ctx(ctx).Transaction(ctx, f) |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// ==========================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// ==========================================================================
|
|||
|
|||
package internal |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/gogf/gf/v2/database/gdb" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
// UserDao is the data access object for table user.
|
|||
type UserDao struct { |
|||
table string // table is the underlying table name of the DAO.
|
|||
group string // group is the database configuration group name of current DAO.
|
|||
columns UserColumns // columns contains all the column names of Table for convenient usage.
|
|||
} |
|||
|
|||
// UserColumns defines and stores column names for table user.
|
|||
type UserColumns struct { |
|||
Id string //
|
|||
Name string //
|
|||
Pass string //
|
|||
Property string //
|
|||
CreateAt string //
|
|||
DeleteAt string //
|
|||
UpdateAt string //
|
|||
} |
|||
|
|||
// userColumns holds the columns for table user.
|
|||
var userColumns = UserColumns{ |
|||
Id: "id", |
|||
Name: "name", |
|||
Pass: "pass", |
|||
Property: "property", |
|||
CreateAt: "create_at", |
|||
DeleteAt: "delete_at", |
|||
UpdateAt: "update_at", |
|||
} |
|||
|
|||
// NewUserDao creates and returns a new DAO object for table data access.
|
|||
func NewUserDao() *UserDao { |
|||
return &UserDao{ |
|||
group: "default", |
|||
table: "user", |
|||
columns: userColumns, |
|||
} |
|||
} |
|||
|
|||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
|||
func (dao *UserDao) DB() gdb.DB { |
|||
return g.DB(dao.group) |
|||
} |
|||
|
|||
// Table returns the table name of current dao.
|
|||
func (dao *UserDao) Table() string { |
|||
return dao.table |
|||
} |
|||
|
|||
// Columns returns all column names of current dao.
|
|||
func (dao *UserDao) Columns() UserColumns { |
|||
return dao.columns |
|||
} |
|||
|
|||
// Group returns the configuration group name of database of current dao.
|
|||
func (dao *UserDao) Group() string { |
|||
return dao.group |
|||
} |
|||
|
|||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
|||
func (dao *UserDao) Ctx(ctx context.Context) *gdb.Model { |
|||
return dao.DB().Model(dao.table).Safe().Ctx(ctx) |
|||
} |
|||
|
|||
// Transaction wraps the transaction logic using function f.
|
|||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
|||
// It commits the transaction and returns nil if function f returns nil.
|
|||
//
|
|||
// Note that, you should not Commit or Rollback the transaction in function f
|
|||
// as it is automatically handled by this function.
|
|||
func (dao *UserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { |
|||
return dao.Ctx(ctx).Transaction(ctx, f) |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
// ==========================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// ==========================================================================
|
|||
|
|||
package internal |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/gogf/gf/v2/database/gdb" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
// UserCourseDao is the data access object for table user_course.
|
|||
type UserCourseDao struct { |
|||
table string // table is the underlying table name of the DAO.
|
|||
group string // group is the database configuration group name of current DAO.
|
|||
columns UserCourseColumns // columns contains all the column names of Table for convenient usage.
|
|||
} |
|||
|
|||
// UserCourseColumns defines and stores column names for table user_course.
|
|||
type UserCourseColumns struct { |
|||
Uid string //
|
|||
Cid string //
|
|||
} |
|||
|
|||
// userCourseColumns holds the columns for table user_course.
|
|||
var userCourseColumns = UserCourseColumns{ |
|||
Uid: "uid", |
|||
Cid: "cid", |
|||
} |
|||
|
|||
// NewUserCourseDao creates and returns a new DAO object for table data access.
|
|||
func NewUserCourseDao() *UserCourseDao { |
|||
return &UserCourseDao{ |
|||
group: "default", |
|||
table: "user_course", |
|||
columns: userCourseColumns, |
|||
} |
|||
} |
|||
|
|||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
|||
func (dao *UserCourseDao) DB() gdb.DB { |
|||
return g.DB(dao.group) |
|||
} |
|||
|
|||
// Table returns the table name of current dao.
|
|||
func (dao *UserCourseDao) Table() string { |
|||
return dao.table |
|||
} |
|||
|
|||
// Columns returns all column names of current dao.
|
|||
func (dao *UserCourseDao) Columns() UserCourseColumns { |
|||
return dao.columns |
|||
} |
|||
|
|||
// Group returns the configuration group name of database of current dao.
|
|||
func (dao *UserCourseDao) Group() string { |
|||
return dao.group |
|||
} |
|||
|
|||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
|||
func (dao *UserCourseDao) Ctx(ctx context.Context) *gdb.Model { |
|||
return dao.DB().Model(dao.table).Safe().Ctx(ctx) |
|||
} |
|||
|
|||
// Transaction wraps the transaction logic using function f.
|
|||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
|||
// It commits the transaction and returns nil if function f returns nil.
|
|||
//
|
|||
// Note that, you should not Commit or Rollback the transaction in function f
|
|||
// as it is automatically handled by this function.
|
|||
func (dao *UserCourseDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { |
|||
return dao.Ctx(ctx).Transaction(ctx, f) |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
// =================================================================================
|
|||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
|||
// =================================================================================
|
|||
|
|||
package dao |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/dao/internal" |
|||
) |
|||
|
|||
// internalStockDao is internal type for wrapping internal DAO implements.
|
|||
type internalStockDao = *internal.StockDao |
|||
|
|||
// stockDao is the data access object for table stock.
|
|||
// You can define custom methods on it to extend its functionality as you wish.
|
|||
type stockDao struct { |
|||
internalStockDao |
|||
} |
|||
|
|||
var ( |
|||
// Stock is globally public accessible object for table stock operations.
|
|||
Stock = stockDao{ |
|||
internal.NewStockDao(), |
|||
} |
|||
) |
|||
|
|||
// Fill with you ideas below.
|
|||
@ -0,0 +1,27 @@ |
|||
// =================================================================================
|
|||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
|||
// =================================================================================
|
|||
|
|||
package dao |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/dao/internal" |
|||
) |
|||
|
|||
// internalUserDao is internal type for wrapping internal DAO implements.
|
|||
type internalUserDao = *internal.UserDao |
|||
|
|||
// userDao is the data access object for table user.
|
|||
// You can define custom methods on it to extend its functionality as you wish.
|
|||
type userDao struct { |
|||
internalUserDao |
|||
} |
|||
|
|||
var ( |
|||
// User is globally public accessible object for table user operations.
|
|||
User = userDao{ |
|||
internal.NewUserDao(), |
|||
} |
|||
) |
|||
|
|||
// Fill with you ideas below.
|
|||
@ -0,0 +1,27 @@ |
|||
// =================================================================================
|
|||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
|||
// =================================================================================
|
|||
|
|||
package dao |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/dao/internal" |
|||
) |
|||
|
|||
// internalUserCourseDao is internal type for wrapping internal DAO implements.
|
|||
type internalUserCourseDao = *internal.UserCourseDao |
|||
|
|||
// userCourseDao is the data access object for table user_course.
|
|||
// You can define custom methods on it to extend its functionality as you wish.
|
|||
type userCourseDao struct { |
|||
internalUserCourseDao |
|||
} |
|||
|
|||
var ( |
|||
// UserCourse is globally public accessible object for table user_course operations.
|
|||
UserCourse = userCourseDao{ |
|||
internal.NewUserCourseDao(), |
|||
} |
|||
) |
|||
|
|||
// Fill with you ideas below.
|
|||
@ -0,0 +1,12 @@ |
|||
package course |
|||
|
|||
import ( |
|||
"context" |
|||
"gf_demo_02/internal/model" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
func GetCourses(ctx context.Context) (courses []model.CourseWithUsers, err error) { |
|||
g.Redis().HGetAll() |
|||
g.Dump() |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
// ==========================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// ==========================================================================
|
|||
|
|||
package logic |
|||
|
|||
import ( |
|||
_ "gf_demo_02/internal/logic/user" |
|||
) |
|||
@ -0,0 +1,143 @@ |
|||
package user |
|||
|
|||
import ( |
|||
"context" |
|||
"gf_demo_02/api/user/v1" |
|||
"gf_demo_02/internal/model/entity" |
|||
"gf_demo_02/internal/service" |
|||
"github.com/gogf/gf/v2/database/gdb" |
|||
"github.com/gogf/gf/v2/errors/gcode" |
|||
"github.com/gogf/gf/v2/errors/gerror" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/util/gconv" |
|||
"golang.org/x/crypto/bcrypt" |
|||
"strings" |
|||
) |
|||
|
|||
type sUser struct { |
|||
} |
|||
|
|||
func init() { |
|||
service.RegisterUser(&sUser{}) |
|||
} |
|||
|
|||
func (u *sUser) GetUser(cond g.Map) (user *entity.User, err error) { |
|||
model := g.Model("user") |
|||
if cond["id"] != nil && gconv.Uint(cond["id"]) != 0 { |
|||
model = model.Where("id", cond["id"]) |
|||
} else if cond["name"] != nil && gconv.String(cond["name"]) != "" { |
|||
model = model.Where("name", cond["name"]) |
|||
} else { |
|||
return nil, gerror.NewCode(gcode.New(88, "缺少查询条件", nil)) |
|||
} |
|||
err = model.Scan(&user) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
if user == nil { |
|||
return nil, gerror.NewCode(gcode.New(483, "用户不存在!", nil)) |
|||
} |
|||
return user, nil |
|||
} |
|||
|
|||
func (*sUser) GetUserList(ctx context.Context) (users []entity.User, err error) { |
|||
all, err := g.DB().Model("user").All() |
|||
if err != nil { |
|||
return nil, gerror.NewCode(gcode.New(599, "数据库error", nil)) |
|||
} |
|||
err = all.Structs(&users) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return users, nil |
|||
} |
|||
|
|||
func (*sUser) AddUser(ctx context.Context, req *user.EditUserReq) error { |
|||
u := entity.User{ |
|||
Id: req.Id, |
|||
Name: req.Name, |
|||
Pass: req.Pass, |
|||
Property: req.Property, |
|||
} |
|||
one, _ := g.Model("user").Where("name", req.Name).One() |
|||
if one != nil { |
|||
return gerror.NewCode(gcode.New(480, "用户名重复", nil)) |
|||
} |
|||
if len(req.Pass) < 6 { |
|||
return gerror.NewCode(gcode.New(481, "密码过短,至少6位", nil)) |
|||
} |
|||
password, err := bcrypt.GenerateFromPassword([]byte(u.Pass), 10) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
u.Pass = string(password) |
|||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { |
|||
_, err = tx.Model("user").Insert(u) |
|||
return err |
|||
}) |
|||
} |
|||
|
|||
func (*sUser) UpdateUser(ctx context.Context, req *user.EditUserReq) error { |
|||
u := entity.User{ |
|||
Id: req.Id, |
|||
Name: req.Name, |
|||
Pass: req.Pass, |
|||
Property: req.Property, |
|||
} |
|||
one, _ := g.Model("user").Where("id", req.Id).One() |
|||
if one == nil { |
|||
return gerror.NewCode(gcode.New(483, "用户不存在!", nil)) |
|||
} |
|||
one, _ = g.Model("user").Where("name", req.Name).WhereNot("id", u.Id).One() |
|||
if one != nil { |
|||
return gerror.NewCode(gcode.New(480, "用户名重复", nil)) |
|||
} |
|||
if len(req.Pass) < 6 && req.Pass != "" { |
|||
return gerror.NewCode(gcode.New(481, "密码过短,至少6位", nil)) |
|||
} |
|||
if req.Pass != "" { |
|||
password, err := bcrypt.GenerateFromPassword([]byte(u.Pass), 10) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
u.Pass = string(password) |
|||
} |
|||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { |
|||
model := tx.Model("user").OmitEmptyData() |
|||
result, err := model.Where("id", u.Id).Update(u) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if affected, err := result.RowsAffected(); affected < 1 || err != nil { |
|||
return gerror.NewCode(gcode.New(500, "服务器错误", nil)) |
|||
} |
|||
return nil |
|||
}) |
|||
} |
|||
|
|||
func (*sUser) DeleteUser(ctx context.Context, req *user.DeleteUserReq) error { |
|||
one, _ := g.DB().Model("user").Where("id", req.Id).One() |
|||
if one == nil { |
|||
return gerror.NewCode(gcode.New(483, "用户不存在!", nil)) |
|||
} |
|||
tokenStr := g.RequestFromCtx(ctx).GetCtxVar("Authorization").String() |
|||
tokenStr = strings.TrimSpace(tokenStr) |
|||
tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") |
|||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { |
|||
_, err := tx.Model("user").Where("id", req.Id).Delete() |
|||
return err |
|||
}) |
|||
} |
|||
|
|||
func (*sUser) SearchUser(ctx context.Context, keyword string) ([]entity.User, error) { |
|||
all, err := g.Model("user").WhereLike("name", "%"+keyword+"%").All() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
users := make([]entity.User, 0) |
|||
err = all.Structs(&users) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return users, nil |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
package model |
|||
|
|||
import "github.com/golang-jwt/jwt/v5" |
|||
|
|||
type UserClaim struct { |
|||
UserId uint |
|||
UserName string |
|||
jwt.RegisteredClaims |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package do |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// Course is the golang structure of table course for DAO operations like Where/Data.
|
|||
type Course struct { |
|||
g.Meta `orm:"table:course, do:true"` |
|||
Id interface{} //
|
|||
Name interface{} //
|
|||
Day interface{} //
|
|||
CreateAt *gtime.Time //
|
|||
UpdateAt *gtime.Time //
|
|||
DeleteAt *gtime.Time //
|
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package do |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// Stock is the golang structure of table stock for DAO operations like Where/Data.
|
|||
type Stock struct { |
|||
g.Meta `orm:"table:stock, do:true"` |
|||
Id interface{} //
|
|||
Name interface{} //
|
|||
Num interface{} //
|
|||
CreateAt *gtime.Time //
|
|||
UpdateAt *gtime.Time //
|
|||
DeleteAt *gtime.Time //
|
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package do |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// User is the golang structure of table user for DAO operations like Where/Data.
|
|||
type User struct { |
|||
g.Meta `orm:"table:user, do:true"` |
|||
Id interface{} //
|
|||
Name interface{} //
|
|||
Pass interface{} //
|
|||
Property interface{} //
|
|||
CreateAt *gtime.Time //
|
|||
DeleteAt *gtime.Time //
|
|||
UpdateAt *gtime.Time //
|
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package do |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
// UserCourse is the golang structure of table user_course for DAO operations like Where/Data.
|
|||
type UserCourse struct { |
|||
g.Meta `orm:"table:user_course, do:true"` |
|||
Uid interface{} //
|
|||
Cid interface{} //
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package entity |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// Course is the golang structure for table course.
|
|||
type Course struct { |
|||
Id uint `json:"id" orm:"id" ` //
|
|||
Name string `json:"name" orm:"name" ` //
|
|||
Day string `json:"day" orm:"day" ` //
|
|||
CreateAt *gtime.Time `json:"createAt" orm:"create_at" ` //
|
|||
UpdateAt *gtime.Time `json:"updateAt" orm:"update_at" ` //
|
|||
DeleteAt *gtime.Time `json:"deleteAt" orm:"delete_at" ` //
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package entity |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// Stock is the golang structure for table stock.
|
|||
type Stock struct { |
|||
Id uint `json:"id" orm:"id" ` //
|
|||
Name string `json:"name" orm:"name" ` //
|
|||
Num uint `json:"num" orm:"num" ` //
|
|||
CreateAt *gtime.Time `json:"createAt" orm:"create_at" ` //
|
|||
UpdateAt *gtime.Time `json:"updateAt" orm:"update_at" ` //
|
|||
DeleteAt *gtime.Time `json:"deleteAt" orm:"delete_at" ` //
|
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package entity |
|||
|
|||
import ( |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
// User is the golang structure for table user.
|
|||
type User struct { |
|||
Id uint `json:"id" orm:"id" ` //
|
|||
Name string `json:"name" orm:"name" ` //
|
|||
Pass string `json:"pass" orm:"pass" ` //
|
|||
Property uint `json:"property" orm:"property" ` //
|
|||
CreateAt *gtime.Time `json:"createAt" orm:"create_at" ` //
|
|||
DeleteAt *gtime.Time `json:"deleteAt" orm:"delete_at" ` //
|
|||
UpdateAt *gtime.Time `json:"updateAt" orm:"update_at" ` //
|
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
// =================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// =================================================================================
|
|||
|
|||
package entity |
|||
|
|||
// UserCourse is the golang structure for table user_course.
|
|||
type UserCourse struct { |
|||
Uid uint `json:"uid" orm:"uid" ` //
|
|||
Cid uint `json:"cid" orm:"cid" ` //
|
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
package model |
|||
|
|||
import ( |
|||
"gf_demo_02/internal/model/entity" |
|||
"github.com/gogf/gf/v2/os/gtime" |
|||
) |
|||
|
|||
type CourseWithUsers struct { |
|||
Id uint `json:"id" orm:"id" ` //
|
|||
Name string `json:"name" orm:"name" ` //
|
|||
Day string `json:"day" orm:"day" ` //
|
|||
CreateAt *gtime.Time `json:"createAt" orm:"create_at" ` //
|
|||
UpdateAt *gtime.Time `json:"updateAt" orm:"update_at" ` //
|
|||
DeleteAt *gtime.Time `json:"deleteAt" orm:"delete_at" ` |
|||
Users []entity.User `json:"users"` |
|||
} |
|||
@ -0,0 +1 @@ |
|||
package packed |
|||
@ -0,0 +1,65 @@ |
|||
package service |
|||
|
|||
import ( |
|||
"fmt" |
|||
"gf_demo_02/internal/consts" |
|||
"gf_demo_02/internal/model" |
|||
"strings" |
|||
|
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/net/ghttp" |
|||
"github.com/golang-jwt/jwt/v5" |
|||
) |
|||
|
|||
func JWTMiddleware(r *ghttp.Request) { |
|||
url := r.GetUrl() |
|||
if strings.HasSuffix(url, "/login") || strings.HasSuffix(url, "/loginPage") { |
|||
r.Middleware.Next() |
|||
return |
|||
} |
|||
tokenStr := r.Header.Get("Authorization") |
|||
tokenStr = strings.TrimSpace(tokenStr) |
|||
tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") |
|||
if g.IsEmpty(tokenStr) { |
|||
r.Response.WriteStatus(401, "no token") |
|||
return |
|||
} |
|||
token, err := jwt.ParseWithClaims(tokenStr, &model.UserClaim{}, func(token *jwt.Token) (interface{}, error) { |
|||
_, ok := token.Method.(*jwt.SigningMethodHMAC) |
|||
if !ok { |
|||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) |
|||
} |
|||
return []byte(consts.TOKEN_KEY), nil |
|||
}) |
|||
if err != nil { |
|||
r.Response.WriteStatus(401, "token invalid") |
|||
return |
|||
} |
|||
claim, ok := token.Claims.(*model.UserClaim) |
|||
if !ok || !token.Valid { |
|||
r.Response.WriteStatus(401, "token invalid") |
|||
return |
|||
} |
|||
id := claim.UserId |
|||
name := claim.UserName |
|||
cond := g.Map{ |
|||
"id": id, |
|||
"name": name, |
|||
} |
|||
user, err := User().GetUser(cond) |
|||
if err != nil || user == nil { |
|||
r.Response.WriteStatus(401, "token invalid") |
|||
return |
|||
} |
|||
if user.Id != id || user.Name != name { |
|||
r.Response.WriteStatus(401, "token invalid") |
|||
return |
|||
} |
|||
r.SetCtxVar("user", user) |
|||
r.Middleware.Next() |
|||
} |
|||
|
|||
func CorsMiddleware(r *ghttp.Request) { |
|||
r.Response.CORSDefault() |
|||
r.Middleware.Next() |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package service |
|||
|
|||
import ( |
|||
"fmt" |
|||
|
|||
"golang.org/x/crypto/bcrypt" |
|||
) |
|||
|
|||
// bcrypt加密
|
|||
func encode() { |
|||
password, err := bcrypt.GenerateFromPassword([]byte("123"), 10) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
fmt.Println(string(password)) |
|||
err = bcrypt.CompareHashAndPassword(password, []byte("123")) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
fmt.Println("correct") |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
package service |
|||
|
|||
import "testing" |
|||
|
|||
func TestEncode(T *testing.T) { |
|||
encode() |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
// ================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// You can delete these comments if you wish manually maintain this interface file.
|
|||
// ================================================================================
|
|||
|
|||
package service |
|||
|
|||
import ( |
|||
"context" |
|||
"gf_demo_02/api/user/v1" |
|||
"gf_demo_02/internal/model/entity" |
|||
|
|||
"github.com/gogf/gf/v2/frame/g" |
|||
) |
|||
|
|||
type ( |
|||
IUser interface { |
|||
GetUser(cond g.Map) (user *entity.User, err error) |
|||
GetUserList(ctx context.Context) (users []entity.User, err error) |
|||
AddUser(ctx context.Context, req *user.EditUserReq) error |
|||
UpdateUser(ctx context.Context, req *user.EditUserReq) error |
|||
DeleteUser(ctx context.Context, req *user.DeleteUserReq) error |
|||
SearchUser(ctx context.Context, keyword string) ([]entity.User, error) |
|||
} |
|||
) |
|||
|
|||
var ( |
|||
localUser IUser |
|||
) |
|||
|
|||
func User() IUser { |
|||
if localUser == nil { |
|||
panic("implement not found for interface IUser, forgot register?") |
|||
} |
|||
return localUser |
|||
} |
|||
|
|||
func RegisterUser(i IUser) { |
|||
localUser = i |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
package main |
|||
|
|||
import ( |
|||
_ "gf_demo_02/internal/packed" |
|||
|
|||
_ "gf_demo_02/internal/logic" |
|||
|
|||
"github.com/gogf/gf/v2/os/gctx" |
|||
|
|||
"gf_demo_02/internal/cmd" |
|||
|
|||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2" |
|||
) |
|||
|
|||
func main() { |
|||
cmd.Main.Run(gctx.GetInitCtx()) |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
apiVersion: apps/v1 |
|||
kind: Deployment |
|||
metadata: |
|||
name: template-single |
|||
labels: |
|||
app: template-single |
|||
spec: |
|||
replicas: 1 |
|||
selector: |
|||
matchLabels: |
|||
app: template-single |
|||
template: |
|||
metadata: |
|||
labels: |
|||
app: template-single |
|||
spec: |
|||
containers: |
|||
- name : main |
|||
image: template-single |
|||
imagePullPolicy: Always |
|||
|
|||
@ -0,0 +1,8 @@ |
|||
apiVersion: kustomize.config.k8s.io/v1beta1 |
|||
kind: Kustomization |
|||
resources: |
|||
- deployment.yaml |
|||
- service.yaml |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,12 @@ |
|||
apiVersion: v1 |
|||
kind: Service |
|||
metadata: |
|||
name: template-single |
|||
spec: |
|||
ports: |
|||
- port: 80 |
|||
protocol: TCP |
|||
targetPort: 8000 |
|||
selector: |
|||
app: template-single |
|||
|
|||
@ -0,0 +1,14 @@ |
|||
apiVersion: v1 |
|||
kind: ConfigMap |
|||
metadata: |
|||
name: template-single-configmap |
|||
data: |
|||
config.yaml: | |
|||
server: |
|||
address: ":8000" |
|||
openapiPath: "/api.json" |
|||
swaggerPath: "/swagger" |
|||
|
|||
logger: |
|||
level : "all" |
|||
stdout: true |
|||
@ -0,0 +1,10 @@ |
|||
apiVersion: apps/v1 |
|||
kind: Deployment |
|||
metadata: |
|||
name: template-single |
|||
spec: |
|||
template: |
|||
spec: |
|||
containers: |
|||
- name : main |
|||
image: template-single:develop |
|||
@ -0,0 +1,14 @@ |
|||
apiVersion: kustomize.config.k8s.io/v1beta1 |
|||
kind: Kustomization |
|||
|
|||
resources: |
|||
- ../../base |
|||
- configmap.yaml |
|||
|
|||
patchesStrategicMerge: |
|||
- deployment.yaml |
|||
|
|||
namespace: default |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,16 @@ |
|||
FROM loads/alpine:3.8 |
|||
|
|||
############################################################################### |
|||
# INSTALLATION |
|||
############################################################################### |
|||
|
|||
ENV WORKDIR /app |
|||
ADD resource $WORKDIR/ |
|||
ADD ./temp/linux_amd64/main $WORKDIR/main |
|||
RUN chmod +x $WORKDIR/main |
|||
|
|||
############################################################################### |
|||
# START |
|||
############################################################################### |
|||
WORKDIR $WORKDIR |
|||
CMD ./main |
|||
@ -0,0 +1,8 @@ |
|||
#!/bin/bash |
|||
|
|||
# This shell is executed before docker build. |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
@ -0,0 +1,8 @@ |
|||
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] |
|||
charset = utf-8 |
|||
indent_size = 2 |
|||
indent_style = space |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
|||
end_of_line = lf |
|||
max_line_length = 100 |
|||
@ -0,0 +1 @@ |
|||
* text=auto eol=lf |
|||
@ -0,0 +1,42 @@ |
|||
# 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 |
|||
|
|||
# Editor directories and files |
|||
.vscode/* |
|||
!.vscode/extensions.json |
|||
.idea |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
|
|||
*.tsbuildinfo |
|||
|
|||
.eslintcache |
|||
|
|||
# Cypress |
|||
/cypress/videos/ |
|||
/cypress/screenshots/ |
|||
|
|||
# Vitest |
|||
__screenshots__/ |
|||
|
|||
# Vite |
|||
*.timestamp-*-*.mjs |
|||
|
|||
test-results/ |
|||
playwright-report/ |
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"$schema": "./node_modules/oxlint/configuration_schema.json", |
|||
"plugins": ["eslint", "typescript", "unicorn", "oxc", "vue", "vitest"], |
|||
"env": { |
|||
"browser": true |
|||
}, |
|||
"categories": { |
|||
"correctness": "error" |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/prettierrc", |
|||
"semi": false, |
|||
"singleQuote": true, |
|||
"printWidth": 100 |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
{ |
|||
"recommendations": [ |
|||
"Vue.volar", |
|||
"vitest.explorer", |
|||
"ms-playwright.playwright", |
|||
"dbaeumer.vscode-eslint", |
|||
"EditorConfig.EditorConfig", |
|||
"oxc.oxc-vscode", |
|||
"esbenp.prettier-vscode" |
|||
] |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
# vue_prj |
|||
|
|||
This template should help get you started developing with Vue 3 in Vite. |
|||
|
|||
## Recommended IDE Setup |
|||
|
|||
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). |
|||
|
|||
## Recommended Browser Setup |
|||
|
|||
- Chromium-based browsers (Chrome, Edge, Brave, etc.): |
|||
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) |
|||
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters) |
|||
- Firefox: |
|||
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) |
|||
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/) |
|||
|
|||
## Type Support for `.vue` Imports in TS |
|||
|
|||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. |
|||
|
|||
## Customize configuration |
|||
|
|||
See [Vite Configuration Reference](https://vite.dev/config/). |
|||
|
|||
## Project Setup |
|||
|
|||
```sh |
|||
npm install |
|||
``` |
|||
|
|||
### Compile and Hot-Reload for Development |
|||
|
|||
```sh |
|||
npm run dev |
|||
``` |
|||
|
|||
### Type-Check, Compile and Minify for Production |
|||
|
|||
```sh |
|||
npm run build |
|||
``` |
|||
|
|||
### Run Unit Tests with [Vitest](https://vitest.dev/) |
|||
|
|||
```sh |
|||
npm run test:unit |
|||
``` |
|||
|
|||
### Run End-to-End Tests with [Playwright](https://playwright.dev) |
|||
|
|||
```sh |
|||
# Install browsers for the first run |
|||
npx playwright install |
|||
|
|||
# When testing on CI, must build the project first |
|||
npm run build |
|||
|
|||
# Runs the end-to-end tests |
|||
npm run test:e2e |
|||
# Runs the tests only on Chromium |
|||
npm run test:e2e -- --project=chromium |
|||
# Runs the tests of a specific file |
|||
npm run test:e2e -- tests/example.spec.ts |
|||
# Runs the tests in debug mode |
|||
npm run test:e2e -- --debug |
|||
``` |
|||
|
|||
### Lint with [ESLint](https://eslint.org/) |
|||
|
|||
```sh |
|||
npm run lint |
|||
``` |
|||
@ -0,0 +1,4 @@ |
|||
{ |
|||
"extends": "@tsconfig/node24/tsconfig.json", |
|||
"include": ["./**/*"] |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
import { test, expect } from '@playwright/test' |
|||
|
|||
// See here how to get started:
|
|||
// https://playwright.dev/docs/intro
|
|||
test('visits the app root url', async ({ page }) => { |
|||
await page.goto('/') |
|||
await expect(page.locator('h1')).toHaveText('You did it!') |
|||
}) |
|||
@ -0,0 +1 @@ |
|||
/// <reference types="vite/client" />
|
|||
@ -0,0 +1,38 @@ |
|||
import { globalIgnores } from 'eslint/config' |
|||
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' |
|||
import pluginVue from 'eslint-plugin-vue' |
|||
import pluginPlaywright from 'eslint-plugin-playwright' |
|||
import pluginVitest from '@vitest/eslint-plugin' |
|||
import pluginOxlint from 'eslint-plugin-oxlint' |
|||
import skipFormatting from 'eslint-config-prettier/flat' |
|||
|
|||
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
|
|||
// import { configureVueProject } from '@vue/eslint-config-typescript'
|
|||
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
|
|||
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
|
|||
|
|||
export default defineConfigWithVueTs( |
|||
{ |
|||
name: 'app/files-to-lint', |
|||
files: ['**/*.{vue,ts,mts,tsx}'], |
|||
}, |
|||
|
|||
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']), |
|||
|
|||
...pluginVue.configs['flat/essential'], |
|||
vueTsConfigs.recommended, |
|||
|
|||
{ |
|||
...pluginPlaywright.configs['flat/recommended'], |
|||
files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], |
|||
}, |
|||
|
|||
{ |
|||
...pluginVitest.configs.recommended, |
|||
files: ['src/**/__tests__/*'], |
|||
}, |
|||
|
|||
...pluginOxlint.buildFromOxlintConfigFile('.oxlintrc.json'), |
|||
|
|||
skipFormatting, |
|||
) |
|||
@ -0,0 +1,13 @@ |
|||
<!DOCTYPE html> |
|||
<html lang=""> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<link rel="icon" href="/favicon.ico"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Vite App</title> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
</html> |
|||
7739
周新忠学习笔记/4.1/vue_prj/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,60 @@ |
|||
{ |
|||
"name": "vue_prj", |
|||
"version": "0.0.0", |
|||
"private": true, |
|||
"type": "module", |
|||
"scripts": { |
|||
"dev": "vite", |
|||
"build": "run-p type-check \"build-only {@}\" --", |
|||
"preview": "vite preview", |
|||
"test:unit": "vitest", |
|||
"test:e2e": "playwright test", |
|||
"build-only": "vite build", |
|||
"type-check": "vue-tsc --build", |
|||
"lint": "run-s lint:*", |
|||
"lint:oxlint": "oxlint . --fix", |
|||
"lint:eslint": "eslint . --fix --cache", |
|||
"format": "prettier --write --experimental-cli src/" |
|||
}, |
|||
"dependencies": { |
|||
"@element-plus/icons-vue": "^2.3.2", |
|||
"axios": "^1.14.0", |
|||
"element-plus": "^2.13.6", |
|||
"lucide-vue-next": "^1.0.0", |
|||
"pinia": "^3.0.4", |
|||
"vue": "^3.5.30", |
|||
"vue-router": "^4.6.4" |
|||
}, |
|||
"devDependencies": { |
|||
"@playwright/test": "^1.58.2", |
|||
"@tsconfig/node24": "^24.0.4", |
|||
"@types/jsdom": "^28.0.0", |
|||
"@types/node": "^24.12.0", |
|||
"@vitejs/plugin-vue": "^6.0.4", |
|||
"@vitejs/plugin-vue-jsx": "^5.1.4", |
|||
"@vitest/eslint-plugin": "^1.6.10", |
|||
"@vue/eslint-config-typescript": "^14.7.0", |
|||
"@vue/test-utils": "^2.4.6", |
|||
"@vue/tsconfig": "^0.9.0", |
|||
"eslint": "^10.0.3", |
|||
"eslint-config-prettier": "^10.1.8", |
|||
"eslint-plugin-oxlint": "~1.51.0", |
|||
"eslint-plugin-playwright": "^2.9.0", |
|||
"eslint-plugin-vue": "~10.8.0", |
|||
"jiti": "^2.6.1", |
|||
"jsdom": "^28.1.0", |
|||
"npm-run-all2": "^8.0.4", |
|||
"oxlint": "~1.51.0", |
|||
"prettier": "3.8.1", |
|||
"typescript": "~5.9.3", |
|||
"unplugin-auto-import": "^21.0.0", |
|||
"unplugin-vue-components": "^32.0.0", |
|||
"vite": "^7.3.1", |
|||
"vite-plugin-vue-devtools": "^8.0.7", |
|||
"vitest": "^4.0.18", |
|||
"vue-tsc": "^3.2.5" |
|||
}, |
|||
"engines": { |
|||
"node": "^20.19.0 || >=22.12.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
import process from 'node:process' |
|||
import { defineConfig, devices } from '@playwright/test' |
|||
|
|||
/** |
|||
* Read environment variables from file. |
|||
* https://github.com/motdotla/dotenv
|
|||
*/ |
|||
// require('dotenv').config();
|
|||
|
|||
/** |
|||
* See https://playwright.dev/docs/test-configuration.
|
|||
*/ |
|||
export default defineConfig({ |
|||
testDir: './e2e', |
|||
/* Maximum time one test can run for. */ |
|||
timeout: 30 * 1000, |
|||
expect: { |
|||
/** |
|||
* Maximum time expect() should wait for the condition to be met. |
|||
* For example in `await expect(locator).toHaveText();` |
|||
*/ |
|||
timeout: 5000, |
|||
}, |
|||
/* Fail the build on CI if you accidentally left test.only in the source code. */ |
|||
forbidOnly: !!process.env.CI, |
|||
/* Retry on CI only */ |
|||
retries: process.env.CI ? 2 : 0, |
|||
/* Opt out of parallel tests on CI. */ |
|||
workers: process.env.CI ? 1 : undefined, |
|||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ |
|||
reporter: 'html', |
|||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ |
|||
use: { |
|||
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ |
|||
actionTimeout: 0, |
|||
/* Base URL to use in actions like `await page.goto('/')`. */ |
|||
baseURL: process.env.CI ? 'http://localhost:4173' : 'http://localhost:5173', |
|||
|
|||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ |
|||
trace: 'on-first-retry', |
|||
|
|||
/* Only on CI systems run the tests headless */ |
|||
headless: !!process.env.CI, |
|||
}, |
|||
|
|||
/* Configure projects for major browsers */ |
|||
projects: [ |
|||
{ |
|||
name: 'chromium', |
|||
use: { |
|||
...devices['Desktop Chrome'], |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'firefox', |
|||
use: { |
|||
...devices['Desktop Firefox'], |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'webkit', |
|||
use: { |
|||
...devices['Desktop Safari'], |
|||
}, |
|||
}, |
|||
|
|||
/* Test against mobile viewports. */ |
|||
// {
|
|||
// name: 'Mobile Chrome',
|
|||
// use: {
|
|||
// ...devices['Pixel 5'],
|
|||
// },
|
|||
// },
|
|||
// {
|
|||
// name: 'Mobile Safari',
|
|||
// use: {
|
|||
// ...devices['iPhone 12'],
|
|||
// },
|
|||
// },
|
|||
|
|||
/* Test against branded browsers. */ |
|||
// {
|
|||
// name: 'Microsoft Edge',
|
|||
// use: {
|
|||
// channel: 'msedge',
|
|||
// },
|
|||
// },
|
|||
// {
|
|||
// name: 'Google Chrome',
|
|||
// use: {
|
|||
// channel: 'chrome',
|
|||
// },
|
|||
// },
|
|||
], |
|||
|
|||
/* Folder for test artifacts such as screenshots, videos, traces, etc. */ |
|||
// outputDir: 'test-results/',
|
|||
|
|||
/* Run your local dev server before starting the tests */ |
|||
webServer: { |
|||
/** |
|||
* Use the dev server by default for faster feedback loop. |
|||
* Use the preview server on CI for more realistic testing. |
|||
* Playwright will re-use the local server if there is already a dev-server running. |
|||
*/ |
|||
command: process.env.CI ? 'npm run preview' : 'npm run dev', |
|||
port: process.env.CI ? 4173 : 5173, |
|||
reuseExistingServer: !process.env.CI, |
|||
}, |
|||
}) |
|||
@ -0,0 +1,3 @@ |
|||
<template> |
|||
<router-view /> |
|||
</template> |
|||
@ -0,0 +1,11 @@ |
|||
import { describe, it, expect } from 'vitest' |
|||
|
|||
import { mount } from '@vue/test-utils' |
|||
import App from '../App.vue' |
|||
|
|||
describe('App', () => { |
|||
it('mounts renders properly', () => { |
|||
const wrapper = mount(App) |
|||
expect(wrapper.text()).toContain('You did it!') |
|||
}) |
|||
}) |
|||
@ -0,0 +1,32 @@ |
|||
import axios from "axios"; |
|||
import {ElMessage} from "element-plus"; |
|||
|
|||
const service =axios.create({baseURL:"http://localhost:8000",timeout:5000}) |
|||
|
|||
service.interceptors.request.use( |
|||
(config) => { |
|||
const token = localStorage.getItem('token') |
|||
if (token) { |
|||
// 统一加上 Header,后端 JWTMiddleware 就能拿到了
|
|||
config.headers['Authorization'] = token |
|||
} |
|||
return config |
|||
} |
|||
) |
|||
|
|||
// --- 响应拦截器 ---
|
|||
service.interceptors.response.use( |
|||
(response) => { |
|||
const res = response.data |
|||
return res |
|||
},(error)=>{ |
|||
const res = error.response |
|||
// 如果后端返回 401(未授权),强制跳回登录
|
|||
if (res.status === 401) { |
|||
localStorage.removeItem('token') |
|||
window.location.href = '/loginPage' |
|||
} |
|||
} |
|||
) |
|||
|
|||
export default service |
|||
@ -0,0 +1,156 @@ |
|||
<script setup lang="ts"> |
|||
import { ref, onMounted } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import { User, Reading } from '@element-plus/icons-vue' // 引入图标 |
|||
import { ElMessageBox, ElMessage } from 'element-plus' |
|||
import service from "@/api/service.ts"; |
|||
|
|||
const router = useRouter() |
|||
const isLogin = ref(false) |
|||
const loginButton=ref() |
|||
const logoutButton=ref() |
|||
const username=ref() |
|||
const userCard=ref() |
|||
const jumpLogin=()=>{ |
|||
console.log("跳转....") |
|||
router.push("/loginPage") |
|||
} |
|||
|
|||
const getName =()=>{ |
|||
if (isLogin.value) { |
|||
service.get("/admin/user/getSelf").then(res => { |
|||
console.log(res) |
|||
if (res.code == 0 || res.code == 200) { |
|||
username.value = res.data.user.name |
|||
} else { |
|||
console.log("获取用户信息失败") |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
onMounted(() => { |
|||
isLogin.value = !!localStorage.getItem('token') |
|||
getName() |
|||
}) |
|||
|
|||
const handleLogout = () => { |
|||
ElMessageBox.confirm('确定要退出当前账号吗?', '提示', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
}).then(() => { |
|||
localStorage.removeItem('token') |
|||
isLogin.value = false |
|||
ElMessage.success('登出成功') |
|||
router.push('/loginPage') |
|||
}) |
|||
} |
|||
</script> |
|||
<template> |
|||
<div class="portal-wrapper"> |
|||
<header class="navbar"> |
|||
<div class="brand">后台管理系统</div> |
|||
<div class="auth-area" :ref="userCard"> |
|||
<span v-show="isLogin">欢迎!{{username}}</span> |
|||
<el-button type="primary" @click="jumpLogin" :ref="loginButton" v-show="!isLogin">登录</el-button> |
|||
<el-button v-if="isLogin" type="danger" plain @click="handleLogout" :ref="logoutButton" v-show="isLogin">登出</el-button> |
|||
</div> |
|||
</header> |
|||
|
|||
<main class="portal-content"> |
|||
<div class="card-container"> |
|||
<div class="big-card" @click="router.push('/user')"> |
|||
<div class="icon-circle user-bg"> |
|||
<el-icon ><User /></el-icon> |
|||
</div> |
|||
<div class="info"> |
|||
<h3>查看用户</h3> |
|||
<p>管理系统成员与权限信息</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="big-card" @click="router.push('/courses')"> |
|||
<div class="icon-circle course-bg"> |
|||
<el-icon><Reading /></el-icon> |
|||
</div> |
|||
<div class="info"> |
|||
<h3>查看课程</h3> |
|||
<p>查询与排查教学课程进度</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.portal-wrapper { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
background-color: #f5f7fa; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.navbar { |
|||
height: 60px; |
|||
background: #fff; |
|||
padding: 0 40px; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
box-shadow: 0 2px 10px rgba(0,0,0,0.05); |
|||
} |
|||
|
|||
.brand { font-size: 18px; font-weight: bold; color: #409eff; } |
|||
|
|||
.auth-area { display: flex; gap: 12px; } |
|||
|
|||
.portal-content { |
|||
flex: 1; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.card-container { display: flex; gap: 30px; } |
|||
|
|||
/* 大卡片 */ |
|||
.big-card { |
|||
width: 300px; |
|||
padding: 40px 20px; |
|||
background: #fff; |
|||
border-radius: 16px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
cursor: pointer; |
|||
transition: all 0.3s; |
|||
border: 1px solid #e4e7ed; |
|||
} |
|||
|
|||
.big-card:hover { |
|||
transform: translateY(-10px); |
|||
box-shadow: 0 15px 30px rgba(0,0,0,0.1); |
|||
border-color: #409eff; |
|||
} |
|||
|
|||
/* 图标背景圆圈 */ |
|||
.icon-circle { |
|||
width: 80px; |
|||
height: 80px; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
font-size: 40px; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.user-bg { background-color: #ecf5ff; color: #409eff; } |
|||
.course-bg { background-color: #f0f9eb; color: #67c23a; } |
|||
|
|||
.info { text-align: center; } |
|||
.info h3 { margin: 0 0 10px 0; color: #303133; } |
|||
.info p { margin: 0; color: #909399; font-size: 14px; } |
|||
</style> |
|||
@ -0,0 +1,116 @@ |
|||
<template> |
|||
<div class="simple-login-container"> |
|||
<el-card style="width: 350px;" id="loginCard"> |
|||
<template #header> |
|||
<div style="text-align: center; font-weight: bold;">系统登录</div> |
|||
</template> |
|||
<el-form :model="loginForm" :rules="rules" ref="loginRef"> |
|||
<el-form-item prop="username"> |
|||
<el-input |
|||
v-model="loginForm.username" |
|||
placeholder="请输入用户名" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="password"> |
|||
<el-input |
|||
v-model="loginForm.password" |
|||
type="password" |
|||
placeholder="请输入密码" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
<el-button |
|||
type="primary" |
|||
style="width: 100%;" |
|||
@click="handleLogin" |
|||
> |
|||
登 录 |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-card> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, reactive } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import { ElMessage } from 'element-plus' |
|||
import service from '../api/service.ts' |
|||
import type { FormInstance } from 'element-plus' |
|||
|
|||
const router = useRouter() |
|||
const loginRef = ref<FormInstance>() |
|||
|
|||
const loginForm = reactive({ |
|||
username: '', |
|||
password: '' |
|||
}) |
|||
|
|||
const rules = { |
|||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], |
|||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }] |
|||
} |
|||
|
|||
const handleLogin = async () => { |
|||
if (!loginRef.value) return |
|||
|
|||
await loginRef.value.validate((valid) => { |
|||
if (valid) { |
|||
service.post("/login",loginForm).then(res=>{ |
|||
console.log(res) |
|||
if (res.code == 0){ |
|||
localStorage.setItem("token",res.data.token) |
|||
ElMessage.success("登录成功,3秒后跳转") |
|||
setTimeout(()=>{ |
|||
router.push("/") |
|||
},3000) |
|||
} |
|||
else if (res.code== 450) { |
|||
ElMessage.error("密码错误") |
|||
} |
|||
else if (res.code==451){ |
|||
ElMessage.error("用户名不存在") |
|||
} |
|||
else { |
|||
ElMessage.error("未知错误") |
|||
} |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 针对所有 Element Plus 图标,强行锁死大小,无视任何外部干扰 */ |
|||
:deep(.el-input__icon), |
|||
:deep(.el-icon), |
|||
:deep(svg) { |
|||
width: 1em !important; |
|||
height: 1em !important; |
|||
font-size: 16px !important; /* 眼睛图标的标准大小 */ |
|||
} |
|||
|
|||
/* 针对密码框那只“大眼睛”的专属镇压 */ |
|||
:deep(.el-input__password) { |
|||
width: 25px !important; |
|||
height: 25px !important; |
|||
display: flex !important; |
|||
align-items: center !important; |
|||
justify-content: center !important; |
|||
} |
|||
|
|||
/* 确保输入框本身不会被撑大 */ |
|||
:deep(.el-input__wrapper) { |
|||
padding: 1px 11px !important; |
|||
} |
|||
|
|||
#loginCard{ |
|||
position: absolute; |
|||
left: 40%; |
|||
height: 60%; |
|||
align-items: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,193 @@ |
|||
<template> |
|||
<div class="user-container"> |
|||
<el-card shadow="hover"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<el-form :inline="true" :model="searchForm" class="search-form"> |
|||
<el-form-item label="用户名"> |
|||
<el-input v-model="searchForm.name" placeholder="输入姓名搜索" clearable @clear="fetchUserList" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" icon="Search" @click="searchUsers">搜索</el-button> |
|||
<el-button type="success" icon="Plus" @click="handleAdd">新增用户</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
<el-button @click="fetchUserList" icon="Refresh">刷新</el-button> |
|||
</div> |
|||
</template> |
|||
|
|||
<el-table :data="userList" stripe style="width: 100%" v-loading="loading"> |
|||
<el-table-column prop="id" label="ID" width="80" /> |
|||
<el-table-column prop="name" label="用户名" /> |
|||
<el-table-column prop="property" label="权限等级" width="100" /> |
|||
<el-table-column prop="createAt" label="创建时间" /> |
|||
|
|||
<el-table-column label="操作" width="180" fixed="right"> |
|||
<template #default="scope"> |
|||
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button> |
|||
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-card> |
|||
|
|||
<el-dialog v-model="dialogVisible" :title="form.id ? '编辑用户' : '新增用户'" width="30%"> |
|||
<el-form :model="form" label-width="80px"> |
|||
<el-form-item label="用户名"> |
|||
<el-input v-model="form.name" /> |
|||
</el-form-item> |
|||
<el-form-item label="密码"> |
|||
<el-input v-model="form.pass" /> |
|||
</el-form-item> |
|||
<el-form-item label="权限等级"> |
|||
<el-input-number v-model="form.property" :min="1" :max="5" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<el-button @click="closeDialog">取消</el-button> |
|||
<el-button type="primary" @click="submitForm">确定</el-button> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import {ref, onMounted, reactive} from 'vue' |
|||
import service from '../api/service.js' // 确保这是你封装好的 axios 实例 |
|||
import { ElMessage } from 'element-plus' |
|||
|
|||
const userList = ref([]) |
|||
const loading = ref(false) |
|||
|
|||
// 获取用户列表 |
|||
const fetchUserList = async () => { |
|||
loading.value = true |
|||
try { |
|||
// 注意:这里的路径要对应你后端绑定的路由 |
|||
const res = await service.get('/getUsers') |
|||
|
|||
// GoFrame 规范路由通常返回 {code:0, data: { list: [], total: 0 }} |
|||
// 根据你后端的具体返回结构“剥壳” |
|||
if (res.code === 0 || res.code === 200) { |
|||
console.log(res.data) |
|||
userList.value = res.data.users |
|||
} else { |
|||
ElMessage.error(res.message || '获取数据失败') |
|||
} |
|||
} catch (error) { |
|||
console.error('Fetch Error:', error) |
|||
} finally { |
|||
loading.value = false |
|||
} |
|||
} |
|||
//面板可见度 |
|||
const dialogVisible =ref(false) |
|||
|
|||
//搜索 |
|||
const searchForm = reactive({ |
|||
name:"" |
|||
}) |
|||
|
|||
//区分添加还是编辑 |
|||
const addOrUpdate =ref(false) |
|||
|
|||
//添加 |
|||
const handleAdd=()=>{ |
|||
dialogVisible.value=true |
|||
addOrUpdate.value=false |
|||
} |
|||
|
|||
const form =reactive({ |
|||
id:0, |
|||
name:"", |
|||
property:0, |
|||
pass:"", |
|||
}) |
|||
|
|||
|
|||
|
|||
//编辑 |
|||
const handleEdit = (row: any) => { |
|||
addOrUpdate.value=true |
|||
dialogVisible.value = true |
|||
form.id = row.id |
|||
form.name = row.name |
|||
form.property = row.property |
|||
} |
|||
|
|||
//删除 |
|||
const handleDelete=(row: any)=>{ |
|||
service.delete("/admin/user/delete",{params:{id:row.id}}).then(res=>{ |
|||
if (res.code==200||res.code==0){ |
|||
ElMessage.success("删除用户成功") |
|||
fetchUserList() |
|||
} |
|||
else { |
|||
ElMessage.error(res.message) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
//保存编辑 |
|||
const submitForm=()=>{ |
|||
service.post("/admin/user/editUser",form).then( |
|||
res=>{ |
|||
console.log(res) |
|||
if (res.code===0||res.code===200){ |
|||
if (addOrUpdate.value){ |
|||
ElMessage.success("更新成功") |
|||
} |
|||
else { |
|||
ElMessage.success("添加成功") |
|||
} |
|||
form.id = 0 |
|||
form.name = "" |
|||
form.property = 0 |
|||
form.pass="" |
|||
fetchUserList() |
|||
dialogVisible.value=false |
|||
} |
|||
else { |
|||
ElMessage.error(res.message) |
|||
} |
|||
} |
|||
) |
|||
} |
|||
|
|||
const searchUsers=()=>{ |
|||
service.get("/admin/user/search",{params:{keyword:searchForm.name}}).then( |
|||
res=>{ |
|||
if (res.code==0||res.code==200){ |
|||
userList.value=res.data.users |
|||
} |
|||
else { |
|||
ElMessage.error(res.message) |
|||
} |
|||
} |
|||
) |
|||
} |
|||
|
|||
|
|||
onMounted(() => { |
|||
fetchUserList() |
|||
}) |
|||
|
|||
//关闭窗口 |
|||
const closeDialog=()=>{ |
|||
dialogVisible.value=false |
|||
form.id=0 |
|||
form.name="" |
|||
form.property=0 |
|||
form.pass="" |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.user-container { |
|||
padding: 20px; |
|||
} |
|||
.card-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,21 @@ |
|||
import { createApp } from 'vue' |
|||
import { createPinia } from 'pinia' |
|||
|
|||
import App from './App.vue' |
|||
import router from './router' |
|||
import ElementUiPlus from 'element-plus' |
|||
import 'element-plus/dist/index.css' |
|||
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
|||
|
|||
|
|||
|
|||
const app = createApp(App) |
|||
|
|||
app.use(ElementUiPlus) |
|||
app.use(createPinia()) |
|||
// 全局注册所有图标
|
|||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
|||
app.component(key, component) |
|||
} |
|||
app.use(router).mount('#app') |
|||
|
|||
@ -0,0 +1,20 @@ |
|||
import { createRouter, createWebHistory } from 'vue-router' |
|||
import LoginPage from "@/components/LoginPage.vue"; |
|||
import Home from "@/components/Home.vue"; |
|||
import User from "@/components/User.vue"; |
|||
|
|||
const router = createRouter({ |
|||
history: createWebHistory(import.meta.env.BASE_URL), |
|||
routes: [{ |
|||
path:"/loginPage", |
|||
component:LoginPage |
|||
}, |
|||
{ |
|||
path:"/", |
|||
component:Home |
|||
}, |
|||
{path:"/user", |
|||
component:User}], |
|||
}) |
|||
|
|||
export default router |
|||
@ -0,0 +1,12 @@ |
|||
import { ref, computed } from 'vue' |
|||
import { defineStore } from 'pinia' |
|||
|
|||
export const useCounterStore = defineStore('counter', () => { |
|||
const count = ref(0) |
|||
const doubleCount = computed(() => count.value * 2) |
|||
function increment() { |
|||
count.value++ |
|||
} |
|||
|
|||
return { count, doubleCount, increment } |
|||
}) |
|||
@ -0,0 +1,18 @@ |
|||
{ |
|||
"extends": "@vue/tsconfig/tsconfig.dom.json", |
|||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"], |
|||
"exclude": ["src/**/__tests__/*"], |
|||
"compilerOptions": { |
|||
// Extra safety for array and object lookups, but may have false positives. |
|||
"noUncheckedIndexedAccess": true, |
|||
|
|||
// Path mapping for cleaner imports. |
|||
"paths": { |
|||
"@/*": ["./src/*"] |
|||
}, |
|||
|
|||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. |
|||
// Specified here to keep it out of the root directory. |
|||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
{ |
|||
"files": [], |
|||
"references": [ |
|||
{ |
|||
"path": "./tsconfig.node.json" |
|||
}, |
|||
{ |
|||
"path": "./tsconfig.app.json" |
|||
}, |
|||
{ |
|||
"path": "./tsconfig.vitest.json" |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping. |
|||
{ |
|||
"extends": "@tsconfig/node24/tsconfig.json", |
|||
"include": [ |
|||
"vite.config.*", |
|||
"vitest.config.*", |
|||
"cypress.config.*", |
|||
"playwright.config.*", |
|||
"eslint.config.*" |
|||
], |
|||
"compilerOptions": { |
|||
// Most tools use transpilation instead of Node.js's native type-stripping. |
|||
// Bundler mode provides a smoother developer experience. |
|||
"module": "preserve", |
|||
"moduleResolution": "bundler", |
|||
|
|||
// Include Node.js types and avoid accidentally including other `@types/*` packages. |
|||
"types": ["node"], |
|||
|
|||
// Disable emitting output during `vue-tsc --build`, which is used for type-checking only. |
|||
"noEmit": true, |
|||
|
|||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. |
|||
// Specified here to keep it out of the root directory. |
|||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
{ |
|||
"extends": "./tsconfig.app.json", |
|||
|
|||
// Override to include only test files and clear exclusions. |
|||
// Application code imported in tests is automatically included via module resolution. |
|||
"include": ["src/**/__tests__/*", "env.d.ts"], |
|||
"exclude": [], |
|||
|
|||
"compilerOptions": { |
|||
// Vitest runs in a different environment than the application code. |
|||
// Adjust lib and types accordingly. |
|||
"lib": [], |
|||
"types": ["node", "jsdom"], |
|||
|
|||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. |
|||
// Specified here to keep it out of the root directory. |
|||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo" |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
import { fileURLToPath, URL } from 'node:url' |
|||
|
|||
import { defineConfig } from 'vite' |
|||
import vue from '@vitejs/plugin-vue' |
|||
import vueJsx from '@vitejs/plugin-vue-jsx' |
|||
import vueDevTools from 'vite-plugin-vue-devtools' |
|||
|
|||
// https://vite.dev/config/
|
|||
export default defineConfig({ |
|||
plugins: [ |
|||
vue(), |
|||
vueJsx(), |
|||
vueDevTools(), |
|||
],server:{ |
|||
port:5173, |
|||
proxy:{ |
|||
'/api':{ |
|||
target:"http://localhost:8000", |
|||
changeOrigin:true, |
|||
rewrite:(path)=>path.replace(/^\/api/,'') |
|||
} |
|||
} |
|||
}, |
|||
resolve: { |
|||
alias: { |
|||
'@': fileURLToPath(new URL('./src', import.meta.url)) |
|||
}, |
|||
}, |
|||
}) |
|||
@ -0,0 +1,14 @@ |
|||
import { fileURLToPath } from 'node:url' |
|||
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' |
|||
import viteConfig from './vite.config' |
|||
|
|||
export default mergeConfig( |
|||
viteConfig, |
|||
defineConfig({ |
|||
test: { |
|||
environment: 'jsdom', |
|||
exclude: [...configDefaults.exclude, 'e2e/**'], |
|||
root: fileURLToPath(new URL('./', import.meta.url)), |
|||
}, |
|||
}), |
|||
) |
|||
@ -0,0 +1,63 @@ |
|||
## 技术方面 |
|||
|
|||
写了一个vue3+Goframe的demo |
|||
|
|||
目前是有用户一个表,有对用户增删改查的功能, |
|||
|
|||
有按名称模糊搜索用户的功能,在主页上显示当前用户用户名的功能 |
|||
|
|||
用token+响应请求拦截器进行登录检验,逻辑如下: |
|||
|
|||
绑定了一个token中间件,当前端向后端发起请求时,若请求接口非/login会尝试从请求头提取"Authorization"参数检验token合法性,若token不合法(加密方式错误、解析失败、解析出的用户信息不存在),直接返回错误,前端响应拦截器接收到此错误时会跳转到登录页。如果token合法,将token对应的用户信息直接存到上下文里以便后续调用不用重复请求数据库 |
|||
|
|||
在增删改操作时开启了事务,并进行了数据合法性校验(如密码不得低于6位,用户名不可重复不可为空等) |
|||
|
|||
对密码进行了Bcrpt加密,删除用户使用软删除 |
|||
|
|||
后续会增加对Course表的操作和更多功能 |
|||
|
|||
## 股票相关 |
|||
|
|||
#### 1. 基本面分析 (Fundamental Analysis) |
|||
|
|||
**核心逻辑**:价值决定价格。 |
|||
|
|||
**分析维度**: |
|||
|
|||
**宏观**:全球及国内经济形势、政策走向。 |
|||
|
|||
**行业**:行业前景、景气度。 |
|||
|
|||
**公司**:财务状况、管理层素质、投资方向、每股收益(EPS)。 |
|||
|
|||
**目标**:评估公司内在价值,做中长期投资决策。 |
|||
|
|||
#### 2. 技术分析 (Technical Analysis) |
|||
|
|||
**核心逻辑**:供求决定价格。 |
|||
|
|||
**三大公理**: |
|||
|
|||
1. **市场行为包容消化一切**(核心要素:价格、成交量、时间、参与人)。 |
|||
|
|||
2. **价格以趋势方式运行**: |
|||
|
|||
**方向**:上升、下降、横盘。 |
|||
|
|||
**周期**:短期(6-10天)、中期(数周至数月)、长期(一年以上)。 |
|||
|
|||
3. **历史会不断重演**:虽然不是简单重复,但规律相似。 |
|||
|
|||
#### 交易优先原则 |
|||
|
|||
**价格优先**:买入报单价高者优先,卖出报单价低者优先。 |
|||
|
|||
**时间优先**:同价位时,先申报者优先。 |
|||
|
|||
#### A股交易规则 (重点) |
|||
|
|||
**交易时间**(周一至周五,法定节假日休息): |
|||
|
|||
**上午**:9:15-9:25(集合竞价,其中9:20后不可撤单);9:30-11:30(连续竞价)。 |
|||
|
|||
**下午**:13:00-14:57(连续竞价);14:57-15:00(收盘集合竞价)。 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue