Browse Source

Merge branch 'zhouxinzhong/feature-20260327150147-学习笔记' into milestone-20260325-学习笔记

milestone-20260325-学习笔记
zhouxinzhong 2 weeks ago
parent
commit
9c53f8a0a5
  1. 1
      周新忠学习笔记/4.1/gf_demo_02/.gitattributes
  2. 19
      周新忠学习笔记/4.1/gf_demo_02/.gitignore
  3. 7
      周新忠学习笔记/4.1/gf_demo_02/Makefile
  4. 6
      周新忠学习笔记/4.1/gf_demo_02/README.MD
  5. 57
      周新忠学习笔记/4.1/gf_demo_02/api/user/v1/user.go
  6. 38
      周新忠学习笔记/4.1/gf_demo_02/go.mod
  7. 70
      周新忠学习笔记/4.1/gf_demo_02/go.sum
  8. 13
      周新忠学习笔记/4.1/gf_demo_02/hack/config.yaml
  9. 20
      周新忠学习笔记/4.1/gf_demo_02/hack/hack-cli.mk
  10. 75
      周新忠学习笔记/4.1/gf_demo_02/hack/hack.mk
  11. 30
      周新忠学习笔记/4.1/gf_demo_02/internal/cmd/cmd.go
  12. 3
      周新忠学习笔记/4.1/gf_demo_02/internal/consts/consts.go
  13. 98
      周新忠学习笔记/4.1/gf_demo_02/internal/controller/user/user.go
  14. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/.gitkeep
  15. 27
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/course.go
  16. 83
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/course.go
  17. 83
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/stock.go
  18. 85
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user.go
  19. 75
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user_course.go
  20. 27
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/stock.go
  21. 27
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/user.go
  22. 27
      周新忠学习笔记/4.1/gf_demo_02/internal/dao/user_course.go
  23. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/logic/.gitkeep
  24. 12
      周新忠学习笔记/4.1/gf_demo_02/internal/logic/course/course.go
  25. 9
      周新忠学习笔记/4.1/gf_demo_02/internal/logic/logic.go
  26. 143
      周新忠学习笔记/4.1/gf_demo_02/internal/logic/user/user.go
  27. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/model/.gitkeep
  28. 9
      周新忠学习笔记/4.1/gf_demo_02/internal/model/claim.go
  29. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/model/do/.gitkeep
  30. 21
      周新忠学习笔记/4.1/gf_demo_02/internal/model/do/course.go
  31. 21
      周新忠学习笔记/4.1/gf_demo_02/internal/model/do/stock.go
  32. 22
      周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user.go
  33. 16
      周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user_course.go
  34. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/.gitkeep
  35. 19
      周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/course.go
  36. 19
      周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/stock.go
  37. 20
      周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user.go
  38. 11
      周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user_course.go
  39. 16
      周新忠学习笔记/4.1/gf_demo_02/internal/model/models.go
  40. 1
      周新忠学习笔记/4.1/gf_demo_02/internal/packed/packed.go
  41. 0
      周新忠学习笔记/4.1/gf_demo_02/internal/service/.gitkeep
  42. 65
      周新忠学习笔记/4.1/gf_demo_02/internal/service/JWTMiddleware.go
  43. 21
      周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass.go
  44. 7
      周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass_test.go
  45. 40
      周新忠学习笔记/4.1/gf_demo_02/internal/service/user.go
  46. BIN
      周新忠学习笔记/4.1/gf_demo_02/main.exe~
  47. 17
      周新忠学习笔记/4.1/gf_demo_02/main.go
  48. 21
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/deployment.yaml
  49. 8
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/kustomization.yaml
  50. 12
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/service.yaml
  51. 14
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/configmap.yaml
  52. 10
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/deployment.yaml
  53. 14
      周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/kustomization.yaml
  54. 16
      周新忠学习笔记/4.1/gf_demo_02/manifest/docker/Dockerfile
  55. 8
      周新忠学习笔记/4.1/gf_demo_02/manifest/docker/docker.sh
  56. 0
      周新忠学习笔记/4.1/gf_demo_02/manifest/i18n/.gitkeep
  57. 0
      周新忠学习笔记/4.1/gf_demo_02/manifest/protobuf/.keep-if-necessary
  58. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/public/html/.gitkeep
  59. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/public/plugin/.gitkeep
  60. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/css/.gitkeep
  61. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/image/.gitkeep
  62. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/public/resource/js/.gitkeep
  63. 0
      周新忠学习笔记/4.1/gf_demo_02/resource/template/.gitkeep
  64. 0
      周新忠学习笔记/4.1/gf_demo_02/utility/.gitkeep
  65. 8
      周新忠学习笔记/4.1/vue_prj/.editorconfig
  66. 1
      周新忠学习笔记/4.1/vue_prj/.gitattributes
  67. 42
      周新忠学习笔记/4.1/vue_prj/.gitignore
  68. 10
      周新忠学习笔记/4.1/vue_prj/.oxlintrc.json
  69. 6
      周新忠学习笔记/4.1/vue_prj/.prettierrc.json
  70. 11
      周新忠学习笔记/4.1/vue_prj/.vscode/extensions.json
  71. 73
      周新忠学习笔记/4.1/vue_prj/README.md
  72. 4
      周新忠学习笔记/4.1/vue_prj/e2e/tsconfig.json
  73. 8
      周新忠学习笔记/4.1/vue_prj/e2e/vue.spec.ts
  74. 1
      周新忠学习笔记/4.1/vue_prj/env.d.ts
  75. 38
      周新忠学习笔记/4.1/vue_prj/eslint.config.ts
  76. 13
      周新忠学习笔记/4.1/vue_prj/index.html
  77. 7739
      周新忠学习笔记/4.1/vue_prj/package-lock.json
  78. 60
      周新忠学习笔记/4.1/vue_prj/package.json
  79. 110
      周新忠学习笔记/4.1/vue_prj/playwright.config.ts
  80. BIN
      周新忠学习笔记/4.1/vue_prj/public/favicon.ico
  81. 3
      周新忠学习笔记/4.1/vue_prj/src/App.vue
  82. 11
      周新忠学习笔记/4.1/vue_prj/src/__tests__/App.spec.ts
  83. 32
      周新忠学习笔记/4.1/vue_prj/src/api/service.ts
  84. 156
      周新忠学习笔记/4.1/vue_prj/src/components/Home.vue
  85. 116
      周新忠学习笔记/4.1/vue_prj/src/components/LoginPage.vue
  86. 193
      周新忠学习笔记/4.1/vue_prj/src/components/User.vue
  87. 21
      周新忠学习笔记/4.1/vue_prj/src/main.ts
  88. 20
      周新忠学习笔记/4.1/vue_prj/src/router/index.ts
  89. 12
      周新忠学习笔记/4.1/vue_prj/src/stores/counter.ts
  90. 18
      周新忠学习笔记/4.1/vue_prj/tsconfig.app.json
  91. 14
      周新忠学习笔记/4.1/vue_prj/tsconfig.json
  92. 27
      周新忠学习笔记/4.1/vue_prj/tsconfig.node.json
  93. 19
      周新忠学习笔记/4.1/vue_prj/tsconfig.vitest.json
  94. 29
      周新忠学习笔记/4.1/vue_prj/vite.config.ts
  95. 14
      周新忠学习笔记/4.1/vue_prj/vitest.config.ts
  96. 63
      周新忠学习笔记/4.1/周新忠4月1日学习笔记.md

1
周新忠学习笔记/4.1/gf_demo_02/.gitattributes

@ -0,0 +1 @@
* linguist-language=GO

19
周新忠学习笔记/4.1/gf_demo_02/.gitignore

@ -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

7
周新忠学习笔记/4.1/gf_demo_02/Makefile

@ -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

6
周新忠学习笔记/4.1/gf_demo_02/README.MD

@ -0,0 +1,6 @@
# GoFrame Template For SingleRepo
Quick Start:
- https://goframe.org/quick
没做规范化处理目前!!

57
周新忠学习笔记/4.1/gf_demo_02/api/user/v1/user.go

@ -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"`
}

38
周新忠学习笔记/4.1/gf_demo_02/go.mod

@ -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
)

70
周新忠学习笔记/4.1/gf_demo_02/go.sum

@ -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=

13
周新忠学习笔记/4.1/gf_demo_02/hack/config.yaml

@ -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

20
周新忠学习笔记/4.1/gf_demo_02/hack/hack-cli.mk

@ -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;

75
周新忠学习笔记/4.1/gf_demo_02/hack/hack.mk

@ -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

30
周新忠学习笔记/4.1/gf_demo_02/internal/cmd/cmd.go

@ -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
},
}
)

3
周新忠学习笔记/4.1/gf_demo_02/internal/consts/consts.go

@ -0,0 +1,3 @@
package consts
const TOKEN_KEY = "55558888"

98
周新忠学习笔记/4.1/gf_demo_02/internal/controller/user/user.go

@ -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
周新忠学习笔记/4.1/gf_demo_02/internal/dao/.gitkeep

27
周新忠学习笔记/4.1/gf_demo_02/internal/dao/course.go

@ -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.

83
周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/course.go

@ -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)
}

83
周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/stock.go

@ -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)
}

85
周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user.go

@ -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)
}

75
周新忠学习笔记/4.1/gf_demo_02/internal/dao/internal/user_course.go

@ -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)
}

27
周新忠学习笔记/4.1/gf_demo_02/internal/dao/stock.go

@ -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.

27
周新忠学习笔记/4.1/gf_demo_02/internal/dao/user.go

@ -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.

27
周新忠学习笔记/4.1/gf_demo_02/internal/dao/user_course.go

@ -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
周新忠学习笔记/4.1/gf_demo_02/internal/logic/.gitkeep

12
周新忠学习笔记/4.1/gf_demo_02/internal/logic/course/course.go

@ -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()
}

9
周新忠学习笔记/4.1/gf_demo_02/internal/logic/logic.go

@ -0,0 +1,9 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package logic
import (
_ "gf_demo_02/internal/logic/user"
)

143
周新忠学习笔记/4.1/gf_demo_02/internal/logic/user/user.go

@ -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
周新忠学习笔记/4.1/gf_demo_02/internal/model/.gitkeep

9
周新忠学习笔记/4.1/gf_demo_02/internal/model/claim.go

@ -0,0 +1,9 @@
package model
import "github.com/golang-jwt/jwt/v5"
type UserClaim struct {
UserId uint
UserName string
jwt.RegisteredClaims
}

0
周新忠学习笔记/4.1/gf_demo_02/internal/model/do/.gitkeep

21
周新忠学习笔记/4.1/gf_demo_02/internal/model/do/course.go

@ -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 //
}

21
周新忠学习笔记/4.1/gf_demo_02/internal/model/do/stock.go

@ -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 //
}

22
周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user.go

@ -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 //
}

16
周新忠学习笔记/4.1/gf_demo_02/internal/model/do/user_course.go

@ -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
周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/.gitkeep

19
周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/course.go

@ -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" ` //
}

19
周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/stock.go

@ -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" ` //
}

20
周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user.go

@ -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" ` //
}

11
周新忠学习笔记/4.1/gf_demo_02/internal/model/entity/user_course.go

@ -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" ` //
}

16
周新忠学习笔记/4.1/gf_demo_02/internal/model/models.go

@ -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"`
}

1
周新忠学习笔记/4.1/gf_demo_02/internal/packed/packed.go

@ -0,0 +1 @@
package packed

0
周新忠学习笔记/4.1/gf_demo_02/internal/service/.gitkeep

65
周新忠学习笔记/4.1/gf_demo_02/internal/service/JWTMiddleware.go

@ -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()
}

21
周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass.go

@ -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")
}

7
周新忠学习笔记/4.1/gf_demo_02/internal/service/encode_pass_test.go

@ -0,0 +1,7 @@
package service
import "testing"
func TestEncode(T *testing.T) {
encode()
}

40
周新忠学习笔记/4.1/gf_demo_02/internal/service/user.go

@ -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
}

BIN
周新忠学习笔记/4.1/gf_demo_02/main.exe~

17
周新忠学习笔记/4.1/gf_demo_02/main.go

@ -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())
}

21
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/deployment.yaml

@ -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

8
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/kustomization.yaml

@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

12
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/base/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

14
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/configmap.yaml

@ -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

10
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/deployment.yaml

@ -0,0 +1,10 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: template-single
spec:
template:
spec:
containers:
- name : main
image: template-single:develop

14
周新忠学习笔记/4.1/gf_demo_02/manifest/deploy/kustomize/overlays/develop/kustomization.yaml

@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- configmap.yaml
patchesStrategicMerge:
- deployment.yaml
namespace: default

16
周新忠学习笔记/4.1/gf_demo_02/manifest/docker/Dockerfile

@ -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

8
周新忠学习笔记/4.1/gf_demo_02/manifest/docker/docker.sh

@ -0,0 +1,8 @@
#!/bin/bash
# This shell is executed before docker build.

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

@ -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

1
周新忠学习笔记/4.1/vue_prj/.gitattributes

@ -0,0 +1 @@
* text=auto eol=lf

42
周新忠学习笔记/4.1/vue_prj/.gitignore

@ -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/

10
周新忠学习笔记/4.1/vue_prj/.oxlintrc.json

@ -0,0 +1,10 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "unicorn", "oxc", "vue", "vitest"],
"env": {
"browser": true
},
"categories": {
"correctness": "error"
}
}

6
周新忠学习笔记/4.1/vue_prj/.prettierrc.json

@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
}

11
周新忠学习笔记/4.1/vue_prj/.vscode/extensions.json

@ -0,0 +1,11 @@
{
"recommendations": [
"Vue.volar",
"vitest.explorer",
"ms-playwright.playwright",
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"oxc.oxc-vscode",
"esbenp.prettier-vscode"
]
}

73
周新忠学习笔记/4.1/vue_prj/README.md

@ -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
```

4
周新忠学习笔记/4.1/vue_prj/e2e/tsconfig.json

@ -0,0 +1,4 @@
{
"extends": "@tsconfig/node24/tsconfig.json",
"include": ["./**/*"]
}

8
周新忠学习笔记/4.1/vue_prj/e2e/vue.spec.ts

@ -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!')
})

1
周新忠学习笔记/4.1/vue_prj/env.d.ts

@ -0,0 +1 @@
/// <reference types="vite/client" />

38
周新忠学习笔记/4.1/vue_prj/eslint.config.ts

@ -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,
)

13
周新忠学习笔记/4.1/vue_prj/index.html

@ -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

60
周新忠学习笔记/4.1/vue_prj/package.json

@ -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"
}
}

110
周新忠学习笔记/4.1/vue_prj/playwright.config.ts

@ -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,
},
})

BIN
周新忠学习笔记/4.1/vue_prj/public/favicon.ico

3
周新忠学习笔记/4.1/vue_prj/src/App.vue

@ -0,0 +1,3 @@
<template>
<router-view />
</template>

11
周新忠学习笔记/4.1/vue_prj/src/__tests__/App.spec.ts

@ -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!')
})
})

32
周新忠学习笔记/4.1/vue_prj/src/api/service.ts

@ -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

156
周新忠学习笔记/4.1/vue_prj/src/components/Home.vue

@ -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>

116
周新忠学习笔记/4.1/vue_prj/src/components/LoginPage.vue

@ -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>

193
周新忠学习笔记/4.1/vue_prj/src/components/User.vue

@ -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>

21
周新忠学习笔记/4.1/vue_prj/src/main.ts

@ -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')

20
周新忠学习笔记/4.1/vue_prj/src/router/index.ts

@ -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

12
周新忠学习笔记/4.1/vue_prj/src/stores/counter.ts

@ -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 }
})

18
周新忠学习笔记/4.1/vue_prj/tsconfig.app.json

@ -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"
}
}

14
周新忠学习笔记/4.1/vue_prj/tsconfig.json

@ -0,0 +1,14 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.vitest.json"
}
]
}

27
周新忠学习笔记/4.1/vue_prj/tsconfig.node.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"
}
}

19
周新忠学习笔记/4.1/vue_prj/tsconfig.vitest.json

@ -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"
}
}

29
周新忠学习笔记/4.1/vue_prj/vite.config.ts

@ -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))
},
},
})

14
周新忠学习笔记/4.1/vue_prj/vitest.config.ts

@ -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)),
},
}),
)

63
周新忠学习笔记/4.1/周新忠4月1日学习笔记.md

@ -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(收盘集合竞价)。
Loading…
Cancel
Save