mirror of
https://github.com/flipped-aurora/gin-vue-admin.git
synced 2026-09-25 05:50:19 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23952c5f5f | ||
|
|
02fc5036d7 | ||
|
|
a6a65ed9f4 | ||
|
|
369f657aa6 | ||
|
|
1801e5b30f | ||
|
|
b10d5103f3 | ||
|
|
9964bfef8b | ||
|
|
9945a19f2c | ||
|
|
a5d43e6f14 | ||
|
|
b61b9a06dd | ||
|
|
f28570fa98 | ||
|
|
fb53d639be | ||
|
|
42de9257c3 | ||
|
|
0fba597a61 | ||
|
|
d0393c4e9f | ||
|
|
a21d2a591e | ||
|
|
de54688c56 | ||
|
|
3c486d9117 | ||
|
|
e8128250f4 | ||
|
|
58a1b72910 | ||
|
|
ee00d29afd | ||
|
|
5cfcc538a8 | ||
|
|
e7c8a9d420 | ||
|
|
6b07ffe8f7 | ||
|
|
0d17340445 | ||
|
|
2a0b92713b | ||
|
|
fb22eb4178 | ||
|
|
136fb2f394 | ||
|
|
c515805f0a | ||
|
|
613ba9ba20 | ||
|
|
f6314d3581 | ||
|
|
043f5c78c2 | ||
|
|
0f9e519b0e | ||
|
|
0d17a2351f | ||
|
|
1b388664cb | ||
|
|
1edb0c529f | ||
|
|
f07a58bff4 | ||
|
|
c054840aec | ||
|
|
e259418398 | ||
|
|
df1d68a724 | ||
|
|
9d58390e11 | ||
|
|
db4c7a8bda | ||
|
|
ab163fc0ef | ||
|
|
0265801830 | ||
|
|
5fa7bbbc0f | ||
|
|
e15351e1c5 | ||
|
|
5eb0133b5c | ||
|
|
ff8344d671 | ||
|
|
d9a43ea1d6 | ||
|
|
6c62d73afb | ||
|
|
d23d6c342a | ||
|
|
90549a09e1 | ||
|
|
17d3639443 | ||
|
|
e8a096b8fe | ||
|
|
fea136e513 | ||
|
|
f3a4095462 | ||
|
|
d7d25cf69b | ||
|
|
3b33fe83e6 | ||
|
|
56f4d223ab | ||
|
|
c07317a619 | ||
|
|
4798f7688b | ||
|
|
24db0eb5aa | ||
|
|
1ece13c43d | ||
|
|
48268309b9 | ||
|
|
4074a52b1b | ||
|
|
61dd524c26 | ||
|
|
61a678a318 | ||
|
|
8ecec6a14f | ||
|
|
e3f8b8a394 | ||
|
|
eebddbafcc | ||
|
|
50cbce0f7a | ||
|
|
f9974a8971 | ||
|
|
baa48a1679 | ||
|
|
032910f87a | ||
|
|
773ef95b70 | ||
|
|
18c2f84771 | ||
|
|
ea721a71b5 | ||
|
|
b1b7427c6e | ||
|
|
7bc7c30510 | ||
|
|
d1e055430d | ||
|
|
736534379a | ||
|
|
f6b71e157c | ||
|
|
53e9f931f2 | ||
|
|
c226a9476f | ||
|
|
8ca5600286 | ||
|
|
9729bc00a0 | ||
|
|
f9c9af8261 | ||
|
|
c9e64373fb | ||
|
|
262febf486 | ||
|
|
eca9c4d7f8 | ||
|
|
a20083bb9c | ||
|
|
d31b01415b | ||
|
|
26cdb472f0 | ||
|
|
3c2595aaf9 | ||
|
|
ad323a0dff | ||
|
|
9a0417b1a7 | ||
|
|
3324a816ee | ||
|
|
cc4135a2d7 | ||
|
|
2d884c83cc | ||
|
|
619c5b5e1d | ||
|
|
33afa9adfc | ||
|
|
0c141cc6f7 | ||
|
|
efdff2ab0c | ||
|
|
ebefb0eba4 | ||
|
|
d4b9c2c97b | ||
|
|
d4db16b501 | ||
|
|
a5cbd7387b | ||
|
|
99d6b4a361 | ||
|
|
18365689e6 | ||
|
|
8ea827412a | ||
|
|
4d8979c4ad | ||
|
|
236357baa8 | ||
|
|
5ef4b21858 | ||
|
|
3b3441851c | ||
|
|
5517987e14 | ||
|
|
7e98f61bec | ||
|
|
e2d360e8b1 | ||
|
|
57cfedfd7c | ||
|
|
50b1d21d13 | ||
|
|
7b79ec6c66 | ||
|
|
7a5b31530f | ||
|
|
e9100a9542 | ||
|
|
421304d4a3 | ||
|
|
10d61bbbb3 | ||
|
|
095709fb19 | ||
|
|
725f4150fc | ||
|
|
93ac2e70d2 | ||
|
|
f4c2b50ca5 | ||
|
|
3354edbb1c | ||
|
|
d3600499af | ||
|
|
35e2c2cfe8 | ||
|
|
1e4970469f | ||
|
|
4cbfd7c9b1 | ||
|
|
deb32fa0fa | ||
|
|
f17a738780 | ||
|
|
2f53d0efae | ||
|
|
3e43c2e6e6 | ||
|
|
96919a9f79 | ||
|
|
a23fb627cd | ||
|
|
aae915b092 | ||
|
|
160c8e814b | ||
|
|
88f48baba1 | ||
|
|
7835efbf37 | ||
|
|
455fbb505e | ||
|
|
df3f7090e8 | ||
|
|
632b3c200c | ||
|
|
5b203326ae | ||
|
|
fd87aca57d | ||
|
|
b9b7e556e3 | ||
|
|
5b9a7e6a2a | ||
|
|
d278e19367 | ||
|
|
342030ca47 | ||
|
|
f90e241cc9 | ||
|
|
ff6bcc437c | ||
|
|
e32dbb5125 | ||
|
|
06701cc7d1 | ||
|
|
ccb31bc1b4 | ||
|
|
7e2e29e2e8 | ||
|
|
0c76995f6d | ||
|
|
17cab8fcb7 | ||
|
|
d64753859d | ||
|
|
48b1c24c95 | ||
|
|
7e5e12b139 | ||
|
|
59ba4752c0 | ||
|
|
189219c673 | ||
|
|
4b54262edd | ||
|
|
458b035a7e | ||
|
|
abe85cf6e7 | ||
|
|
379b63275a | ||
|
|
07cde689b1 | ||
|
|
26606f138d | ||
|
|
24c4774f7e | ||
|
|
6bbb4f577e | ||
|
|
4890de5052 | ||
|
|
746af37899 | ||
|
|
0136ce7034 | ||
|
|
5ca47a91a6 | ||
|
|
d849df41be | ||
|
|
a2269bcdd5 | ||
|
|
d41394c70a | ||
|
|
756f73bbd2 | ||
|
|
95eb17b6d1 | ||
|
|
773fd1f221 | ||
|
|
c95b436680 | ||
|
|
3f47151678 | ||
|
|
dbf1e7136c | ||
|
|
84b44eef91 | ||
|
|
686ada1e49 | ||
|
|
d9f6bc058a | ||
|
|
6f531793f0 | ||
|
|
f8794bef5f | ||
|
|
9daf103669 | ||
|
|
26fa047fe4 | ||
|
|
1a04bb535d | ||
|
|
ad41b7b434 | ||
|
|
6791b1dbdc | ||
|
|
dc1b84130c | ||
|
|
e70a933090 | ||
|
|
08617f2fd4 | ||
|
|
8aefb5db8e | ||
|
|
e1d214b91a | ||
|
|
0285de50e5 | ||
|
|
5f7caa0535 | ||
|
|
df9d2bc472 | ||
|
|
a923b6beca | ||
|
|
760ef77593 | ||
|
|
64f703856e | ||
|
|
36eba36bf2 | ||
|
|
332176a619 | ||
|
|
cd5b60c8cc | ||
|
|
5ea8947fc9 | ||
|
|
474a5c8e42 | ||
|
|
952062d5be | ||
|
|
c071564de4 | ||
|
|
b2fa7563d3 | ||
|
|
22f68fedcb | ||
|
|
0a4cda26cb | ||
|
|
54eb84e690 | ||
|
|
5cd33814fc | ||
|
|
90f19679e7 | ||
|
|
38ade9e498 | ||
|
|
4c77831001 | ||
|
|
722fe556e3 | ||
|
|
98b83c0078 | ||
|
|
85646b5ffa | ||
|
|
d3f5ed7d60 | ||
|
|
e0a8e93704 | ||
|
|
3aab5e9eb7 | ||
|
|
2307ac88cb | ||
|
|
0f2018d913 | ||
|
|
8b9a75ba5a | ||
|
|
7872e0ce38 | ||
|
|
d28ac73987 | ||
|
|
2c8c7a8b51 | ||
|
|
f98fc6bf3c | ||
|
|
d42958734f | ||
|
|
6f2c785713 | ||
|
|
05a1ce51f0 | ||
|
|
58b063770d | ||
|
|
6f9a83709d | ||
|
|
bd2a3ddfba | ||
|
|
4433b6623e | ||
|
|
e1ca17637f | ||
|
|
5ef0e43312 | ||
|
|
aa6ca95f13 | ||
|
|
2523467c97 | ||
|
|
b38eb6709e | ||
|
|
f6dacdb046 | ||
|
|
cc0903f74d | ||
|
|
72936fc0d1 | ||
|
|
4b7f552885 | ||
|
|
9b2fc60d79 | ||
|
|
3e5a26b95a | ||
|
|
a5f3139784 | ||
|
|
9ca9fcdb09 | ||
|
|
913db35b23 | ||
|
|
8eba3ba4f7 | ||
|
|
5bd0f24a84 | ||
|
|
e8fb3180db | ||
|
|
232aaad090 | ||
|
|
b3dbb8d4be | ||
|
|
3caf070056 | ||
|
|
1e24bbc3e2 | ||
|
|
18694fd24a | ||
|
|
10dc003f20 | ||
|
|
809e2496c0 | ||
|
|
c1c37901b5 | ||
|
|
44e115f211 | ||
|
|
217cc338a8 | ||
|
|
81eccc177d | ||
|
|
4ea00b7e7b | ||
|
|
844699263d | ||
|
|
d72a548852 | ||
|
|
722ed9bece | ||
|
|
8852367837 | ||
|
|
5559f9b9af | ||
|
|
39526edafd | ||
|
|
a4f86354d3 | ||
|
|
636204bbaf | ||
|
|
08494834c2 | ||
|
|
2247f34b89 | ||
|
|
5c84412238 | ||
|
|
13112aa4d8 | ||
|
|
836a165ff2 | ||
|
|
f36e0b39ed | ||
|
|
74e2ec74e0 | ||
|
|
bcb6243f3b | ||
|
|
c00b628fb4 | ||
|
|
2fbed17ebc | ||
|
|
7bfea23958 | ||
|
|
91c567779b | ||
|
|
c4aeeb419e | ||
|
|
7808fbb852 | ||
|
|
9e64bd474b | ||
|
|
25a6aef472 | ||
|
|
203ba521b0 | ||
|
|
287685420a | ||
|
|
a6ae0ba4b0 | ||
|
|
208346a480 | ||
|
|
0d5c55a3b5 | ||
|
|
4fcd2bf14c | ||
|
|
deea1aba7f | ||
|
|
3e31666cd6 | ||
|
|
197c4c46ab | ||
|
|
33cb2ed43d | ||
|
|
b56e521c5f | ||
|
|
639b930ac9 | ||
|
|
607235eb01 | ||
|
|
dbfeb4b0fa | ||
|
|
432725b80d | ||
|
|
91c2909c4a | ||
|
|
699a2f7956 | ||
|
|
7c2751ad37 | ||
|
|
50b524fa7a | ||
|
|
aee26bc9b2 | ||
|
|
78de254230 | ||
|
|
22fe4053e9 | ||
|
|
e73f9ac8f2 | ||
|
|
19987234e5 | ||
|
|
33239f28f8 | ||
|
|
350f4572ed | ||
|
|
ab29267d64 | ||
|
|
b410820868 | ||
|
|
b1268e0001 | ||
|
|
9fe661269d | ||
|
|
a715a77e76 | ||
|
|
20933f77f5 | ||
|
|
c618fcafaa | ||
|
|
350ce2ad35 | ||
|
|
eef8580e89 | ||
|
|
406fc05970 | ||
|
|
2b6cb775d8 | ||
|
|
fe27fd4c86 | ||
|
|
784dca2baa | ||
|
|
6cff6414c2 | ||
|
|
b84b6c3464 | ||
|
|
bd3931d62d | ||
|
|
7ababb626b | ||
|
|
62b2833c2f | ||
|
|
190c82bbe6 | ||
|
|
b8055d45e7 | ||
|
|
fe09bb3c91 | ||
|
|
84d0a91c44 | ||
|
|
9d95f660e3 | ||
|
|
2d76d1f50c | ||
|
|
df3b921654 | ||
|
|
e98fccdcfd | ||
|
|
7b9b940b6a | ||
|
|
3a4b750d93 | ||
|
|
40e3555d13 | ||
|
|
4b6adb3919 | ||
|
|
66aece580f | ||
|
|
09fc200d55 | ||
|
|
b17b56dba0 | ||
|
|
a9d0531a56 | ||
|
|
a7a2c85f82 | ||
|
|
83a06fcd2b | ||
|
|
d2d7b22a8f | ||
|
|
92b78ab3c8 | ||
|
|
0bed3bab98 | ||
|
|
a60637fb79 | ||
|
|
f1218264be | ||
|
|
18cf63facc | ||
|
|
9f8e1775af | ||
|
|
0e39f3ad05 | ||
|
|
4fc90c0168 | ||
|
|
57b4f539f9 | ||
|
|
8667ce5fb4 | ||
|
|
0ed922bb29 | ||
|
|
80eff97be3 | ||
|
|
e5cfe5cd99 | ||
|
|
1d8b952a6d | ||
|
|
c204f7a514 | ||
|
|
6e2ef1e29c | ||
|
|
5f0402043a | ||
|
|
6ad7ccdd6e | ||
|
|
90a2fd7f19 | ||
|
|
58c8b11f85 | ||
|
|
4d700be9ae | ||
|
|
da0d02b990 | ||
|
|
854cb59f6b | ||
|
|
33cbee23d4 | ||
|
|
0497cf384d | ||
|
|
acd8fa3810 | ||
|
|
9d024bca3b | ||
|
|
7434c9db55 | ||
|
|
a3ab0b3243 | ||
|
|
64608f6b05 | ||
|
|
a207c982b7 | ||
|
|
072acac399 | ||
|
|
8049466dff | ||
|
|
80077ba94d | ||
|
|
bd4744557f | ||
|
|
d8072634ef | ||
|
|
27158f7075 | ||
|
|
f06f1fb7f1 | ||
|
|
8bb7b75f05 | ||
|
|
0c9e92abb0 | ||
|
|
7a8787b1a0 | ||
|
|
78f71c8b13 | ||
|
|
a0a35e8253 | ||
|
|
e892e3f9e1 | ||
|
|
2dadc98485 | ||
|
|
1bd2b4629e | ||
|
|
ce52cbf6ac | ||
|
|
0abcb5aba1 | ||
|
|
ca7bdc913e | ||
|
|
2de7d34b4a | ||
|
|
0eea78f796 | ||
|
|
95fa7e8130 | ||
|
|
fd78876dd3 | ||
|
|
eaa3075516 | ||
|
|
92338fd219 | ||
|
|
26d32c02ea | ||
|
|
e03efc33d7 | ||
|
|
2d1188af11 | ||
|
|
66666ed5fd | ||
|
|
dfcb283899 | ||
|
|
24215f8b28 | ||
|
|
ddc2b4c2ad | ||
|
|
10cef483f4 | ||
|
|
51dde2f71e | ||
|
|
5e0117e7c6 | ||
|
|
3b3535faec | ||
|
|
3e1067faba | ||
|
|
722382f60e | ||
|
|
e47a512fc8 | ||
|
|
0627359b6e | ||
|
|
01d1e4c7f5 | ||
|
|
3f564e8179 | ||
|
|
b6f3038a73 | ||
|
|
e67354f34c | ||
|
|
a04982425f | ||
|
|
2e6f99edf0 | ||
|
|
9307d08bb6 | ||
|
|
2cdcd98e08 | ||
|
|
7540ee942f | ||
|
|
7bfad03b2e | ||
|
|
9dacd7056b | ||
|
|
4ebe66a29c | ||
|
|
6ebed9eff6 | ||
|
|
cc13685062 | ||
|
|
6b28490d7b | ||
|
|
27ba592434 | ||
|
|
cf5daffe69 | ||
|
|
192c0e529d | ||
|
|
c300e16de9 | ||
|
|
e46eecfc8e | ||
|
|
1e2add4b97 | ||
|
|
975f515691 | ||
|
|
05f8ae2aae | ||
|
|
525b3a0da9 | ||
|
|
03265e03fc | ||
|
|
28c928890a | ||
|
|
6f3e8683a0 | ||
|
|
ba7a16250b | ||
|
|
1cbbce741a | ||
|
|
9f9f6b7a08 |
@@ -1,64 +0,0 @@
|
||||
name: gin-vue-admin build test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- "./db/**"
|
||||
- "**.md"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- "./db/**"
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
frontend:
|
||||
name: Frontend build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.8.0]
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Build test
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: ./web
|
||||
|
||||
backend:
|
||||
name: Backend build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.6
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
working-directory: ./server
|
||||
|
||||
- name: Test and Build
|
||||
run: |
|
||||
go build -v -race
|
||||
working-directory: ./server
|
||||
@@ -0,0 +1,269 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ '*' ]
|
||||
pull_request:
|
||||
release:
|
||||
types: [ created, edited ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
gva_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
init:
|
||||
if: github.repository_owner == 'flipped-aurora'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: init
|
||||
run: |
|
||||
echo "flipped-aurora"
|
||||
frontend:
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'release'
|
||||
name: Frontend node ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.8.0]
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Build test
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: ./web
|
||||
|
||||
backend:
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'release'
|
||||
name: Backend go
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.22]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
id: go
|
||||
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
working-directory: ./server
|
||||
|
||||
- name: Test and Build
|
||||
run: |
|
||||
go build -v -race
|
||||
working-directory: ./server
|
||||
|
||||
devops-test:
|
||||
if: github.ref == 'refs/heads/test'
|
||||
name: devops-test
|
||||
needs:
|
||||
- init
|
||||
- backend
|
||||
- frontend
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.8.0]
|
||||
go-version: [1.22]
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Sed Config
|
||||
env:
|
||||
PROD: ${{ secrets.PROD }}
|
||||
TESTING: ${{ secrets.TESTING }}
|
||||
shell: bash
|
||||
run: |
|
||||
git branch
|
||||
ls -l
|
||||
sed -i "s/${PROD}/${TESTING}/g" web/.env.production
|
||||
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Build-Node
|
||||
run: |
|
||||
cd web/ && yarn install && yarn run build
|
||||
- name: Use Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Build-go
|
||||
run: |
|
||||
cd server/ && go mod tidy && CGO_ENABLED=0 go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
|
||||
- name: restart
|
||||
env:
|
||||
KEY: ${{ secrets.KEY }}
|
||||
HOST: ${{ secrets.HOST }}
|
||||
USER: ${{ secrets.USER }}
|
||||
PROT: ${{ secrets.PROT }}
|
||||
MKDIRTEST: ${{ secrets.MKDIRTEST }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIRTEST}dist/
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIRTEST}
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST}resource/ && rm -rf ${MKDIRTEST}resource/*"
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIRTEST}resource/
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST} && bash restart.sh > /dev/null 2>&1 &"
|
||||
|
||||
release-pr:
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository_owner == 'flipped-aurora'}}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Sed Config
|
||||
env:
|
||||
GVA_VERSION: ${{ inputs.gva_version }}
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 's/当前版本.*`$/当前版本:v'${GVA_VERSION##v}'`/' web/src/core/config.js
|
||||
sed -i 's/当前版本.*$/当前版本:v'${GVA_VERSION##v}'/' server/core/server.go
|
||||
sed -i 's/当前版本.*$/当前版本:v'${GVA_VERSION##v}'/' web/src/core/gin-vue-admin.js
|
||||
sed -i 's/"version": ".*",$/"version": "'${GVA_VERSION##v}'",/' web/package.json
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add . && git commit -m "release: v${GVA_VERSION##v}"
|
||||
- name: Push
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
command: release-pr
|
||||
release-type: simple
|
||||
changelog-path: docs/CHANGELOG.md
|
||||
release-as: ${{ inputs.gva_version }}
|
||||
package-name: gin-vue-admin
|
||||
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
|
||||
|
||||
release-please:
|
||||
if: github.ref == 'refs/heads/main' || github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- init
|
||||
- backend
|
||||
- frontend
|
||||
outputs:
|
||||
release_created: ${{ steps.release_please.outputs.release_created }}
|
||||
tag_name: ${{ steps.release_please.outputs.tag_name }}
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
id: release_please
|
||||
with:
|
||||
#token: ${{ secrets.GAV_TOKEN }}
|
||||
command: github-release
|
||||
#signoff: "github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
|
||||
release-type: simple
|
||||
changelog-path: docs/CHANGELOG.md
|
||||
#release-as: ${{ inputs.deploy_target }}
|
||||
package-name: gin-vue-admin
|
||||
#extra-files: |
|
||||
# x-release-please-version.json
|
||||
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
|
||||
|
||||
devops-prod:
|
||||
if: needs.release-please.outputs.release_created || github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- init
|
||||
- release-please
|
||||
name: devops-prod
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['16.x']
|
||||
go-version: ['1.22']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: tag major and minor versions
|
||||
run: |
|
||||
echo " ${{ needs.release-please.outputs.tag_name }}"
|
||||
- name: Sed Config
|
||||
shell: bash
|
||||
run: |
|
||||
git branch
|
||||
ls -l
|
||||
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Build-Node
|
||||
run: |
|
||||
cd web/ && yarn install && yarn run build
|
||||
- name: Use Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Build-go
|
||||
run: |
|
||||
cd server/ && go mod tidy && CGO_ENABLED=0 go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
|
||||
- name: restart
|
||||
env:
|
||||
KEY: ${{ secrets.KEY }}
|
||||
HOST: ${{ secrets.HOST }}
|
||||
USER: ${{ secrets.USER }}
|
||||
PROT: ${{ secrets.PROT }}
|
||||
MKDIR: ${{ secrets.MKDIR }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIR}dist/
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIR}
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR}resource/ && rm -rf ${MKDIR}resource/*"
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIR}resource/
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR} && bash restart.sh > /dev/null 2>&1 &"
|
||||
|
||||
docker:
|
||||
name: docker
|
||||
if: github.ref == 'refs/heads/stop-stop-stop'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- init
|
||||
- release-please
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Login to Aliyun Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ${{ secrets.ALIYUN_REGISTRY }}
|
||||
username: ${{ secrets.ALIYUN_DOCKERHUB_USER }}
|
||||
password: ${{ secrets.ALIYUN_DOCKERHUB_PASSWORD }}
|
||||
- name: Sed Config
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 56c"\ && yarn install && yarn build" Makefile
|
||||
make image TAGS_OPT="latest"
|
||||
sed -i 's#./entrypoint.sh"#./entrypoint.sh","actions"#g' deploy/docker/Dockerfile
|
||||
sed -i "s#COPY build/ /usr/share/nginx/html/#COPY . /opt/gva#g" deploy/docker/Dockerfile
|
||||
sed -i 16c"\ && cd /opt/gva/server/ && go mod tidy && cd /opt/gva/web/ && yarn" deploy/docker/Dockerfile
|
||||
sed -i "s#open: true#open: false#g" web/vite.config.js
|
||||
make images TAGS_OPT="latest"
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/gin-vue-admin:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/web:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/server:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/all:latest
|
||||
@@ -1,55 +0,0 @@
|
||||
name: devops-test
|
||||
on:
|
||||
push:
|
||||
branches: [test]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['16.x']
|
||||
go-version: ['1.16']
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Sed Config
|
||||
env:
|
||||
PROD: ${{ secrets.PROD }}
|
||||
TESTING: ${{ secrets.TESTING }}
|
||||
shell: bash
|
||||
run: |
|
||||
git branch
|
||||
ls -l
|
||||
sed -i "s/${PROD}/${TESTING}/g" web/.env.production
|
||||
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Build-Node
|
||||
run: |
|
||||
cd web/ && yarn install && yarn run build
|
||||
- name: Use Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Build-go
|
||||
run: |
|
||||
cd server/ && go mod tidy && go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
|
||||
- name: restart
|
||||
env:
|
||||
KEY: ${{ secrets.KEY }}
|
||||
HOST: ${{ secrets.HOST }}
|
||||
USER: ${{ secrets.USER }}
|
||||
PROT: ${{ secrets.PROT }}
|
||||
MKDIRTEST: ${{ secrets.MKDIRTEST }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIRTEST}dist/
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIRTEST}
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST}resource/ && rm -rf ${MKDIRTEST}resource/*"
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIRTEST}resource/
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST} && bash restart.sh > /dev/null 2>&1 &"
|
||||
@@ -1,52 +0,0 @@
|
||||
name: devops
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['16.x']
|
||||
go-version: ['1.16']
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Sed Config
|
||||
shell: bash
|
||||
run: |
|
||||
git branch
|
||||
ls -l
|
||||
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Build-Node
|
||||
run: |
|
||||
cd web/ && yarn install && yarn run build
|
||||
- name: Use Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Build-go
|
||||
run: |
|
||||
cd server/ && go mod tidy && go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
|
||||
- name: restart
|
||||
env:
|
||||
KEY: ${{ secrets.KEY }}
|
||||
HOST: ${{ secrets.HOST }}
|
||||
USER: ${{ secrets.USER }}
|
||||
PROT: ${{ secrets.PROT }}
|
||||
MKDIR: ${{ secrets.MKDIR }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIR}dist/
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIR}
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR}resource/ && rm -rf ${MKDIR}resource/*"
|
||||
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIR}resource/
|
||||
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR} && bash restart.sh > /dev/null 2>&1 &"
|
||||
@@ -1,32 +0,0 @@
|
||||
name: Docker-CICD
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@v2
|
||||
- name: Login to Aliyun Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ${{ secrets.ALIYUN_REGISTRY }}
|
||||
username: ${{ secrets.ALIYUN_DOCKERHUB_USER }}
|
||||
password: ${{ secrets.ALIYUN_DOCKERHUB_PASSWORD }}
|
||||
- name: Sed Config
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 56c"\ && yarn install && yarn build" Makefile
|
||||
make image TAGS_OPT="latest"
|
||||
sed -i 's#./entrypoint.sh"#./entrypoint.sh","actions"#g' deploy/docker/Dockerfile
|
||||
sed -i "s#COPY build/ /usr/share/nginx/html/#COPY . /opt/gva#g" deploy/docker/Dockerfile
|
||||
sed -i 16c"\ && cd /opt/gva/server/ && go mod tidy && cd /opt/gva/web/ && yarn" deploy/docker/Dockerfile
|
||||
sed -i "s#open: true#open: false#g" web/vite.config.js
|
||||
make images TAGS_OPT="latest"
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/gin-vue-admin:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/web:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/server:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/gva/all:latest
|
||||
@@ -1,114 +0,0 @@
|
||||
name: GIN-VUE-ADMIN Docker Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [stopstopstop]
|
||||
#workflow_dispatch:
|
||||
# inputs:
|
||||
# webtag:
|
||||
# description: 'Set web tag, Default latest'
|
||||
# required: true
|
||||
# default: "latest"
|
||||
# servertag:
|
||||
# description: 'Set server tag, Default latest'
|
||||
# required: true
|
||||
# default: "latest"
|
||||
|
||||
jobs:
|
||||
GIN_VUE_ADMIN_WEB:
|
||||
name: GIN VUE ADMIN WEB
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Private Actions Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
- name: Docker Setup QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
- name: Docker Setup Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
- name: Docker Login
|
||||
uses: docker/login-action@v1.10.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Docker Login in Aliyun
|
||||
uses: docker/login-action@v1.10.0
|
||||
with:
|
||||
registry: ${{ secrets.DOCKERHUB_REGISTRY_ALIYUN }}
|
||||
username: ${{ secrets.DOCKERHUB_ACCOUNT_ALIYUN }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD_ALIYUN }}
|
||||
- name: Build and push Docker images
|
||||
uses: docker/build-push-action@v2.7.0
|
||||
with:
|
||||
context: .
|
||||
# 这里是适配 arm64 ,主要看你们的程序是否支持 arm64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: web/Dockerfile
|
||||
push: true
|
||||
# 这里是给docker 打标签,默认不上传 latest
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/web:${{ github.event.inputs.webtag }}
|
||||
${{ secrets.DOCKERHUB_REGISTRY_ALIYUN }}/${{ secrets.DOCKERHUB_USERNAME_ALIYUN }}web:${{ github.event.inputs.webtag }}
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/web:${{ github.event.inputs.webtag }}.cache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/web:${{ github.event.inputs.webtag }}.cache,mode=max
|
||||
# 漏洞扫描
|
||||
- name: Scan for vulnerabilities
|
||||
uses: crazy-max/ghaction-container-scan@v1
|
||||
with:
|
||||
image: ${{ secrets.DOCKERHUB_USERNAME }}/web:${{ github.event.inputs.webtag }}
|
||||
dockerfile: web/Dockerfile
|
||||
# 更新 docker 描述页面
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
repository: ${{ secrets.DOCKERHUB_USERNAME }}/web
|
||||
|
||||
GIN_VUE_ADMIN_SERVER:
|
||||
name: GIN VUE ADMIN SERVER
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Private Actions Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
- name: Docker Setup QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
- name: Docker Setup Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
- name: Docker Login
|
||||
uses: docker/login-action@v1.10.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Docker Login in Aliyun
|
||||
uses: docker/login-action@v1.10.0
|
||||
with:
|
||||
registry: ${{ secrets.DOCKERHUB_REGISTRY_ALIYUN }}
|
||||
username: ${{ secrets.DOCKERHUB_ACCOUNT_ALIYUN }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD_ALIYUN }}
|
||||
- name: Build and push Docker images
|
||||
uses: docker/build-push-action@v2.7.0
|
||||
with:
|
||||
context: .
|
||||
# 这里是适配 arm64 ,主要看你们的程序是否支持 arm64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: server/Dockerfile
|
||||
push: true
|
||||
# 这里是给docker 打标签,默认不上传 latest
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/server:${{ github.event.inputs.servertag }}
|
||||
${{ secrets.DOCKERHUB_REGISTRY_ALIYUN }}/${{ secrets.DOCKERHUB_USERNAME_ALIYUN }}server:${{ github.event.inputs.servertag }}
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/server:${{ github.event.inputs.servertag }}.cache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/server:${{ github.event.inputs.servertag }}.cache,mode=max
|
||||
# 漏洞扫描
|
||||
- name: Scan for vulnerabilities
|
||||
uses: crazy-max/ghaction-container-scan@v1
|
||||
with:
|
||||
image: ${{ secrets.DOCKERHUB_USERNAME }}/server:${{ github.event.inputs.servertag }}
|
||||
dockerfile: server/Dockerfile
|
||||
# 更新 docker 描述页面
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
repository: ${{ secrets.DOCKERHUB_USERNAME }}/server
|
||||
@@ -25,6 +25,7 @@ yarn-error.log*
|
||||
/server/log/
|
||||
/server/gva
|
||||
/server/latest_log
|
||||
/server/__debug_bin*
|
||||
|
||||
*.iml
|
||||
web/.pnpm-debug.log
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 JiZhao Jiang
|
||||
Copyright 2019 北京翻转极光科技有限责任公司
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -2,7 +2,7 @@ SHELL = /bin/bash
|
||||
|
||||
#SCRIPT_DIR = $(shell pwd)/etc/script
|
||||
#请选择golang版本
|
||||
BUILD_IMAGE_SERVER = golang:1.16
|
||||
BUILD_IMAGE_SERVER = golang:1.18
|
||||
#请选择node版本
|
||||
BUILD_IMAGE_WEB = node:16
|
||||
#项目名称
|
||||
|
||||
+5
-9
@@ -3,11 +3,11 @@
|
||||
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width=300" height="300" />
|
||||
</div>
|
||||
<div align=center>
|
||||
<img src="https://img.shields.io/badge/golang-1.16-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-1.7.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/vue-3.2.25-brightgreen"/>
|
||||
<img src="https://img.shields.io/badge/element--plus-2.0.1-green"/>
|
||||
<img src="https://img.shields.io/badge/gorm-1.22.5-red"/>
|
||||
<img src="https://img.shields.io/badge/golang-1.18-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-1.9.1-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/vue-3.3.4-brightgreen"/>
|
||||
<img src="https://img.shields.io/badge/element--plus-2.3.8-green"/>
|
||||
<img src="https://img.shields.io/badge/gorm-1.25.2-red"/>
|
||||
</div>
|
||||
|
||||
English | [简体中文](./README.md)
|
||||
@@ -16,10 +16,6 @@ English | [简体中文](./README.md)
|
||||
|
||||
[github](https://github.com/flipped-aurora/gin-vue-admin): https://github.com/flipped-aurora/gin-vue-admin
|
||||
|
||||
[Vue3 version branch address](https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop): https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop
|
||||
|
||||
[Approval flow branch](https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow): https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow
|
||||
|
||||
# Project Guidelines
|
||||
[Online Documentation](https://www.gin-vue-admin.com/) : https://www.gin-vue-admin.com/
|
||||
|
||||
|
||||
@@ -3,24 +3,15 @@
|
||||
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width=300" height="300" />
|
||||
</div>
|
||||
<div align=center>
|
||||
<img src="https://img.shields.io/badge/golang-1.16-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-1.7.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/vue-3.2.25-brightgreen"/>
|
||||
<img src="https://img.shields.io/badge/element--plus-2.0.1-green"/>
|
||||
<img src="https://img.shields.io/badge/gorm-1.22.5-red"/>
|
||||
<img src="https://img.shields.io/badge/golang-1.20-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-1.9.1-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/vue-3.3.4-brightgreen"/>
|
||||
<img src="https://img.shields.io/badge/element--plus-2.3.8-green"/>
|
||||
<img src="https://img.shields.io/badge/gorm-1.25.2-red"/>
|
||||
</div>
|
||||
|
||||
[English](./README-en.md) | 简体中文
|
||||
|
||||
## 不同版本
|
||||
|
||||
我们会对以下四个版本持续维护,请选择适合自己的版本使用。最新技术栈为组合式api版本,已支持多语言(I18N)
|
||||
|
||||
[组合式API版(主)](https://github.com/flipped-aurora/gin-vue-admin) |
|
||||
[组合式API多语言(i18n)版](https://github.com/flipped-aurora/gin-vue-admin/tree/i18n-dev-new) |
|
||||
[声明式API版](https://github.com/flipped-aurora/gin-vue-admin/tree/v2.4.x) |
|
||||
[声明式API多语言(i18n)版](https://github.com/flipped-aurora/gin-vue-admin/tree/i18n-dev)
|
||||
|
||||
# 项目文档
|
||||
[在线文档](https://www.gin-vue-admin.com) : https://www.gin-vue-admin.com
|
||||
|
||||
@@ -42,9 +33,11 @@
|
||||
|
||||
3.您完全可以通过我们的教程和文档完成一切操作,因此我们不再提供免费的技术服务,如需服务请进行[付费支持](https://www.gin-vue-admin.com/coffee/payment.html)
|
||||
|
||||
4.如果您将此项目用于商业用途,请遵守Apache2.0协议并保留作者技术支持声明。您需保留如下版权声明信息,其余信息功能不做任何限制。如需剔除请[购买授权](https://www.gin-vue-admin.com/empower/index.html)
|
||||
4.如果您将此项目用于商业用途,请遵守Apache2.0协议并保留作者技术支持声明。您需保留如下版权声明信息,以及日志和代码中所包含的版权声明信息。所需保留信息均为文案性质,不会影响任何业务内容,如决定商用且必须剔除请[购买授权](https://www.gin-vue-admin.com/empower/index.html)
|
||||
|
||||
<img src="https://qmplusimg.henrongyi.top/%E6%8E%88%E6%9D%83.png" width="1000">
|
||||
<img src="https://qmplusimg.henrongyi.top/openSource/login.jpg" width="1000">
|
||||
|
||||
<img src="https://qmplusimg.henrongyi.top/openSource/dashboard.jpg" width="1000">
|
||||
|
||||
## 1. 基本介绍
|
||||
|
||||
@@ -66,8 +59,8 @@ Gin-vue-admin 是一套为快速研发准备的一整套前后端分离架构式
|
||||
Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-admin 贡献代码或提供建议,请阅读以下内容。
|
||||
|
||||
#### 1.2.1 Issue 规范
|
||||
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。如果你在使用时产生了疑问,请到 Slack 或 [Gitter](https://gitter.im/ElemeFE/element) 里咨询。
|
||||
|
||||
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
|
||||
|
||||
- 在提交 issue 之前,请搜索相关内容是否已被提出。
|
||||
|
||||
#### 1.2.2 Pull Request 规范
|
||||
@@ -83,7 +76,7 @@ Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-adm
|
||||
|
||||
```
|
||||
- node版本 > v16.8.3
|
||||
- golang版本 >= v1.16
|
||||
- golang版本 >= v1.22
|
||||
- IDE推荐:Goland
|
||||
```
|
||||
|
||||
@@ -125,29 +118,8 @@ npm run serve
|
||||
|
||||
#### 2.3.1 安装 swagger
|
||||
|
||||
##### (1)可以访问外国网站
|
||||
|
||||
````
|
||||
go get -u github.com/swaggo/swag/cmd/swag
|
||||
````
|
||||
|
||||
##### (2)无法访问外国网站
|
||||
|
||||
由于国内没法安装 go.org/x 包下面的东西,推荐使用 [goproxy.cn](https://goproxy.cn) 或者 [goproxy.io](https://goproxy.io/zh/)
|
||||
|
||||
```bash
|
||||
# 如果您使用的 Go 版本是 1.13 - 1.15 需要手动设置GO111MODULE=on, 开启方式如下命令, 如果你的 Go 版本 是 1.16 ~ 最新版 可以忽略以下步骤一
|
||||
# 步骤一、启用 Go Modules 功能
|
||||
go env -w GO111MODULE=on
|
||||
# 步骤二、配置 GOPROXY 环境变量
|
||||
go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct
|
||||
|
||||
# 如果嫌弃麻烦,可以使用go generate 编译前自动执行代码, 不过这个不能使用 `Goland` 或者 `Vscode` 的 命令行终端
|
||||
cd server
|
||||
go generate -run "go env -w .*?"
|
||||
|
||||
# 使用如下命令下载swag
|
||||
go get -u github.com/swaggo/swag/cmd/swag
|
||||
``` shell
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
```
|
||||
|
||||
#### 2.3.2 生成API文档
|
||||
@@ -314,8 +286,8 @@ swag init
|
||||
- 前端文件参考: [web/src/view/superAdmin/api/api.vue](https://github.com/flipped-aurora/gin-vue-admin/blob/master/web/src/view/superAdmin/api/api.vue)
|
||||
- 后台文件参考: [server/router/sys_api.go](https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/router/sys_api.go)
|
||||
- 多点登录限制:需要在`config.yaml`中把`system`中的`use-multipoint`修改为true(需要自行配置Redis和Config中的Redis参数,测试阶段,有bug请及时反馈)。
|
||||
- 分片长传:提供文件分片上传和大文件分片上传功能示例。
|
||||
- 表单生成器:表单生成器借助 [@form-generator](https://github.com/JakHuang/form-generator) 。
|
||||
- 分片上传:提供文件分片上传和大文件分片上传功能示例。
|
||||
- 表单生成器:表单生成器借助 [@Variant Form](https://github.com/vform666/variant-form) 。
|
||||
- 代码生成器:后台基础逻辑以及简单curd的代码生成器。
|
||||
|
||||
## 6. 知识库
|
||||
@@ -352,17 +324,20 @@ swag init
|
||||
|
||||
### 7.1 技术群
|
||||
|
||||
### QQ交流群:622360840
|
||||
| QQ 群 |
|
||||
| :---: |
|
||||
| <img src="http://qmplusimg.henrongyi.top/qq.jpg" width="180"/> |
|
||||
### QQ交流群:470239250
|
||||
|
||||
### 微信交流群
|
||||
| 微信 |
|
||||
| :---: |
|
||||
| <img width="150" src="http://qmplusimg.henrongyi.top/qrjjz.png">
|
||||
|
||||
添加微信,备注"加入gin-vue-admin交流群"
|
||||
防止广告进群,添加微信,输入以下代码执行结果(请勿转码为string)
|
||||
|
||||
```
|
||||
str := "5Yqg5YWlR1ZB5Lqk5rWB576k"
|
||||
decodeBytes, err := base64.StdEncoding.DecodeString(str)
|
||||
fmt.Println(decodeBytes, err)
|
||||
```
|
||||
|
||||
### [关于我们](https://www.gin-vue-admin.com/about/join.html)
|
||||
|
||||
|
||||
@@ -34,15 +34,17 @@ services:
|
||||
ipv4_address: 177.7.0.11
|
||||
|
||||
server:
|
||||
image: golang:1.16
|
||||
image: golang:1.18
|
||||
container_name: gva-server
|
||||
hostname: gva-server
|
||||
restart: always
|
||||
ports:
|
||||
- '8888:8888'
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../../server:/server
|
||||
working_dir: /server # 如果docker 设置了workdir 则此处不需要设置
|
||||
@@ -63,8 +65,15 @@ services:
|
||||
ports:
|
||||
- "13306:3306" # host物理直接映射端口为13306
|
||||
environment:
|
||||
#MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
|
||||
MYSQL_DATABASE: 'qmPlus' # 初始化启动时要创建的数据库的名称
|
||||
MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
|
||||
MYSQL_USER: 'gva'
|
||||
MYSQL_PASSWORD: 'Aa@6447985'
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "gva", "-pAa@6447985"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
networks:
|
||||
@@ -78,6 +87,11 @@ services:
|
||||
restart: always
|
||||
ports:
|
||||
- '16379:6379'
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
volumes:
|
||||
- redis:/data
|
||||
networks:
|
||||
|
||||
@@ -38,8 +38,10 @@ services:
|
||||
ports:
|
||||
- '8888:8888'
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- mysql
|
||||
- redis
|
||||
@@ -55,8 +57,15 @@ services:
|
||||
ports:
|
||||
- "13306:3306" # host物理直接映射端口为13306
|
||||
environment:
|
||||
#MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
|
||||
MYSQL_DATABASE: 'qmPlus' # 初始化启动时要创建的数据库的名称
|
||||
MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
|
||||
MYSQL_USER: 'gva'
|
||||
MYSQL_PASSWORD: 'Aa@6447985'
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "gva", "-pAa@6447985"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
networks:
|
||||
@@ -69,6 +78,11 @@ services:
|
||||
restart: always
|
||||
ports:
|
||||
- '16379:6379'
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
volumes:
|
||||
- redis:/data
|
||||
networks:
|
||||
|
||||
@@ -9,7 +9,7 @@ RUN set -ex \
|
||||
&& echo "LANG=en_US.utf8" > /etc/locale.conf \
|
||||
&& echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf \
|
||||
&& echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf \
|
||||
&& yum -y install yum -y install *epel* \
|
||||
&& yum -y install epel-release \
|
||||
&& yum -y localinstall http://mirrors.ustc.edu.cn/mysql-repo/mysql57-community-release-el7.rpm \
|
||||
&& yum -y install mysql-community-server git redis nginx go npm --nogpgcheck && chmod +x ./entrypoint.sh \
|
||||
&& npm install -g yarn && go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct \
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
- containerPort: 8888
|
||||
name: http
|
||||
volumeMounts:
|
||||
- mountPath: /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.yaml
|
||||
- mountPath: /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.docker.yaml
|
||||
name: config
|
||||
subPath: config.yaml
|
||||
- mountPath: /etc/localtime
|
||||
|
||||
@@ -3,13 +3,11 @@ package example
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
|
||||
type ApiGroup struct {
|
||||
ExcelApi
|
||||
CustomerApi
|
||||
FileUploadAndDownloadApi
|
||||
}
|
||||
|
||||
var (
|
||||
excelService = service.ServiceGroupApp.ExampleServiceGroup.ExcelService
|
||||
customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
|
||||
fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
|
||||
)
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type ExcelApi struct{}
|
||||
|
||||
// /excel/importExcel 接口,与upload接口作用类似,只是把文件存到resource/excel目录下,用于导入Excel时存放Excel文件(ExcelImport.xlsx)
|
||||
// /excel/loadExcel接口,用于读取resource/excel目录下的文件((ExcelImport.xlsx)并加载为[]model.SysBaseMenu类型的示例数据
|
||||
// /excel/exportExcel 接口,用于读取前端传来的tableData,生成Excel文件并返回
|
||||
// /excel/downloadTemplate 接口,用于下载resource/excel目录下的 ExcelTemplate.xlsx 文件,作为导入的模板
|
||||
|
||||
// ExportExcel
|
||||
// @Tags excel
|
||||
// @Summary 导出Excel
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/octet-stream
|
||||
// @Param data body example.ExcelInfo true "导出Excel文件信息"
|
||||
// @Success 200
|
||||
// @Router /excel/exportExcel [post]
|
||||
func (e *ExcelApi) ExportExcel(c *gin.Context) {
|
||||
var excelInfo example.ExcelInfo
|
||||
err := c.ShouldBindJSON(&excelInfo)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if strings.Index(excelInfo.FileName, "..") > -1 {
|
||||
response.FailWithMessage("包含非法字符", c)
|
||||
return
|
||||
}
|
||||
filePath := global.GVA_CONFIG.Excel.Dir + excelInfo.FileName
|
||||
err = excelService.ParseInfoList2Excel(excelInfo.InfoList, filePath)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("转换Excel失败!", zap.Error(err))
|
||||
response.FailWithMessage("转换Excel失败", c)
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Add("success", "true")
|
||||
c.File(filePath)
|
||||
}
|
||||
|
||||
// ImportExcel
|
||||
// @Tags excel
|
||||
// @Summary 导入Excel文件
|
||||
// @Security ApiKeyAuth
|
||||
// @accept multipart/form-data
|
||||
// @Produce application/json
|
||||
// @Param file formData file true "导入Excel文件"
|
||||
// @Success 200 {object} response.Response{msg=string} "导入Excel文件"
|
||||
// @Router /excel/importExcel [post]
|
||||
func (e *ExcelApi) ImportExcel(c *gin.Context) {
|
||||
_, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
|
||||
response.FailWithMessage("接收文件失败", c)
|
||||
return
|
||||
}
|
||||
_ = c.SaveUploadedFile(header, global.GVA_CONFIG.Excel.Dir+"ExcelImport.xlsx")
|
||||
response.OkWithMessage("导入成功", c)
|
||||
}
|
||||
|
||||
// LoadExcel
|
||||
// @Tags excel
|
||||
// @Summary 加载Excel数据
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "加载Excel数据,返回包括列表,总数,页码,每页数量"
|
||||
// @Router /excel/loadExcel [get]
|
||||
func (e *ExcelApi) LoadExcel(c *gin.Context) {
|
||||
menus, err := excelService.ParseExcel2InfoList()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("加载数据失败!", zap.Error(err))
|
||||
response.FailWithMessage("加载数据失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: menus,
|
||||
Total: int64(len(menus)),
|
||||
Page: 1,
|
||||
PageSize: 999,
|
||||
}, "加载数据成功", c)
|
||||
}
|
||||
|
||||
// DownloadTemplate
|
||||
// @Tags excel
|
||||
// @Summary 下载模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept multipart/form-data
|
||||
// @Produce application/json
|
||||
// @Param fileName query string true "模板名称"
|
||||
// @Success 200
|
||||
// @Router /excel/downloadTemplate [get]
|
||||
func (e *ExcelApi) DownloadTemplate(c *gin.Context) {
|
||||
fileName := c.Query("fileName")
|
||||
filePath := global.GVA_CONFIG.Excel.Dir + fileName
|
||||
|
||||
fi, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("文件不存在!", zap.Error(err))
|
||||
response.FailWithMessage("文件不存在", c)
|
||||
return
|
||||
}
|
||||
if fi.IsDir() {
|
||||
global.GVA_LOG.Error("不支持下载文件夹!", zap.Error(err))
|
||||
response.FailWithMessage("不支持下载文件夹", c)
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Add("success", "true")
|
||||
c.File(filePath)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ type ApiGroup struct {
|
||||
AutoCodeHistoryApi
|
||||
DictionaryDetailApi
|
||||
AuthorityBtnApi
|
||||
SysExportTemplateApi
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -212,3 +212,20 @@ func (s *SystemApiApi) DeleteApisByIds(c *gin.Context) {
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// FreshCasbin
|
||||
// @Tags SysApi
|
||||
// @Summary 刷新casbin缓存
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "刷新成功"
|
||||
// @Router /api/freshCasbin [get]
|
||||
func (s *SystemApiApi) FreshCasbin(c *gin.Context) {
|
||||
err := casbinService.FreshCasbin()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("刷新失败!", zap.Error(err))
|
||||
response.FailWithMessage("刷新失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("刷新成功", c)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
|
||||
@@ -25,26 +24,31 @@ type AuthorityApi struct{}
|
||||
// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "创建角色,返回包括系统角色详情"
|
||||
// @Router /authority/createAuthority [post]
|
||||
func (a *AuthorityApi) CreateAuthority(c *gin.Context) {
|
||||
var authority system.SysAuthority
|
||||
err := c.ShouldBindJSON(&authority)
|
||||
if err != nil {
|
||||
var authority, authBack system.SysAuthority
|
||||
var err error
|
||||
|
||||
if err = c.ShouldBindJSON(&authority); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
err = utils.Verify(authority, utils.AuthorityVerify)
|
||||
if err != nil {
|
||||
if err = utils.Verify(authority, utils.AuthorityVerify); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if authBack, err := authorityService.CreateAuthority(authority); err != nil {
|
||||
|
||||
if authBack, err = authorityService.CreateAuthority(authority); err != nil {
|
||||
global.GVA_LOG.Error("创建失败!", zap.Error(err))
|
||||
response.FailWithMessage("创建失败"+err.Error(), c)
|
||||
} else {
|
||||
_ = menuService.AddMenuAuthority(systemReq.DefaultMenu(), authority.AuthorityId)
|
||||
_ = casbinService.UpdateCasbin(authority.AuthorityId, systemReq.DefaultCasbin())
|
||||
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "创建成功", c)
|
||||
return
|
||||
}
|
||||
err = casbinService.FreshCasbin()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建成功,权限刷新失败。", zap.Error(err))
|
||||
response.FailWithMessage("创建成功,权限刷新失败。"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "创建成功", c)
|
||||
}
|
||||
|
||||
// CopyAuthority
|
||||
@@ -93,22 +97,22 @@ func (a *AuthorityApi) CopyAuthority(c *gin.Context) {
|
||||
// @Router /authority/deleteAuthority [post]
|
||||
func (a *AuthorityApi) DeleteAuthority(c *gin.Context) {
|
||||
var authority system.SysAuthority
|
||||
err := c.ShouldBindJSON(&authority)
|
||||
if err != nil {
|
||||
var err error
|
||||
if err = c.ShouldBindJSON(&authority); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = utils.Verify(authority, utils.AuthorityIdVerify)
|
||||
if err != nil {
|
||||
if err = utils.Verify(authority, utils.AuthorityIdVerify); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = authorityService.DeleteAuthority(&authority)
|
||||
if err != nil { // 删除角色之前需要判断是否有用户正在使用此角色
|
||||
// 删除角色之前需要判断是否有用户正在使用此角色
|
||||
if err = authorityService.DeleteAuthority(&authority); err != nil {
|
||||
global.GVA_LOG.Error("删除失败!", zap.Error(err))
|
||||
response.FailWithMessage("删除失败"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
_ = casbinService.FreshCasbin()
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ type AuthorityBtnApi struct{}
|
||||
func (a *AuthorityBtnApi) GetAuthorityBtn(c *gin.Context) {
|
||||
var req request.SysAuthorityBtnReq
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
res, err := authorityBtnService.GetAuthorityBtn(req)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询失败!", zap.Error(err))
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
@@ -20,8 +16,6 @@ import (
|
||||
|
||||
type AutoCodeApi struct{}
|
||||
|
||||
var caser = cases.Title(language.English)
|
||||
|
||||
// PreviewTemp
|
||||
// @Tags AutoCode
|
||||
// @Summary 预览创建后的代码
|
||||
@@ -39,7 +33,7 @@ func (autoApi *AutoCodeApi) PreviewTemp(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
a.Pretreatment() // 处理go关键字
|
||||
a.PackageT = caser.String(a.Package)
|
||||
a.PackageT = utils.FirstUpper(a.Package)
|
||||
autoCode, err := autoCodeService.PreviewTemp(a)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("预览失败!", zap.Error(err))
|
||||
@@ -67,6 +61,7 @@ func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
|
||||
}
|
||||
a.Pretreatment()
|
||||
var apiIds []uint
|
||||
var menuId uint
|
||||
if a.AutoCreateApiToSql {
|
||||
if ids, err := autoCodeService.AutoCreateApi(&a); err != nil {
|
||||
global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Error(err))
|
||||
@@ -77,24 +72,24 @@ func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
|
||||
apiIds = ids
|
||||
}
|
||||
}
|
||||
a.PackageT = caser.String(a.Package)
|
||||
err := autoCodeService.CreateTemp(a, apiIds...)
|
||||
if err != nil {
|
||||
if errors.Is(err, system.ErrAutoMove) {
|
||||
c.Writer.Header().Add("success", "true")
|
||||
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
|
||||
} else {
|
||||
if a.AutoCreateMenuToSql {
|
||||
if id, err := autoCodeService.AutoCreateMenu(&a); err != nil {
|
||||
global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Error(err))
|
||||
c.Writer.Header().Add("success", "false")
|
||||
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
|
||||
_ = os.Remove("./ginvueadmin.zip")
|
||||
c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!"))
|
||||
} else {
|
||||
menuId = id
|
||||
}
|
||||
} else {
|
||||
c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", "ginvueadmin.zip")) // fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名
|
||||
c.Writer.Header().Add("Content-Type", "application/json")
|
||||
c.Writer.Header().Add("success", "true")
|
||||
c.File("./ginvueadmin.zip")
|
||||
_ = os.Remove("./ginvueadmin.zip")
|
||||
}
|
||||
a.PackageT = utils.FirstUpper(a.Package)
|
||||
err := autoCodeService.CreateTemp(a, menuId, apiIds...)
|
||||
if err != nil {
|
||||
c.Writer.Header().Add("success", "false")
|
||||
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Add("Content-Type", "application/json")
|
||||
c.Writer.Header().Add("success", "true")
|
||||
}
|
||||
|
||||
// GetDB
|
||||
@@ -106,12 +101,22 @@ func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前所有数据库"
|
||||
// @Router /autoCode/getDatabase [get]
|
||||
func (autoApi *AutoCodeApi) GetDB(c *gin.Context) {
|
||||
dbs, err := autoCodeService.Database().GetDB()
|
||||
businessDB := c.Query("businessDB")
|
||||
dbs, err := autoCodeService.Database(businessDB).GetDB(businessDB)
|
||||
var dbList []map[string]interface{}
|
||||
for _, db := range global.GVA_CONFIG.DBList {
|
||||
var item = make(map[string]interface{})
|
||||
item["aliasName"] = db.AliasName
|
||||
item["dbName"] = db.Dbname
|
||||
item["disable"] = db.Disable
|
||||
item["dbtype"] = db.Type
|
||||
dbList = append(dbList, item)
|
||||
}
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
} else {
|
||||
response.OkWithDetailed(gin.H{"dbs": dbs}, "获取成功", c)
|
||||
response.OkWithDetailed(gin.H{"dbs": dbs, "dbList": dbList}, "获取成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +130,8 @@ func (autoApi *AutoCodeApi) GetDB(c *gin.Context) {
|
||||
// @Router /autoCode/getTables [get]
|
||||
func (autoApi *AutoCodeApi) GetTables(c *gin.Context) {
|
||||
dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname)
|
||||
tables, err := autoCodeService.Database().GetTables(dbName)
|
||||
businessDB := c.Query("businessDB")
|
||||
tables, err := autoCodeService.Database(businessDB).GetTables(businessDB, dbName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询table失败!", zap.Error(err))
|
||||
response.FailWithMessage("查询table失败", c)
|
||||
@@ -143,9 +149,10 @@ func (autoApi *AutoCodeApi) GetTables(c *gin.Context) {
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前表所有字段"
|
||||
// @Router /autoCode/getColumn [get]
|
||||
func (autoApi *AutoCodeApi) GetColumn(c *gin.Context) {
|
||||
businessDB := c.Query("businessDB")
|
||||
dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname)
|
||||
tableName := c.Query("tableName")
|
||||
columns, err := autoCodeService.Database().GetColumn(tableName, dbName)
|
||||
columns, err := autoCodeService.Database(businessDB).GetColumn(businessDB, tableName, dbName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
@@ -170,9 +177,16 @@ func (autoApi *AutoCodeApi) CreatePackage(c *gin.Context) {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
// PackageName可能导致路径穿越的问题 / 和 \ 都要防止
|
||||
if strings.Contains(a.PackageName, "\\") || strings.Contains(a.PackageName, "/") || strings.Contains(a.PackageName, "..") {
|
||||
response.FailWithMessage("包名不合法", c)
|
||||
return
|
||||
}
|
||||
|
||||
err := autoCodeService.CreateAutoCode(&a)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建成功!", zap.Error(err))
|
||||
|
||||
global.GVA_LOG.Error("创建失败!", zap.Error(err))
|
||||
response.FailWithMessage("创建失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("创建成功", c)
|
||||
@@ -234,6 +248,11 @@ func (autoApi *AutoCodeApi) AutoPlug(c *gin.Context) {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if strings.Contains(a.PlugName, "\\") || strings.Contains(a.PlugName, "/") || strings.Contains(a.PlugName, "..") {
|
||||
response.FailWithMessage("插件名称不合法", c)
|
||||
return
|
||||
}
|
||||
|
||||
a.Snake = strings.ToLower(a.PlugName)
|
||||
a.NeedModel = a.HasRequest || a.HasResponse
|
||||
err = autoCodeService.CreatePlug(a)
|
||||
@@ -253,7 +272,7 @@ func (autoApi *AutoCodeApi) AutoPlug(c *gin.Context) {
|
||||
// @Produce application/json
|
||||
// @Param plug formData file true "this is a test file"
|
||||
// @Success 200 {object} response.Response{data=[]interface{},msg=string} "安装插件成功"
|
||||
// @Router /autoCode/createPlug [post]
|
||||
// @Router /autoCode/installPlugin [post]
|
||||
func (autoApi *AutoCodeApi) InstallPlugin(c *gin.Context) {
|
||||
header, err := c.FormFile("plug")
|
||||
if err != nil {
|
||||
@@ -283,3 +302,23 @@ func (autoApi *AutoCodeApi) InstallPlugin(c *gin.Context) {
|
||||
"msg": serverStr,
|
||||
}}, c)
|
||||
}
|
||||
|
||||
// PubPlug
|
||||
// @Tags AutoCode
|
||||
// @Summary 打包插件
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysAutoCode true "打包插件"
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功"
|
||||
// @Router /autoCode/pubPlug [get]
|
||||
func (autoApi *AutoCodeApi) PubPlug(c *gin.Context) {
|
||||
plugName := c.Query("plugName")
|
||||
zipPath, err := autoCodeService.PubPlug(plugName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("打包失败!", zap.Error(err))
|
||||
response.FailWithMessage("打包失败"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage(fmt.Sprintf("打包成功,文件路径为:%s", zipPath), c)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
|
||||
@@ -21,15 +23,28 @@ type BaseApi struct{}
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{data=systemRes.SysCaptchaResponse,msg=string} "生成验证码,返回包括随机数id,base64,验证码长度"
|
||||
// @Success 200 {object} response.Response{data=systemRes.SysCaptchaResponse,msg=string} "生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码"
|
||||
// @Router /base/captcha [post]
|
||||
func (b *BaseApi) Captcha(c *gin.Context) {
|
||||
// 判断验证码是否开启
|
||||
openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数
|
||||
openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间
|
||||
key := c.ClientIP()
|
||||
v, ok := global.BlackCache.Get(key)
|
||||
if !ok {
|
||||
global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut))
|
||||
}
|
||||
|
||||
var oc bool
|
||||
if openCaptcha == 0 || openCaptcha < interfaceToInt(v) {
|
||||
oc = true
|
||||
}
|
||||
// 字符,公式,验证码配置
|
||||
// 生成默认数字的driver
|
||||
driver := base64Captcha.NewDriverDigit(global.GVA_CONFIG.Captcha.ImgHeight, global.GVA_CONFIG.Captcha.ImgWidth, global.GVA_CONFIG.Captcha.KeyLong, 0.7, 80)
|
||||
// cp := base64Captcha.NewCaptcha(driver, store.UseWithCtx(c)) // v8下使用redis
|
||||
cp := base64Captcha.NewCaptcha(driver, store)
|
||||
id, b64s, err := cp.Generate()
|
||||
id, b64s, _, err := cp.Generate()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("验证码获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("验证码获取失败", c)
|
||||
@@ -39,5 +54,17 @@ func (b *BaseApi) Captcha(c *gin.Context) {
|
||||
CaptchaId: id,
|
||||
PicPath: b64s,
|
||||
CaptchaLength: global.GVA_CONFIG.Captcha.KeyLong,
|
||||
OpenCaptcha: oc,
|
||||
}, "验证码获取成功", c)
|
||||
}
|
||||
|
||||
// 类型转换
|
||||
func interfaceToInt(v interface{}) (i int) {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
i = v
|
||||
default:
|
||||
i = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -118,31 +116,14 @@ func (s *DictionaryApi) FindSysDictionary(c *gin.Context) {
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query request.SysDictionarySearch true "页码, 每页大小, 搜索条件"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量"
|
||||
// @Router /sysDictionary/getSysDictionaryList [get]
|
||||
func (s *DictionaryApi) GetSysDictionaryList(c *gin.Context) {
|
||||
var pageInfo request.SysDictionarySearch
|
||||
err := c.ShouldBindQuery(&pageInfo)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
list, total, err := dictionaryService.GetSysDictionaryInfoList(pageInfo)
|
||||
list, err := dictionaryService.GetSysDictionaryInfoList()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: pageInfo.Page,
|
||||
PageSize: pageInfo.PageSize,
|
||||
}, "获取成功", c)
|
||||
response.OkWithDetailed(list, "获取成功", c)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SysExportTemplateApi struct {
|
||||
}
|
||||
|
||||
var sysExportTemplateService = service.ServiceGroupApp.SystemServiceGroup.SysExportTemplateService
|
||||
|
||||
// CreateSysExportTemplate 创建导出模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 创建导出模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysExportTemplate true "创建导出模板"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
|
||||
// @Router /sysExportTemplate/createSysExportTemplate [post]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) CreateSysExportTemplate(c *gin.Context) {
|
||||
var sysExportTemplate system.SysExportTemplate
|
||||
err := c.ShouldBindJSON(&sysExportTemplate)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
verify := utils.Rules{
|
||||
"Name": {utils.NotEmpty()},
|
||||
}
|
||||
if err := utils.Verify(sysExportTemplate, verify); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := sysExportTemplateService.CreateSysExportTemplate(&sysExportTemplate); err != nil {
|
||||
global.GVA_LOG.Error("创建失败!", zap.Error(err))
|
||||
response.FailWithMessage("创建失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplate 删除导出模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 删除导出模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysExportTemplate true "删除导出模板"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
|
||||
// @Router /sysExportTemplate/deleteSysExportTemplate [delete]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) DeleteSysExportTemplate(c *gin.Context) {
|
||||
var sysExportTemplate system.SysExportTemplate
|
||||
err := c.ShouldBindJSON(&sysExportTemplate)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := sysExportTemplateService.DeleteSysExportTemplate(sysExportTemplate); err != nil {
|
||||
global.GVA_LOG.Error("删除失败!", zap.Error(err))
|
||||
response.FailWithMessage("删除失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplateByIds 批量删除导出模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 批量删除导出模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body request.IdsReq true "批量删除导出模板"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}"
|
||||
// @Router /sysExportTemplate/deleteSysExportTemplateByIds [delete]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) DeleteSysExportTemplateByIds(c *gin.Context) {
|
||||
var IDS request.IdsReq
|
||||
err := c.ShouldBindJSON(&IDS)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := sysExportTemplateService.DeleteSysExportTemplateByIds(IDS); err != nil {
|
||||
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
|
||||
response.FailWithMessage("批量删除失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("批量删除成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateSysExportTemplate 更新导出模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 更新导出模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysExportTemplate true "更新导出模板"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
|
||||
// @Router /sysExportTemplate/updateSysExportTemplate [put]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) UpdateSysExportTemplate(c *gin.Context) {
|
||||
var sysExportTemplate system.SysExportTemplate
|
||||
err := c.ShouldBindJSON(&sysExportTemplate)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
verify := utils.Rules{
|
||||
"Name": {utils.NotEmpty()},
|
||||
}
|
||||
if err := utils.Verify(sysExportTemplate, verify); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := sysExportTemplateService.UpdateSysExportTemplate(sysExportTemplate); err != nil {
|
||||
global.GVA_LOG.Error("更新失败!", zap.Error(err))
|
||||
response.FailWithMessage("更新失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// FindSysExportTemplate 用id查询导出模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 用id查询导出模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query system.SysExportTemplate true "用id查询导出模板"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
|
||||
// @Router /sysExportTemplate/findSysExportTemplate [get]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) FindSysExportTemplate(c *gin.Context) {
|
||||
var sysExportTemplate system.SysExportTemplate
|
||||
err := c.ShouldBindQuery(&sysExportTemplate)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if resysExportTemplate, err := sysExportTemplateService.GetSysExportTemplate(sysExportTemplate.ID); err != nil {
|
||||
global.GVA_LOG.Error("查询失败!", zap.Error(err))
|
||||
response.FailWithMessage("查询失败", c)
|
||||
} else {
|
||||
response.OkWithData(gin.H{"resysExportTemplate": resysExportTemplate}, c)
|
||||
}
|
||||
}
|
||||
|
||||
// GetSysExportTemplateList 分页获取导出模板列表
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 分页获取导出模板列表
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query systemReq.SysExportTemplateSearch true "分页获取导出模板列表"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
|
||||
// @Router /sysExportTemplate/getSysExportTemplateList [get]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gin.Context) {
|
||||
var pageInfo systemReq.SysExportTemplateSearch
|
||||
err := c.ShouldBindQuery(&pageInfo)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if list, total, err := sysExportTemplateService.GetSysExportTemplateInfoList(pageInfo); err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
} else {
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: pageInfo.Page,
|
||||
PageSize: pageInfo.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportExcel 导出表格
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 导出表格
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Router /sysExportTemplate/exportExcel [get]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) ExportExcel(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
queryParams := c.Request.URL.Query()
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
if file, name, err := sysExportTemplateService.ExportExcel(templateID, queryParams); err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
} else {
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+utils.RandomString(6)+".xlsx")) // 对下载的文件重命名
|
||||
c.Header("success", "true")
|
||||
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// ExportExcel 导出表格模板
|
||||
// @Tags SysExportTemplate
|
||||
// @Summary 导出表格模板
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Router /sysExportTemplate/exportExcel [get]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) ExportTemplate(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
if file, name, err := sysExportTemplateService.ExportTemplate(templateID); err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
} else {
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+"模板.xlsx")) // 对下载的文件重命名
|
||||
c.Header("success", "true")
|
||||
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// ExportExcel 导入表格
|
||||
// @Tags SysImportTemplate
|
||||
// @Summary 导入表格
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Router /sysExportTemplate/importExcel [post]
|
||||
func (sysExportTemplateApi *SysExportTemplateApi) ImportExcel(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("文件获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("文件获取失败", c)
|
||||
return
|
||||
}
|
||||
if err := sysExportTemplateService.ImportExcel(templateID, file); err != nil {
|
||||
global.GVA_LOG.Error(err.Error(), zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
} else {
|
||||
response.OkWithMessage("导入成功", c)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -19,7 +20,7 @@ type JwtApi struct{}
|
||||
// @Success 200 {object} response.Response{msg=string} "jwt加入黑名单"
|
||||
// @Router /jwt/jsonInBlacklist [post]
|
||||
func (j *JwtApi) JsonInBlacklist(c *gin.Context) {
|
||||
token := c.Request.Header.Get("x-token")
|
||||
token := utils.GetToken(c)
|
||||
jwt := system.JwtBlacklist{Jwt: token}
|
||||
err := jwtService.JsonInBlacklist(jwt)
|
||||
if err != nil {
|
||||
@@ -27,5 +28,6 @@ func (j *JwtApi) JsonInBlacklist(c *gin.Context) {
|
||||
response.FailWithMessage("jwt作废失败", c)
|
||||
return
|
||||
}
|
||||
utils.ClearToken(c)
|
||||
response.OkWithMessage("jwt作废成功", c)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func (a *AuthorityMenuApi) GetMenu(c *gin.Context) {
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
if menus == nil {
|
||||
menus = []system.SysMenu{}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package system
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -26,6 +27,8 @@ import (
|
||||
func (b *BaseApi) Login(c *gin.Context) {
|
||||
var l systemReq.Login
|
||||
err := c.ShouldBindJSON(&l)
|
||||
key := c.ClientIP()
|
||||
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
@@ -35,22 +38,39 @@ func (b *BaseApi) Login(c *gin.Context) {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if store.Verify(l.CaptchaId, l.Captcha, true) {
|
||||
|
||||
// 判断验证码是否开启
|
||||
openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数
|
||||
openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间
|
||||
v, ok := global.BlackCache.Get(key)
|
||||
if !ok {
|
||||
global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut))
|
||||
}
|
||||
|
||||
var oc bool = openCaptcha == 0 || openCaptcha < interfaceToInt(v)
|
||||
|
||||
if !oc || (l.CaptchaId != "" && l.Captcha != "" && store.Verify(l.CaptchaId, l.Captcha, true)) {
|
||||
u := &system.SysUser{Username: l.Username, Password: l.Password}
|
||||
user, err := userService.Login(u)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err))
|
||||
// 验证码次数+1
|
||||
global.BlackCache.Increment(key, 1)
|
||||
response.FailWithMessage("用户名不存在或者密码错误", c)
|
||||
return
|
||||
}
|
||||
if user.Enable != 1 {
|
||||
global.GVA_LOG.Error("登陆失败! 用户被禁止登录!")
|
||||
// 验证码次数+1
|
||||
global.BlackCache.Increment(key, 1)
|
||||
response.FailWithMessage("用户被禁止登录", c)
|
||||
return
|
||||
}
|
||||
b.TokenNext(c, *user)
|
||||
return
|
||||
}
|
||||
// 验证码次数+1
|
||||
global.BlackCache.Increment(key, 1)
|
||||
response.FailWithMessage("验证码错误", c)
|
||||
}
|
||||
|
||||
@@ -71,10 +91,11 @@ func (b *BaseApi) TokenNext(c *gin.Context, user system.SysUser) {
|
||||
return
|
||||
}
|
||||
if !global.GVA_CONFIG.System.UseMultipoint {
|
||||
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
|
||||
response.OkWithDetailed(systemRes.LoginResponse{
|
||||
User: user,
|
||||
Token: token,
|
||||
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
|
||||
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
|
||||
}, "登录成功", c)
|
||||
return
|
||||
}
|
||||
@@ -85,10 +106,11 @@ func (b *BaseApi) TokenNext(c *gin.Context, user system.SysUser) {
|
||||
response.FailWithMessage("设置登录状态失败", c)
|
||||
return
|
||||
}
|
||||
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
|
||||
response.OkWithDetailed(systemRes.LoginResponse{
|
||||
User: user,
|
||||
Token: token,
|
||||
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
|
||||
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
|
||||
}, "登录成功", c)
|
||||
} else if err != nil {
|
||||
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
|
||||
@@ -104,10 +126,11 @@ func (b *BaseApi) TokenNext(c *gin.Context, user system.SysUser) {
|
||||
response.FailWithMessage("设置登录状态失败", c)
|
||||
return
|
||||
}
|
||||
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
|
||||
response.OkWithDetailed(systemRes.LoginResponse{
|
||||
User: user,
|
||||
Token: token,
|
||||
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
|
||||
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
|
||||
}, "登录成功", c)
|
||||
}
|
||||
}
|
||||
@@ -137,7 +160,7 @@ func (b *BaseApi) Register(c *gin.Context) {
|
||||
AuthorityId: v,
|
||||
})
|
||||
}
|
||||
user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities, Enable: r.Enable}
|
||||
user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities, Enable: r.Enable, Phone: r.Phone, Email: r.Email}
|
||||
userReturn, err := userService.Register(*user)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("注册失败!", zap.Error(err))
|
||||
@@ -248,7 +271,8 @@ func (b *BaseApi) SetUserAuthority(c *gin.Context) {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
} else {
|
||||
c.Header("new-token", token)
|
||||
c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt, 10))
|
||||
c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt.Unix(), 10))
|
||||
utils.SetToken(c, token, int((claims.ExpiresAt.Unix()-time.Now().Unix())/60))
|
||||
response.OkWithMessage("修改成功", c)
|
||||
}
|
||||
}
|
||||
@@ -379,7 +403,7 @@ func (b *BaseApi) SetSelfInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
user.ID = utils.GetUserID(c)
|
||||
err = userService.SetUserInfo(system.SysUser{
|
||||
err = userService.SetSelfInfo(system.SysUser{
|
||||
GVA_MODEL: global.GVA_MODEL{
|
||||
ID: user.ID,
|
||||
},
|
||||
|
||||
+93
-76
@@ -2,46 +2,61 @@
|
||||
|
||||
# jwt configuration
|
||||
jwt:
|
||||
signing-key: 'qmPlus'
|
||||
expires-time: 604800
|
||||
buffer-time: 86400
|
||||
issuer: 'qmPlus'
|
||||
|
||||
signing-key: qmPlus
|
||||
expires-time: 7d
|
||||
buffer-time: 1d
|
||||
issuer: qmPlus
|
||||
# zap logger configuration
|
||||
zap:
|
||||
level: 'info'
|
||||
prefix: '[github.com/flipped-aurora/gin-vue-admin/server]'
|
||||
format: 'console'
|
||||
director: 'log'
|
||||
encode-level: 'LowercaseColorLevelEncoder'
|
||||
stacktrace-key: 'stacktrace'
|
||||
max-age: 30 # 默认日志留存默认以天为单位
|
||||
level: info
|
||||
format: console
|
||||
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
|
||||
director: log
|
||||
show-line: true
|
||||
encode-level: LowercaseColorLevelEncoder
|
||||
stacktrace-key: stacktrace
|
||||
log-in-console: true
|
||||
|
||||
# redis configuration
|
||||
redis:
|
||||
db: 0
|
||||
addr: '177.7.0.14:6379'
|
||||
addr: 177.7.0.14:6379
|
||||
password: ""
|
||||
|
||||
# mongo configuration
|
||||
mongo:
|
||||
coll: ''
|
||||
options: ''
|
||||
database: ''
|
||||
username: ''
|
||||
password: ''
|
||||
min-pool-size: 0
|
||||
max-pool-size: 100
|
||||
socket-timeout-ms: 0
|
||||
connect-timeout-ms: 0
|
||||
is-zap: false
|
||||
hosts:
|
||||
- host: ''
|
||||
port: ''
|
||||
|
||||
# email configuration
|
||||
email:
|
||||
to: 'xxx@qq.com'
|
||||
to: xxx@qq.com
|
||||
port: 465
|
||||
from: 'xxx@163.com'
|
||||
host: 'smtp.163.com'
|
||||
from: xxx@163.com
|
||||
host: smtp.163.com
|
||||
is-ssl: true
|
||||
secret: 'xxx'
|
||||
nickname: 'test'
|
||||
secret: xxx
|
||||
nickname: test
|
||||
|
||||
# system configuration
|
||||
system:
|
||||
env: 'public' # Change to "develop" to skip authentication for development mode
|
||||
env: public # Change to "develop" to skip authentication for development mode
|
||||
addr: 8888
|
||||
db-type: 'mysql'
|
||||
oss-type: 'local' # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
||||
db-type: mysql
|
||||
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
||||
use-redis: false # 使用redis
|
||||
use-mongo: false # 使用mongo
|
||||
use-multipoint: false
|
||||
# IP限制次数 一个小时15000次
|
||||
iplimit-count: 15000
|
||||
@@ -53,16 +68,18 @@ captcha:
|
||||
key-long: 6
|
||||
img-width: 240
|
||||
img-height: 80
|
||||
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
|
||||
open-captcha-timeout: 3600 # open-captcha大于0时才生效
|
||||
|
||||
# mysql connect configuration
|
||||
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
||||
mysql:
|
||||
path: ''
|
||||
port: ''
|
||||
config: ''
|
||||
db-name: ''
|
||||
username: ''
|
||||
password: ''
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
@@ -71,27 +88,27 @@ mysql:
|
||||
# pgsql connect configuration
|
||||
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
||||
pgsql:
|
||||
path: ''
|
||||
port: ''
|
||||
config: ''
|
||||
db-name: ''
|
||||
username: ''
|
||||
password: ''
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
|
||||
db-list:
|
||||
- disabled: true # 是否启用
|
||||
- disable: true # 是否禁用
|
||||
type: "" # 数据库的类型,目前支持mysql、pgsql
|
||||
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
|
||||
path: ''
|
||||
port: ''
|
||||
config: ''
|
||||
db-name: ''
|
||||
username: ''
|
||||
password: ''
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
@@ -100,8 +117,8 @@ db-list:
|
||||
|
||||
# local configuration
|
||||
local:
|
||||
path: 'uploads/file' # 访问路径
|
||||
store-path: 'uploads/file' # 存储路径
|
||||
path: uploads/file
|
||||
store-path: uploads/file
|
||||
|
||||
# autocode configuration
|
||||
autocode:
|
||||
@@ -124,70 +141,70 @@ autocode:
|
||||
|
||||
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
|
||||
qiniu:
|
||||
zone: 'ZoneHuaDong'
|
||||
bucket: ''
|
||||
img-path: ''
|
||||
zone: ZoneHuaDong
|
||||
bucket: ""
|
||||
img-path: ""
|
||||
use-https: false
|
||||
access-key: ''
|
||||
secret-key: ''
|
||||
access-key: ""
|
||||
secret-key: ""
|
||||
use-cdn-domains: false
|
||||
|
||||
# aliyun oss configuration
|
||||
aliyun-oss:
|
||||
endpoint: 'yourEndpoint'
|
||||
access-key-id: 'yourAccessKeyId'
|
||||
access-key-secret: 'yourAccessKeySecret'
|
||||
bucket-name: 'yourBucketName'
|
||||
bucket-url: 'yourBucketUrl'
|
||||
base-path: 'yourBasePath'
|
||||
endpoint: yourEndpoint
|
||||
access-key-id: yourAccessKeyId
|
||||
access-key-secret: yourAccessKeySecret
|
||||
bucket-name: yourBucketName
|
||||
bucket-url: yourBucketUrl
|
||||
base-path: yourBasePath
|
||||
|
||||
# tencent cos configuration
|
||||
tencent-cos:
|
||||
bucket: 'xxxxx-10005608'
|
||||
region: 'ap-shanghai'
|
||||
secret-id: 'xxxxxxxx'
|
||||
secret-key: 'xxxxxxxx'
|
||||
base-url: 'https://gin.vue.admin'
|
||||
path-prefix: 'github.com/flipped-aurora/gin-vue-admin/server'
|
||||
bucket: xxxxx-10005608
|
||||
region: ap-shanghai
|
||||
secret-id: your-secret-id
|
||||
secret-key: your-secret-key
|
||||
base-url: https://gin.vue.admin
|
||||
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
||||
|
||||
# aws s3 configuration (minio compatible)
|
||||
aws-s3:
|
||||
bucket: xxxxx-10005608
|
||||
region: ap-shanghai
|
||||
endpoint: ''
|
||||
endpoint: ""
|
||||
s3-force-path-style: false
|
||||
disable-ssl: false
|
||||
secret-id: xxxxxxxx
|
||||
secret-key: xxxxxxxx
|
||||
secret-id: your-secret-id
|
||||
secret-key: your-secret-key
|
||||
base-url: https://gin.vue.admin
|
||||
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
||||
|
||||
# huawei obs configuration
|
||||
hua-wei-obs:
|
||||
path: 'you-path'
|
||||
bucket: 'you-bucket'
|
||||
endpoint: 'you-endpoint'
|
||||
access-key: 'you-access-key'
|
||||
secret-key: 'you-secret-key'
|
||||
path: you-path
|
||||
bucket: you-bucket
|
||||
endpoint: you-endpoint
|
||||
access-key: you-access-key
|
||||
secret-key: you-secret-key
|
||||
|
||||
# excel configuration
|
||||
excel:
|
||||
dir: './resource/excel/'
|
||||
dir: ./resource/excel/
|
||||
|
||||
# timer task db clear table
|
||||
Timer:
|
||||
start: true
|
||||
spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3
|
||||
detail:
|
||||
- tableName: "sys_operation_records"
|
||||
compareField: "created_at"
|
||||
interval: "2160h"
|
||||
- tableName: "jwt_blacklists"
|
||||
compareField: "created_at"
|
||||
interval: "168h"
|
||||
- tableName: sys_operation_records
|
||||
compareField: created_at
|
||||
interval: 2160h
|
||||
- tableName: jwt_blacklists
|
||||
compareField: created_at
|
||||
interval: 168h
|
||||
|
||||
# 跨域配置
|
||||
# 需要配合 server/initialize/router.go#L32 使用
|
||||
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
|
||||
cors:
|
||||
mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
|
||||
whitelist:
|
||||
@@ -200,4 +217,4 @@ cors:
|
||||
allow-headers: content-type
|
||||
allow-methods: GET, POST
|
||||
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||
allow-credentials: true # 布尔值
|
||||
allow-credentials: true # 布尔值
|
||||
+79
-25
@@ -10,7 +10,7 @@ jwt:
|
||||
zap:
|
||||
level: info
|
||||
format: console
|
||||
prefix: [github.com/flipped-aurora/gin-vue-admin/server]
|
||||
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
|
||||
director: log
|
||||
show-line: true
|
||||
encode-level: LowercaseColorLevelEncoder
|
||||
@@ -19,9 +19,34 @@ zap:
|
||||
|
||||
# redis configuration
|
||||
redis:
|
||||
db: 0
|
||||
#是否使用redis集群模式
|
||||
useCluster: false
|
||||
#使用集群模式addr和db默认无效
|
||||
addr: 127.0.0.1:6379
|
||||
password: ""
|
||||
db: 0
|
||||
clusterAddrs:
|
||||
- "172.21.0.3:7000"
|
||||
- "172.21.0.4:7001"
|
||||
- "172.21.0.2:7002"
|
||||
|
||||
|
||||
# mongo configuration
|
||||
mongo:
|
||||
coll: ''
|
||||
options: ''
|
||||
database: ''
|
||||
username: ''
|
||||
password: ''
|
||||
auth-source: ''
|
||||
min-pool-size: 0
|
||||
max-pool-size: 100
|
||||
socket-timeout-ms: 0
|
||||
connect-timeout-ms: 0
|
||||
is-zap: false
|
||||
hosts:
|
||||
- host: ''
|
||||
port: ''
|
||||
|
||||
# email configuration
|
||||
email:
|
||||
@@ -35,22 +60,27 @@ email:
|
||||
|
||||
# system configuration
|
||||
system:
|
||||
env: public # Change to "develop" to skip authentication for development mode
|
||||
env: local # 修改为public可以关闭路由日志输出
|
||||
addr: 8888
|
||||
db-type: mysql
|
||||
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
||||
use-redis: false # 使用redis
|
||||
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
||||
use-redis: false # 使用redis
|
||||
use-mongo: false # 使用mongo
|
||||
use-multipoint: false
|
||||
# IP限制次数 一个小时15000次
|
||||
iplimit-count: 15000
|
||||
# IP限制一个小时
|
||||
iplimit-time: 3600
|
||||
# 路由全局前缀
|
||||
router-prefix: ""
|
||||
|
||||
# captcha configuration
|
||||
captcha:
|
||||
key-long: 6
|
||||
img-width: 240
|
||||
img-height: 80
|
||||
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
|
||||
open-captcha-timeout: 3600 # open-captcha大于0时才生效
|
||||
|
||||
# mysql connect configuration
|
||||
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
||||
@@ -79,10 +109,42 @@ pgsql:
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
|
||||
oracle:
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
mssql:
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
sqlite:
|
||||
path: ""
|
||||
port: ""
|
||||
config: ""
|
||||
db-name: ""
|
||||
username: ""
|
||||
password: ""
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
db-list:
|
||||
- disabled: true # 是否启用
|
||||
type: "" # 数据库的类型,目前支持mysql、pgsql
|
||||
- disable: true # 是否禁用
|
||||
type: "" # 数据库的类型,目前支持mysql、pgsql、mssql、oracle
|
||||
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
|
||||
path: ""
|
||||
port: ""
|
||||
@@ -95,7 +157,6 @@ db-list:
|
||||
log-mode: ""
|
||||
log-zap: false
|
||||
|
||||
|
||||
# local configuration
|
||||
local:
|
||||
path: uploads/file
|
||||
@@ -172,30 +233,23 @@ hua-wei-obs:
|
||||
excel:
|
||||
dir: ./resource/excel/
|
||||
|
||||
# timer task db clear table
|
||||
Timer:
|
||||
start: true
|
||||
spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3
|
||||
detail:
|
||||
- tableName: sys_operation_records
|
||||
compareField: created_at
|
||||
interval: 2160h
|
||||
- tableName: jwt_blacklists
|
||||
compareField: created_at
|
||||
interval: 168h
|
||||
# disk usage configuration
|
||||
disk-list:
|
||||
- mount-point: "/"
|
||||
|
||||
# 跨域配置
|
||||
# 需要配合 server/initialize/router.go#L32 使用
|
||||
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
|
||||
cors:
|
||||
mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
|
||||
mode: strict-whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
|
||||
whitelist:
|
||||
- allow-origin: example1.com
|
||||
allow-headers: content-type
|
||||
allow-methods: GET, POST
|
||||
allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id
|
||||
allow-methods: POST, GET
|
||||
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||
|
||||
allow-credentials: true # 布尔值
|
||||
- allow-origin: example2.com
|
||||
allow-headers: content-type
|
||||
allow-methods: GET, POST
|
||||
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||
allow-credentials: true # 布尔值
|
||||
allow-credentials: true # 布尔值
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package config
|
||||
|
||||
type Autocode struct {
|
||||
TransferRestart bool `mapstructure:"transfer-restart" json:"transfer-restart" yaml:"transfer-restart"`
|
||||
Root string `mapstructure:"root" json:"root" yaml:"root"`
|
||||
SModel string `mapstructure:"server-model" json:"server-model" yaml:"server-model"`
|
||||
SRouter string `mapstructure:"server-router" json:"server-router" yaml:"server-router"`
|
||||
Server string `mapstructure:"server" json:"server" yaml:"server"`
|
||||
SApi string `mapstructure:"server-api" json:"server-api" yaml:"server-api"`
|
||||
SPlug string `mapstructure:"server-plug" json:"server-plug" yaml:"server-plug"`
|
||||
SInitialize string `mapstructure:"server-initialize" json:"server-initialize" yaml:"server-initialize"`
|
||||
SModel string `mapstructure:"server-model" json:"server-model" yaml:"server-model"`
|
||||
SRequest string `mapstructure:"server-request" json:"server-request" yaml:"server-request"`
|
||||
SRouter string `mapstructure:"server-router" json:"server-router" yaml:"server-router"`
|
||||
SService string `mapstructure:"server-service" json:"server-service" yaml:"server-service"`
|
||||
Root string `mapstructure:"root" json:"root" yaml:"root"`
|
||||
WTable string `mapstructure:"web-table" json:"web-table" yaml:"web-table"`
|
||||
Web string `mapstructure:"web" json:"web" yaml:"web"`
|
||||
SService string `mapstructure:"server-service" json:"server-service" yaml:"server-service"`
|
||||
SRequest string `mapstructure:"server-request" json:"server-request" yaml:"server-request"`
|
||||
WApi string `mapstructure:"web-api" json:"web-api" yaml:"web-api"`
|
||||
WForm string `mapstructure:"web-form" json:"web-form" yaml:"web-form"`
|
||||
WTable string `mapstructure:"web-table" json:"web-table" yaml:"web-table"`
|
||||
TransferRestart bool `mapstructure:"transfer-restart" json:"transfer-restart" yaml:"transfer-restart"`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package config
|
||||
|
||||
type Captcha struct {
|
||||
KeyLong int `mapstructure:"key-long" json:"key-long" yaml:"key-long"` // 验证码长度
|
||||
ImgWidth int `mapstructure:"img-width" json:"img-width" yaml:"img-width"` // 验证码宽度
|
||||
ImgHeight int `mapstructure:"img-height" json:"img-height" yaml:"img-height"` // 验证码高度
|
||||
KeyLong int `mapstructure:"key-long" json:"key-long" yaml:"key-long"` // 验证码长度
|
||||
ImgWidth int `mapstructure:"img-width" json:"img-width" yaml:"img-width"` // 验证码宽度
|
||||
ImgHeight int `mapstructure:"img-height" json:"img-height" yaml:"img-height"` // 验证码高度
|
||||
OpenCaptcha int `mapstructure:"open-captcha" json:"open-captcha" yaml:"open-captcha"` // 防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码
|
||||
OpenCaptchaTimeOut int `mapstructure:"open-captcha-timeout" json:"open-captcha-timeout" yaml:"open-captcha-timeout"` // 防爆破验证码超时时间,单位:s(秒)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ type Server struct {
|
||||
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
|
||||
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
|
||||
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
|
||||
Mongo Mongo `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
|
||||
Email Email `mapstructure:"email" json:"email" yaml:"email"`
|
||||
System System `mapstructure:"system" json:"system" yaml:"system"`
|
||||
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
|
||||
@@ -11,7 +12,10 @@ type Server struct {
|
||||
AutoCode Autocode `mapstructure:"autocode" json:"autocode" yaml:"autocode"`
|
||||
// gorm
|
||||
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
|
||||
Mssql Mssql `mapstructure:"mssql" json:"mssql" yaml:"mssql"`
|
||||
Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
|
||||
Oracle Oracle `mapstructure:"oracle" json:"oracle" yaml:"oracle"`
|
||||
Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"`
|
||||
DBList []SpecializedDB `mapstructure:"db-list" json:"db-list" yaml:"db-list"`
|
||||
// oss
|
||||
Local Local `mapstructure:"local" json:"local" yaml:"local"`
|
||||
@@ -22,7 +26,8 @@ type Server struct {
|
||||
AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"`
|
||||
|
||||
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
|
||||
Timer Timer `mapstructure:"timer" json:"timer" yaml:"timer"`
|
||||
|
||||
DiskList []DiskList `mapstructure:"disk-list" json:"disk-list" yaml:"disk-list"`
|
||||
|
||||
// 跨域配置
|
||||
Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"`
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"gorm.io/gorm/logger"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DsnProvider interface {
|
||||
Dsn() string
|
||||
}
|
||||
@@ -9,21 +14,39 @@ type DsnProvider interface {
|
||||
|
||||
// GeneralDB 也被 Pgsql 和 Mysql 原样使用
|
||||
type GeneralDB struct {
|
||||
Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址:端口
|
||||
Port string `mapstructure:"port" json:"port" yaml:"port"` //:端口
|
||||
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
|
||||
Dbname string `mapstructure:"db-name" json:"db-name" yaml:"db-name"` // 数据库名
|
||||
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
|
||||
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`
|
||||
Port string `mapstructure:"port" json:"port" yaml:"port"`
|
||||
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
|
||||
Dbname string `mapstructure:"db-name" json:"db-name" yaml:"db-name"` // 数据库名
|
||||
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库密码
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
|
||||
Path string `mapstructure:"path" json:"path" yaml:"path"`
|
||||
Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` // 数据库引擎,默认InnoDB
|
||||
LogMode string `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"` // 是否开启Gorm全局日志
|
||||
MaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"` // 空闲中的最大连接数
|
||||
MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
|
||||
LogMode string `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"` // 是否开启Gorm全局日志
|
||||
Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` // 是否开启全局禁用复数,true表示开启
|
||||
LogZap bool `mapstructure:"log-zap" json:"log-zap" yaml:"log-zap"` // 是否通过zap写入日志文件
|
||||
}
|
||||
|
||||
func (c GeneralDB) LogLevel() logger.LogLevel {
|
||||
switch strings.ToLower(c.LogMode) {
|
||||
case "silent", "Silent":
|
||||
return logger.Silent
|
||||
case "error", "Error":
|
||||
return logger.Error
|
||||
case "warn", "Warn":
|
||||
return logger.Warn
|
||||
case "info", "Info":
|
||||
return logger.Info
|
||||
default:
|
||||
return logger.Info
|
||||
}
|
||||
}
|
||||
|
||||
type SpecializedDB struct {
|
||||
Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"`
|
||||
Type string `mapstructure:"type" json:"type" yaml:"type"`
|
||||
AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"`
|
||||
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
||||
Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
type Disk struct {
|
||||
MountPoint string `mapstructure:"mount-point" json:"mount-point" yaml:"mount-point"`
|
||||
}
|
||||
|
||||
type DiskList struct {
|
||||
Disk `yaml:",inline" mapstructure:",squash"`
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package config
|
||||
|
||||
type Email struct {
|
||||
To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔
|
||||
Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口
|
||||
From string `mapstructure:"from" json:"from" yaml:"from"` // 收件人
|
||||
Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址
|
||||
IsSSL bool `mapstructure:"is-ssl" json:"is-ssl" yaml:"is-ssl"` // 是否SSL
|
||||
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
|
||||
Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称
|
||||
To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用
|
||||
From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱
|
||||
Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议
|
||||
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥
|
||||
Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱
|
||||
Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465
|
||||
IsSSL bool `mapstructure:"is-ssl" json:"is-ssl" yaml:"is-ssl"` // 是否SSL 是否开启SSL
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
type Mssql struct {
|
||||
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
||||
}
|
||||
|
||||
// Dsn "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
|
||||
func (m *Mssql) Dsn() string {
|
||||
return "sqlserver://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "?database=" + m.Dbname + "&encrypt=disable"
|
||||
}
|
||||
@@ -7,7 +7,3 @@ type Mysql struct {
|
||||
func (m *Mysql) Dsn() string {
|
||||
return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
|
||||
}
|
||||
|
||||
func (m *Mysql) GetLogMode() string {
|
||||
return m.LogMode
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
type Oracle struct {
|
||||
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
||||
}
|
||||
|
||||
func (m *Oracle) Dsn() string {
|
||||
return "oracle://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "/" + m.Dbname + "?" + m.Config
|
||||
|
||||
}
|
||||
@@ -15,7 +15,3 @@ func (p *Pgsql) Dsn() string {
|
||||
func (p *Pgsql) LinkDsn(dbname string) string {
|
||||
return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + dbname + " port=" + p.Port + " " + p.Config
|
||||
}
|
||||
|
||||
func (m *Pgsql) GetLogMode() string {
|
||||
return m.LogMode
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Sqlite struct {
|
||||
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
||||
}
|
||||
|
||||
func (s *Sqlite) Dsn() string {
|
||||
return filepath.Join(s.Path, s.Dbname+".db")
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Mongo struct {
|
||||
Coll string `json:"coll" yaml:"coll" mapstructure:"coll"` // collection name
|
||||
Options string `json:"options" yaml:"options" mapstructure:"options"` // mongodb options
|
||||
Database string `json:"database" yaml:"database" mapstructure:"database"` // database name
|
||||
Username string `json:"username" yaml:"username" mapstructure:"username"` // 用户名
|
||||
Password string `json:"password" yaml:"password" mapstructure:"password"` // 密码
|
||||
AuthSource string `json:"auth-source" yaml:"auth-source" mapstructure:"auth-source"` // 验证数据库
|
||||
MinPoolSize uint64 `json:"min-pool-size" yaml:"min-pool-size" mapstructure:"min-pool-size"` // 最小连接池
|
||||
MaxPoolSize uint64 `json:"max-pool-size" yaml:"max-pool-size" mapstructure:"max-pool-size"` // 最大连接池
|
||||
SocketTimeoutMs int64 `json:"socket-timeout-ms" yaml:"socket-timeout-ms" mapstructure:"socket-timeout-ms"` // socket超时时间
|
||||
ConnectTimeoutMs int64 `json:"connect-timeout-ms" yaml:"connect-timeout-ms" mapstructure:"connect-timeout-ms"` // 连接超时时间
|
||||
IsZap bool `json:"is-zap" yaml:"is-zap" mapstructure:"is-zap"` // 是否开启zap日志
|
||||
Hosts []*MongoHost `json:"hosts" yaml:"hosts" mapstructure:"hosts"` // 主机列表
|
||||
}
|
||||
|
||||
type MongoHost struct {
|
||||
Host string `json:"host" yaml:"host" mapstructure:"host"` // ip地址
|
||||
Port string `json:"port" yaml:"port" mapstructure:"port"` // 端口
|
||||
}
|
||||
|
||||
// Uri .
|
||||
func (x *Mongo) Uri() string {
|
||||
length := len(x.Hosts)
|
||||
hosts := make([]string, 0, length)
|
||||
for i := 0; i < length; i++ {
|
||||
if x.Hosts[i].Host != "" && x.Hosts[i].Port != "" {
|
||||
hosts = append(hosts, x.Hosts[i].Host+":"+x.Hosts[i].Port)
|
||||
}
|
||||
}
|
||||
if x.Options != "" {
|
||||
return fmt.Sprintf("mongodb://%s/%s?%s", strings.Join(hosts, ","), x.Database, x.Options)
|
||||
}
|
||||
return fmt.Sprintf("mongodb://%s/%s", strings.Join(hosts, ","), x.Database)
|
||||
}
|
||||
@@ -4,10 +4,10 @@ type AwsS3 struct {
|
||||
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
|
||||
Region string `mapstructure:"region" json:"region" yaml:"region"`
|
||||
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
|
||||
S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3-force-path-style" yaml:"s3-force-path-style"`
|
||||
DisableSSL bool `mapstructure:"disable-ssl" json:"disable-ssl" yaml:"disable-ssl"`
|
||||
SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"`
|
||||
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
|
||||
BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
|
||||
PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"`
|
||||
S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3-force-path-style" yaml:"s3-force-path-style"`
|
||||
DisableSSL bool `mapstructure:"disable-ssl" json:"disable-ssl" yaml:"disable-ssl"`
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ type Qiniu struct {
|
||||
Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域
|
||||
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称
|
||||
ImgPath string `mapstructure:"img-path" json:"img-path" yaml:"img-path"` // CDN加速域名
|
||||
UseHTTPS bool `mapstructure:"use-https" json:"use-https" yaml:"use-https"` // 是否使用https
|
||||
AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"` // 秘钥AK
|
||||
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` // 秘钥SK
|
||||
UseHTTPS bool `mapstructure:"use-https" json:"use-https" yaml:"use-https"` // 是否使用https
|
||||
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"use-cdn-domains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package config
|
||||
|
||||
type Redis struct {
|
||||
DB int `mapstructure:"db" json:"db" yaml:"db"` // redis的哪个数据库
|
||||
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
|
||||
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
|
||||
DB int `mapstructure:"db" json:"db" yaml:"db"` // 单实例模式下redis的哪个数据库
|
||||
UseCluster bool `mapstructure:"useCluster" json:"useCluster" yaml:"useCluster"` // 是否使用集群模式
|
||||
ClusterAddrs []string `mapstructure:"clusterAddrs" json:"clusterAddrs" yaml:"clusterAddrs"` // 集群模式下的节点地址列表
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package config
|
||||
|
||||
type System struct {
|
||||
Env string `mapstructure:"env" json:"env" yaml:"env"` // 环境值
|
||||
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
|
||||
DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
|
||||
OssType string `mapstructure:"oss-type" json:"oss-type" yaml:"oss-type"` // Oss类型
|
||||
UseMultipoint bool `mapstructure:"use-multipoint" json:"use-multipoint" yaml:"use-multipoint"` // 多点登录拦截
|
||||
UseRedis bool `mapstructure:"use-redis" json:"use-redis" yaml:"use-redis"` // 使用redis
|
||||
DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
|
||||
OssType string `mapstructure:"oss-type" json:"oss-type" yaml:"oss-type"` // Oss类型
|
||||
RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"`
|
||||
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
|
||||
LimitCountIP int `mapstructure:"iplimit-count" json:"iplimit-count" yaml:"iplimit-count"`
|
||||
LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimit-time" yaml:"iplimit-time"`
|
||||
UseMultipoint bool `mapstructure:"use-multipoint" json:"use-multipoint" yaml:"use-multipoint"` // 多点登录拦截
|
||||
UseRedis bool `mapstructure:"use-redis" json:"use-redis" yaml:"use-redis"` // 使用redis
|
||||
UseMongo bool `mapstructure:"use-mongo" json:"use-mongo" yaml:"use-mongo"` // 使用mongo
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package config
|
||||
|
||||
type Timer struct {
|
||||
Start bool `mapstructure:"start" json:"start" yaml:"start"` // 是否启用
|
||||
Spec string `mapstructure:"spec" json:"spec" yaml:"spec"` // CRON表达式
|
||||
WithSeconds bool `mapstructure:"with_seconds" json:"with_seconds" yaml:"with_seconds"` // 是否精确到秒
|
||||
Detail []Detail `mapstructure:"detail" json:"detail" yaml:"detail"`
|
||||
}
|
||||
|
||||
type Detail struct {
|
||||
TableName string `mapstructure:"tableName" json:"tableName" yaml:"tableName"` // 需要清理的表名
|
||||
CompareField string `mapstructure:"compareField" json:"compareField" yaml:"compareField"` // 需要比较时间的字段
|
||||
Interval string `mapstructure:"interval" json:"interval" yaml:"interval"` // 时间间隔
|
||||
}
|
||||
+45
-35
@@ -2,7 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Zap struct {
|
||||
@@ -12,49 +12,59 @@ type Zap struct {
|
||||
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
|
||||
EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` // 编码级
|
||||
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` // 栈名
|
||||
|
||||
MaxAge int `mapstructure:"max-age" json:"max-age" yaml:"max-age"` // 日志留存时间
|
||||
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
|
||||
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
|
||||
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
|
||||
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
|
||||
}
|
||||
|
||||
// ZapEncodeLevel 根据 EncodeLevel 返回 zapcore.LevelEncoder
|
||||
// Levels 根据字符串转化为 zapcore.Levels
|
||||
func (c *Zap) Levels() []zapcore.Level {
|
||||
levels := make([]zapcore.Level, 0, 7)
|
||||
level, err := zapcore.ParseLevel(c.Level)
|
||||
if err != nil {
|
||||
level = zapcore.DebugLevel
|
||||
}
|
||||
for ; level <= zapcore.FatalLevel; level++ {
|
||||
levels = append(levels, level)
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
func (c *Zap) Encoder() zapcore.Encoder {
|
||||
config := zapcore.EncoderConfig{
|
||||
TimeKey: "time",
|
||||
NameKey: "name",
|
||||
LevelKey: "level",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "message",
|
||||
StacktraceKey: c.StacktraceKey,
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
|
||||
encoder.AppendString(c.Prefix + t.Format("2006-01-02 15:04:05.000"))
|
||||
},
|
||||
EncodeLevel: c.LevelEncoder(),
|
||||
EncodeCaller: zapcore.FullCallerEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
}
|
||||
if c.Format == "json" {
|
||||
return zapcore.NewJSONEncoder(config)
|
||||
}
|
||||
return zapcore.NewConsoleEncoder(config)
|
||||
|
||||
}
|
||||
|
||||
// LevelEncoder 根据 EncodeLevel 返回 zapcore.LevelEncoder
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *Zap) ZapEncodeLevel() zapcore.LevelEncoder {
|
||||
func (c *Zap) LevelEncoder() zapcore.LevelEncoder {
|
||||
switch {
|
||||
case z.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
|
||||
case c.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
|
||||
return zapcore.LowercaseLevelEncoder
|
||||
case z.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
|
||||
case c.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
|
||||
return zapcore.LowercaseColorLevelEncoder
|
||||
case z.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
|
||||
case c.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
|
||||
return zapcore.CapitalLevelEncoder
|
||||
case z.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
|
||||
case c.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
|
||||
return zapcore.CapitalColorLevelEncoder
|
||||
default:
|
||||
return zapcore.LowercaseLevelEncoder
|
||||
}
|
||||
}
|
||||
|
||||
// TransportLevel 根据字符串转化为 zapcore.Level
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *Zap) TransportLevel() zapcore.Level {
|
||||
z.Level = strings.ToLower(z.Level)
|
||||
switch z.Level {
|
||||
case "debug":
|
||||
return zapcore.DebugLevel
|
||||
case "info":
|
||||
return zapcore.InfoLevel
|
||||
case "warn":
|
||||
return zapcore.WarnLevel
|
||||
case "error":
|
||||
return zapcore.WarnLevel
|
||||
case "dpanic":
|
||||
return zapcore.DPanicLevel
|
||||
case "panic":
|
||||
return zapcore.PanicLevel
|
||||
case "fatal":
|
||||
return zapcore.FatalLevel
|
||||
default:
|
||||
return zapcore.DebugLevel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cutter 实现 io.Writer 接口
|
||||
// 用于日志切割, strings.Join([]string{director,layout, formats..., level+".log"}, os.PathSeparator)
|
||||
type Cutter struct {
|
||||
level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
|
||||
layout string // 时间格式 2006-01-02 15:04:05
|
||||
formats []string // 自定义参数([]string{Director,"2006-01-02", "business"(此参数可不写), level+".log"}
|
||||
director string // 日志文件夹
|
||||
file *os.File // 文件句柄
|
||||
mutex *sync.RWMutex // 读写锁
|
||||
}
|
||||
|
||||
type CutterOption func(*Cutter)
|
||||
|
||||
// CutterWithLayout 时间格式
|
||||
func CutterWithLayout(layout string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
c.layout = layout
|
||||
}
|
||||
}
|
||||
|
||||
// CutterWithFormats 格式化参数
|
||||
func CutterWithFormats(format ...string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
if len(format) > 0 {
|
||||
c.formats = format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewCutter(director string, level string, options ...CutterOption) *Cutter {
|
||||
rotate := &Cutter{
|
||||
level: level,
|
||||
director: director,
|
||||
mutex: new(sync.RWMutex),
|
||||
}
|
||||
for i := 0; i < len(options); i++ {
|
||||
options[i](rotate)
|
||||
}
|
||||
return rotate
|
||||
}
|
||||
|
||||
// Write satisfies the io.Writer interface. It writes to the
|
||||
// appropriate file handle that is currently being used.
|
||||
// If we have reached rotation time, the target file gets
|
||||
// automatically rotated, and also purged if necessary.
|
||||
func (c *Cutter) Write(bytes []byte) (n int, err error) {
|
||||
c.mutex.Lock()
|
||||
defer func() {
|
||||
if c.file != nil {
|
||||
_ = c.file.Close()
|
||||
c.file = nil
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
}()
|
||||
length := len(c.formats)
|
||||
values := make([]string, 0, 3+length)
|
||||
values = append(values, c.director)
|
||||
if c.layout != "" {
|
||||
values = append(values, time.Now().Format(c.layout))
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
values = append(values, c.formats[i])
|
||||
}
|
||||
values = append(values, c.level+".log")
|
||||
filename := filepath.Join(values...)
|
||||
director := filepath.Dir(filename)
|
||||
err = os.MkdirAll(director, os.ModePerm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c.file.Write(bytes)
|
||||
}
|
||||
|
||||
func (c *Cutter) Sync() error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if c.file != nil {
|
||||
return c.file.Sync()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
var FileRotatelogs = new(fileRotatelogs)
|
||||
|
||||
type fileRotatelogs struct{}
|
||||
|
||||
// GetWriteSyncer 获取 zapcore.WriteSyncer
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (r *fileRotatelogs) GetWriteSyncer(level string) (zapcore.WriteSyncer, error) {
|
||||
fileWriter, err := rotatelogs.New(
|
||||
path.Join(global.GVA_CONFIG.Zap.Director, "%Y-%m-%d", level+".log"),
|
||||
rotatelogs.WithClock(rotatelogs.Local),
|
||||
rotatelogs.WithMaxAge(time.Duration(global.GVA_CONFIG.Zap.MaxAge)*24*time.Hour), // 日志留存时间
|
||||
rotatelogs.WithRotationTime(time.Hour*24),
|
||||
)
|
||||
if global.GVA_CONFIG.Zap.LogInConsole {
|
||||
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter)), err
|
||||
}
|
||||
return zapcore.AddSync(fileWriter), err
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"time"
|
||||
)
|
||||
|
||||
var Zap = new(_zap)
|
||||
|
||||
type _zap struct{}
|
||||
|
||||
// GetEncoder 获取 zapcore.Encoder
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) GetEncoder() zapcore.Encoder {
|
||||
if global.GVA_CONFIG.Zap.Format == "json" {
|
||||
return zapcore.NewJSONEncoder(z.GetEncoderConfig())
|
||||
}
|
||||
return zapcore.NewConsoleEncoder(z.GetEncoderConfig())
|
||||
}
|
||||
|
||||
// GetEncoderConfig 获取zapcore.EncoderConfig
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) GetEncoderConfig() zapcore.EncoderConfig {
|
||||
return zapcore.EncoderConfig{
|
||||
MessageKey: "message",
|
||||
LevelKey: "level",
|
||||
TimeKey: "time",
|
||||
NameKey: "logger",
|
||||
CallerKey: "caller",
|
||||
StacktraceKey: global.GVA_CONFIG.Zap.StacktraceKey,
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: global.GVA_CONFIG.Zap.ZapEncodeLevel(),
|
||||
EncodeTime: z.CustomTimeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.FullCallerEncoder,
|
||||
}
|
||||
}
|
||||
|
||||
// GetEncoderCore 获取Encoder的 zapcore.Core
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) GetEncoderCore(l zapcore.Level, level zap.LevelEnablerFunc) zapcore.Core {
|
||||
writer, err := FileRotatelogs.GetWriteSyncer(l.String()) // 使用file-rotatelogs进行日志分割
|
||||
if err != nil {
|
||||
fmt.Printf("Get Write Syncer Failed err:%v", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return zapcore.NewCore(z.GetEncoder(), writer, level)
|
||||
}
|
||||
|
||||
// CustomTimeEncoder 自定义日志输出时间格式
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) CustomTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
|
||||
encoder.AppendString(global.GVA_CONFIG.Zap.Prefix + t.Format("2006/01/02 - 15:04:05.000"))
|
||||
}
|
||||
|
||||
// GetZapCores 根据配置文件的Level获取 []zapcore.Core
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) GetZapCores() []zapcore.Core {
|
||||
cores := make([]zapcore.Core, 0, 7)
|
||||
for level := global.GVA_CONFIG.Zap.TransportLevel(); level <= zapcore.FatalLevel; level++ {
|
||||
cores = append(cores, z.GetEncoderCore(level, z.GetLevelPriority(level)))
|
||||
}
|
||||
return cores
|
||||
}
|
||||
|
||||
// GetLevelPriority 根据 zapcore.Level 获取 zap.LevelEnablerFunc
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (z *_zap) GetLevelPriority(level zapcore.Level) zap.LevelEnablerFunc {
|
||||
switch level {
|
||||
case zapcore.DebugLevel:
|
||||
return func(level zapcore.Level) bool { // 调试级别
|
||||
return level == zap.DebugLevel
|
||||
}
|
||||
case zapcore.InfoLevel:
|
||||
return func(level zapcore.Level) bool { // 日志级别
|
||||
return level == zap.InfoLevel
|
||||
}
|
||||
case zapcore.WarnLevel:
|
||||
return func(level zapcore.Level) bool { // 警告级别
|
||||
return level == zap.WarnLevel
|
||||
}
|
||||
case zapcore.ErrorLevel:
|
||||
return func(level zapcore.Level) bool { // 错误级别
|
||||
return level == zap.ErrorLevel
|
||||
}
|
||||
case zapcore.DPanicLevel:
|
||||
return func(level zapcore.Level) bool { // dpanic级别
|
||||
return level == zap.DPanicLevel
|
||||
}
|
||||
case zapcore.PanicLevel:
|
||||
return func(level zapcore.Level) bool { // panic级别
|
||||
return level == zap.PanicLevel
|
||||
}
|
||||
case zapcore.FatalLevel:
|
||||
return func(level zapcore.Level) bool { // 终止级别
|
||||
return level == zap.FatalLevel
|
||||
}
|
||||
default:
|
||||
return func(level zapcore.Level) bool { // 调试级别
|
||||
return level == zap.DebugLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ZapCore struct {
|
||||
level zapcore.Level
|
||||
zapcore.Core
|
||||
}
|
||||
|
||||
func NewZapCore(level zapcore.Level) *ZapCore {
|
||||
entity := &ZapCore{level: level}
|
||||
syncer := entity.WriteSyncer()
|
||||
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
|
||||
return l == level
|
||||
})
|
||||
entity.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, levelEnabler)
|
||||
return entity
|
||||
}
|
||||
|
||||
func (z *ZapCore) WriteSyncer(formats ...string) zapcore.WriteSyncer {
|
||||
cutter := NewCutter(
|
||||
global.GVA_CONFIG.Zap.Director,
|
||||
z.level.String(),
|
||||
CutterWithLayout(time.DateOnly),
|
||||
CutterWithFormats(formats...),
|
||||
)
|
||||
if global.GVA_CONFIG.Zap.LogInConsole {
|
||||
multiSyncer := zapcore.NewMultiWriteSyncer(os.Stdout, cutter)
|
||||
return zapcore.AddSync(multiSyncer)
|
||||
}
|
||||
return zapcore.AddSync(cutter)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Enabled(level zapcore.Level) bool {
|
||||
return z.level == level
|
||||
}
|
||||
|
||||
func (z *ZapCore) With(fields []zapcore.Field) zapcore.Core {
|
||||
return z.Core.With(fields)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Check(entry zapcore.Entry, check *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
if z.Enabled(entry.Level) {
|
||||
return check.AddCore(entry, z)
|
||||
}
|
||||
return check
|
||||
}
|
||||
|
||||
func (z *ZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i].Key == "business" || fields[i].Key == "folder" || fields[i].Key == "directory" {
|
||||
syncer := z.WriteSyncer(fields[i].String)
|
||||
z.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, z.level)
|
||||
}
|
||||
}
|
||||
return z.Core.Write(entry, fields)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Sync() error {
|
||||
return z.Core.Sync()
|
||||
}
|
||||
+14
-9
@@ -2,8 +2,6 @@ package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service/system"
|
||||
@@ -19,7 +17,12 @@ func RunWindowsServer() {
|
||||
// 初始化redis服务
|
||||
initialize.Redis()
|
||||
}
|
||||
|
||||
if global.GVA_CONFIG.System.UseMongo {
|
||||
err := initialize.Mongo.Initialization()
|
||||
if err != nil {
|
||||
zap.L().Error(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
}
|
||||
// 从db加载jwt数据
|
||||
if global.GVA_DB != nil {
|
||||
system.LoadAll()
|
||||
@@ -30,20 +33,22 @@ func RunWindowsServer() {
|
||||
|
||||
address := fmt.Sprintf(":%d", global.GVA_CONFIG.System.Addr)
|
||||
s := initServer(address, Router)
|
||||
// 保证文本顺序输出
|
||||
// In order to ensure that the text order output can be deleted
|
||||
time.Sleep(10 * time.Microsecond)
|
||||
|
||||
global.GVA_LOG.Info("server run success on ", zap.String("address", address))
|
||||
|
||||
fmt.Printf(`
|
||||
欢迎使用 gin-vue-admin
|
||||
当前版本:v2.5.4
|
||||
加群方式:微信号:shouzi_1994 QQ群:622360840
|
||||
当前版本:v2.6.5
|
||||
加群方式:微信号:shouzi_1994 QQ群:470239250
|
||||
项目地址:https://github.com/flipped-aurora/gin-vue-admin
|
||||
插件市场:https://plugin.gin-vue-admin.com
|
||||
GVA讨论社区:https://support.qq.com/products/371961
|
||||
默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
|
||||
默认前端文件运行地址:http://127.0.0.1:8080
|
||||
如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html
|
||||
--------------------------------------版权声明--------------------------------------
|
||||
** 版权所有方:flipped-aurora开源团队 **
|
||||
** 版权持有公司:北京翻转极光科技有限责任公司 **
|
||||
** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **
|
||||
`, address)
|
||||
global.GVA_LOG.Error(s.ListenAndServe().Error())
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ func Viper(path ...string) *viper.Viper {
|
||||
switch gin.Mode() {
|
||||
case gin.DebugMode:
|
||||
config = internal.ConfigDefaultFile
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigDefaultFile)
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.Mode(), internal.ConfigDefaultFile)
|
||||
case gin.ReleaseMode:
|
||||
config = internal.ConfigReleaseFile
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigReleaseFile)
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.Mode(), internal.ConfigReleaseFile)
|
||||
case gin.TestMode:
|
||||
config = internal.ConfigTestFile
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigTestFile)
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.Mode(), internal.ConfigTestFile)
|
||||
}
|
||||
} else { // internal.ConfigEnv 常量存储的环境变量不为空 将值赋值于config
|
||||
config = configEnv
|
||||
@@ -65,7 +65,7 @@ func Viper(path ...string) *viper.Viper {
|
||||
}
|
||||
})
|
||||
if err = v.Unmarshal(&global.GVA_CONFIG); err != nil {
|
||||
fmt.Println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// root 适配性 根据root位置去找到对应迁移位置,保证root路径有效
|
||||
|
||||
+7
-3
@@ -17,10 +17,14 @@ func Zap() (logger *zap.Logger) {
|
||||
fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director)
|
||||
_ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm)
|
||||
}
|
||||
|
||||
cores := internal.Zap.GetZapCores()
|
||||
levels := global.GVA_CONFIG.Zap.Levels()
|
||||
length := len(levels)
|
||||
cores := make([]zapcore.Core, 0, length)
|
||||
for i := 0; i < length; i++ {
|
||||
core := internal.NewZapCore(levels[i])
|
||||
cores = append(cores, core)
|
||||
}
|
||||
logger = zap.New(zapcore.NewTee(cores...))
|
||||
|
||||
if global.GVA_CONFIG.Zap.ShowLine {
|
||||
logger = logger.WithOptions(zap.AddCaller())
|
||||
}
|
||||
|
||||
+705
-531
File diff suppressed because it is too large
Load Diff
+693
-482
File diff suppressed because it is too large
Load Diff
+478
-331
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/qiniu/qmgo"
|
||||
"sync"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils/timer"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -20,7 +21,8 @@ import (
|
||||
var (
|
||||
GVA_DB *gorm.DB
|
||||
GVA_DBList map[string]*gorm.DB
|
||||
GVA_REDIS *redis.Client
|
||||
GVA_REDIS redis.UniversalClient
|
||||
GVA_MONGO *qmgo.QmgoClient
|
||||
GVA_CONFIG config.Server
|
||||
GVA_VP *viper.Viper
|
||||
// GVA_LOG *oplogging.Logger
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type GVA_MODEL struct {
|
||||
ID uint `gorm:"primarykey"` // 主键ID
|
||||
ID uint `gorm:"primarykey" json:"ID"` // 主键ID
|
||||
CreatedAt time.Time // 创建时间
|
||||
UpdatedAt time.Time // 更新时间
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间
|
||||
|
||||
+144
-44
@@ -1,59 +1,159 @@
|
||||
module github.com/flipped-aurora/gin-vue-admin/server
|
||||
|
||||
go 1.16
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible
|
||||
github.com/aws/aws-sdk-go v1.42.27
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
|
||||
github.com/casbin/casbin/v2 v2.51.0
|
||||
github.com/casbin/gorm-adapter/v3 v3.7.3
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible
|
||||
github.com/aws/aws-sdk-go v1.44.307
|
||||
github.com/casbin/casbin/v2 v2.87.1
|
||||
github.com/casbin/gorm-adapter/v3 v3.18.0
|
||||
github.com/flipped-aurora/ws v1.0.2
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
||||
github.com/gin-gonic/gin v1.7.0
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.4
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/gookit/color v1.3.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/glebarez/sqlite v1.8.0
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/gookit/color v1.5.4
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible
|
||||
github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/lestrrat-go/strftime v1.0.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
||||
github.com/mojocn/base64Captcha v1.3.1
|
||||
github.com/mojocn/base64Captcha v1.3.6
|
||||
github.com/otiai10/copy v1.7.0
|
||||
github.com/pelletier/go-toml v1.6.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/qiniu/api.v7/v7 v7.4.1
|
||||
github.com/qiniu/qmgo v1.1.8
|
||||
github.com/redis/go-redis/v9 v9.0.5
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.5
|
||||
github.com/songzhibin97/gkit v1.2.7
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.6
|
||||
github.com/songzhibin97/gkit v1.2.11
|
||||
github.com/spf13/viper v1.16.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.2
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.42
|
||||
github.com/unrolled/secure v1.13.0
|
||||
github.com/xuri/excelize/v2 v2.8.0
|
||||
go.mongodb.org/mongo-driver v1.12.1
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/text v0.14.0
|
||||
gorm.io/driver/mysql v1.5.6
|
||||
gorm.io/driver/postgres v1.5.7
|
||||
gorm.io/driver/sqlserver v1.5.1
|
||||
gorm.io/gorm v1.25.10
|
||||
nhooyr.io/websocket v1.8.7
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/bodgit/plumbing v1.2.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.3.0 // indirect
|
||||
github.com/bodgit/windows v1.0.0 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/casbin/govaluate v1.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/clbanning/mxj v1.8.4 // indirect
|
||||
github.com/connesc/cipherio v0.2.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.3 // indirect
|
||||
github.com/go-openapi/spec v0.20.12 // indirect
|
||||
github.com/go-openapi/swag v0.22.5 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/montanaflynn/stats v0.7.0 // indirect
|
||||
github.com/mozillazg/go-httpheader v0.2.1 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.3 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/spf13/afero v1.9.5 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.19
|
||||
github.com/unrolled/secure v1.0.7
|
||||
github.com/xuri/excelize/v2 v2.4.1
|
||||
go.uber.org/zap v1.16.0
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.5 // indirect
|
||||
gopkg.in/ini.v1 v1.55.0 // indirect
|
||||
gorm.io/driver/mysql v1.3.3
|
||||
gorm.io/driver/postgres v1.3.4
|
||||
gorm.io/gorm v1.23.4
|
||||
nhooyr.io/websocket v1.8.6
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
|
||||
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/image v0.15.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/datatypes v1.2.0 // indirect
|
||||
gorm.io/plugin/dbresolver v1.4.1 // indirect
|
||||
modernc.org/libc v1.24.1 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.6.0 // indirect
|
||||
modernc.org/sqlite v1.23.0 // indirect
|
||||
)
|
||||
|
||||
+578
-715
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,12 @@ func DBList() {
|
||||
switch info.Type {
|
||||
case "mysql":
|
||||
dbMap[info.AliasName] = GormMysqlByConfig(config.Mysql{GeneralDB: info.GeneralDB})
|
||||
case "mssql":
|
||||
dbMap[info.AliasName] = GormMssqlByConfig(config.Mssql{GeneralDB: info.GeneralDB})
|
||||
case "pgsql":
|
||||
dbMap[info.AliasName] = GormPgSqlByConfig(config.Pgsql{GeneralDB: info.GeneralDB})
|
||||
case "oracle":
|
||||
dbMap[info.AliasName] = GormOracleByConfig(config.Oracle{GeneralDB: info.GeneralDB})
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ func (e *ensureTables) MigrateTable(ctx context.Context) (context.Context, error
|
||||
sysModel.SysBaseMenuBtn{},
|
||||
sysModel.SysAuthorityBtn{},
|
||||
sysModel.SysAutoCode{},
|
||||
sysModel.SysExportTemplate{},
|
||||
sysModel.Condition{},
|
||||
sysModel.JoinTemplate{},
|
||||
|
||||
adapter.CasbinRule{},
|
||||
|
||||
@@ -83,6 +86,9 @@ func (e *ensureTables) TableCreated(ctx context.Context) bool {
|
||||
sysModel.SysBaseMenuBtn{},
|
||||
sysModel.SysAuthorityBtn{},
|
||||
sysModel.SysAutoCode{},
|
||||
sysModel.SysExportTemplate{},
|
||||
sysModel.Condition{},
|
||||
sysModel.JoinTemplate{},
|
||||
|
||||
adapter.CasbinRule{},
|
||||
|
||||
|
||||
+12
-12
@@ -11,24 +11,27 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Gorm 初始化数据库并产生数据库全局变量
|
||||
// Author SliverHorn
|
||||
func Gorm() *gorm.DB {
|
||||
switch global.GVA_CONFIG.System.DbType {
|
||||
case "mysql":
|
||||
return GormMysql()
|
||||
case "pgsql":
|
||||
return GormPgSql()
|
||||
case "oracle":
|
||||
return GormOracle()
|
||||
case "mssql":
|
||||
return GormMssql()
|
||||
case "sqlite":
|
||||
return GormSqlite()
|
||||
default:
|
||||
return GormMysql()
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterTables 注册数据库表专用
|
||||
// Author SliverHorn
|
||||
func RegisterTables(db *gorm.DB) {
|
||||
func RegisterTables() {
|
||||
db := global.GVA_DB
|
||||
err := db.AutoMigrate(
|
||||
// 系统模块表
|
||||
|
||||
system.SysApi{},
|
||||
system.SysUser{},
|
||||
system.SysBaseMenu{},
|
||||
@@ -42,17 +45,14 @@ func RegisterTables(db *gorm.DB) {
|
||||
system.SysBaseMenuBtn{},
|
||||
system.SysAuthorityBtn{},
|
||||
system.SysAutoCode{},
|
||||
system.SysExportTemplate{},
|
||||
system.Condition{},
|
||||
system.JoinTemplate{},
|
||||
|
||||
// 示例模块表
|
||||
example.ExaFile{},
|
||||
example.ExaCustomer{},
|
||||
example.ExaFileChunk{},
|
||||
example.ExaFileUploadAndDownload{},
|
||||
|
||||
// 自动化模块表
|
||||
// Code generated by github.com/flipped-aurora/gin-vue-admin/server Begin; DO NOT EDIT.
|
||||
|
||||
// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
|
||||
)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("register table failed", zap.Error(err))
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* @Author: 逆光飞翔 191180776@qq.com
|
||||
* @Date: 2022-12-08 17:25:49
|
||||
* @LastEditors: 逆光飞翔 191180776@qq.com
|
||||
* @LastEditTime: 2022-12-08 18:00:00
|
||||
* @FilePath: \server\initialize\gorm_mssql.go
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||
"gorm.io/driver/sqlserver"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormMssql 初始化Mssql数据库
|
||||
// Author [LouisZhang](191180776@qq.com)
|
||||
func GormMssql() *gorm.DB {
|
||||
m := global.GVA_CONFIG.Mssql
|
||||
if m.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
mssqlConfig := sqlserver.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
}
|
||||
if db, err := gorm.Open(sqlserver.New(mssqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine)
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// GormMssqlByConfig 初始化Mysql数据库用过传入配置
|
||||
func GormMssqlByConfig(m config.Mssql) *gorm.DB {
|
||||
if m.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
mssqlConfig := sqlserver.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
}
|
||||
if db, err := gorm.Open(sqlserver.New(mssqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
db.InstanceSet("gorm:table_options", "ENGINE=InnoDB")
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -21,9 +22,10 @@ func GormMysql() *gorm.DB {
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
SkipInitializeWithVersion: false, // 根据版本自动配置
|
||||
}
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config()); err != nil {
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine)
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
@@ -41,9 +43,10 @@ func GormMysqlByConfig(m config.Mysql) *gorm.DB {
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
SkipInitializeWithVersion: false, // 根据版本自动配置
|
||||
}
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config()); err != nil {
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
db.InstanceSet("gorm:table_options", "ENGINE=InnoDB")
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
//"github.com/dzwvip/oracle"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||
|
||||
//_ "github.com/godror/godror"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormOracle 初始化oracle数据库
|
||||
// 如果需要Oracle库 放开import里的注释 把下方 mysql.Config 改为 oracle.Config ; mysql.New 改为 oracle.New
|
||||
func GormOracle() *gorm.DB {
|
||||
m := global.GVA_CONFIG.Oracle
|
||||
if m.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
oracleConfig := mysql.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
}
|
||||
if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// GormOracleByConfig 初始化Oracle数据库用过传入配置
|
||||
func GormOracleByConfig(m config.Oracle) *gorm.DB {
|
||||
if m.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
oracleConfig := mysql.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
}
|
||||
if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func GormPgSql() *gorm.DB {
|
||||
DSN: p.Dsn(), // DSN data source name
|
||||
PreferSimpleProtocol: false,
|
||||
}
|
||||
if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config()); err != nil {
|
||||
if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
@@ -39,7 +39,7 @@ func GormPgSqlByConfig(p config.Pgsql) *gorm.DB {
|
||||
DSN: p.Dsn(), // DSN data source name
|
||||
PreferSimpleProtocol: false,
|
||||
}
|
||||
if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config()); err != nil {
|
||||
if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormSqlite 初始化Sqlite数据库
|
||||
func GormSqlite() *gorm.DB {
|
||||
s := global.GVA_CONFIG.Sqlite
|
||||
if s.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(s.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(s.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// GormSqliteByConfig 初始化Sqlite数据库用过传入配置
|
||||
func GormSqliteByConfig(s config.Sqlite) *gorm.DB {
|
||||
if s.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(s.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(s.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,48 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DBBASE interface {
|
||||
GetLogMode() string
|
||||
}
|
||||
|
||||
var Gorm = new(_gorm)
|
||||
|
||||
type _gorm struct{}
|
||||
|
||||
// Config gorm 自定义配置
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (g *_gorm) Config() *gorm.Config {
|
||||
config := &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}
|
||||
_default := logger.New(NewWriter(log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
|
||||
SlowThreshold: 200 * time.Millisecond,
|
||||
LogLevel: logger.Warn,
|
||||
Colorful: true,
|
||||
})
|
||||
var logMode DBBASE
|
||||
func (g *_gorm) Config(prefix string, singular bool) *gorm.Config {
|
||||
var general config.GeneralDB
|
||||
switch global.GVA_CONFIG.System.DbType {
|
||||
case "mysql":
|
||||
logMode = &global.GVA_CONFIG.Mysql
|
||||
general = global.GVA_CONFIG.Mysql.GeneralDB
|
||||
case "pgsql":
|
||||
logMode = &global.GVA_CONFIG.Pgsql
|
||||
general = global.GVA_CONFIG.Pgsql.GeneralDB
|
||||
case "oracle":
|
||||
general = global.GVA_CONFIG.Oracle.GeneralDB
|
||||
case "sqlite":
|
||||
general = global.GVA_CONFIG.Sqlite.GeneralDB
|
||||
case "mssql":
|
||||
general = global.GVA_CONFIG.Mssql.GeneralDB
|
||||
default:
|
||||
logMode = &global.GVA_CONFIG.Mysql
|
||||
general = global.GVA_CONFIG.Mysql.GeneralDB
|
||||
}
|
||||
|
||||
switch logMode.GetLogMode() {
|
||||
case "silent", "Silent":
|
||||
config.Logger = _default.LogMode(logger.Silent)
|
||||
case "error", "Error":
|
||||
config.Logger = _default.LogMode(logger.Error)
|
||||
case "warn", "Warn":
|
||||
config.Logger = _default.LogMode(logger.Warn)
|
||||
case "info", "Info":
|
||||
config.Logger = _default.LogMode(logger.Info)
|
||||
default:
|
||||
config.Logger = _default.LogMode(logger.Info)
|
||||
return &gorm.Config{
|
||||
Logger: logger.New(NewWriter(general, log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
|
||||
SlowThreshold: 200 * time.Millisecond,
|
||||
LogLevel: general.LogLevel(),
|
||||
Colorful: true,
|
||||
}),
|
||||
NamingStrategy: schema.NamingStrategy{
|
||||
TablePrefix: prefix,
|
||||
SingularTable: singular,
|
||||
},
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type Writer struct {
|
||||
config config.GeneralDB
|
||||
writer logger.Writer
|
||||
}
|
||||
|
||||
func NewWriter(config config.GeneralDB, writer logger.Writer) *Writer {
|
||||
return &Writer{config: config, writer: writer}
|
||||
}
|
||||
|
||||
// Printf 格式化打印日志
|
||||
func (c *Writer) Printf(message string, data ...any) {
|
||||
if c.config.LogZap {
|
||||
switch c.config.LogLevel() {
|
||||
case logger.Silent:
|
||||
zap.L().Debug(fmt.Sprintf(message, data...))
|
||||
case logger.Error:
|
||||
zap.L().Error(fmt.Sprintf(message, data...))
|
||||
case logger.Warn:
|
||||
zap.L().Warn(fmt.Sprintf(message, data...))
|
||||
case logger.Info:
|
||||
zap.L().Info(fmt.Sprintf(message, data...))
|
||||
default:
|
||||
zap.L().Info(fmt.Sprintf(message, data...))
|
||||
}
|
||||
return
|
||||
}
|
||||
c.writer.Printf(message, data...)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
logger.Writer
|
||||
}
|
||||
|
||||
// NewWriter writer 构造函数
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func NewWriter(w logger.Writer) *writer {
|
||||
return &writer{Writer: w}
|
||||
}
|
||||
|
||||
// Printf 格式化打印日志
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (w *writer) Printf(message string, data ...interface{}) {
|
||||
var logZap bool
|
||||
switch global.GVA_CONFIG.System.DbType {
|
||||
case "mysql":
|
||||
logZap = global.GVA_CONFIG.Mysql.LogZap
|
||||
case "pgsql":
|
||||
logZap = global.GVA_CONFIG.Pgsql.LogZap
|
||||
}
|
||||
if logZap {
|
||||
global.GVA_LOG.Info(fmt.Sprintf(message+"\n", data...))
|
||||
} else {
|
||||
w.Writer.Printf(message, data...)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/qiniu/qmgo/options"
|
||||
"go.mongodb.org/mongo-driver/event"
|
||||
opt "go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var Mongo = new(mongo)
|
||||
|
||||
type mongo struct{}
|
||||
|
||||
func (m *mongo) GetClientOptions() []options.ClientOptions {
|
||||
cmdMonitor := &event.CommandMonitor{
|
||||
Started: func(ctx context.Context, event *event.CommandStartedEvent) {
|
||||
zap.L().Info(fmt.Sprintf("[MongoDB][RequestID:%d][database:%s] %s\n", event.RequestID, event.DatabaseName, event.Command), zap.String("business", "mongo"))
|
||||
},
|
||||
Succeeded: func(ctx context.Context, event *event.CommandSucceededEvent) {
|
||||
zap.L().Info(fmt.Sprintf("[MongoDB][RequestID:%d] [%s] %s\n", event.RequestID, event.Duration.String(), event.Reply), zap.String("business", "mongo"))
|
||||
},
|
||||
Failed: func(ctx context.Context, event *event.CommandFailedEvent) {
|
||||
zap.L().Error(fmt.Sprintf("[MongoDB][RequestID:%d] [%s] %s\n", event.RequestID, event.Duration.String(), event.Failure), zap.String("business", "mongo"))
|
||||
},
|
||||
}
|
||||
return []options.ClientOptions{{ClientOptions: &opt.ClientOptions{Monitor: cmdMonitor}}}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/qiniu/qmgo"
|
||||
"github.com/qiniu/qmgo/options"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
option "go.mongodb.org/mongo-driver/mongo/options"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Mongo = new(mongo)
|
||||
|
||||
type (
|
||||
mongo struct{}
|
||||
Index struct {
|
||||
V any `bson:"v"`
|
||||
Ns any `bson:"ns"`
|
||||
Key []bson.E `bson:"key"`
|
||||
Name string `bson:"name"`
|
||||
}
|
||||
)
|
||||
|
||||
func (m *mongo) Indexes(ctx context.Context) error {
|
||||
// 表名:索引列表 列: "表名": [][]string{{"index1", "index2"}}
|
||||
indexMap := map[string][][]string{}
|
||||
for collection, indexes := range indexMap {
|
||||
err := m.CreateIndexes(ctx, collection, indexes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mongo) Initialization() error {
|
||||
var opts []options.ClientOptions
|
||||
if global.GVA_CONFIG.Mongo.IsZap {
|
||||
opts = internal.Mongo.GetClientOptions()
|
||||
}
|
||||
ctx := context.Background()
|
||||
client, err := qmgo.Open(ctx, &qmgo.Config{
|
||||
Uri: global.GVA_CONFIG.Mongo.Uri(),
|
||||
Coll: global.GVA_CONFIG.Mongo.Coll,
|
||||
Database: global.GVA_CONFIG.Mongo.Database,
|
||||
MinPoolSize: &global.GVA_CONFIG.Mongo.MinPoolSize,
|
||||
MaxPoolSize: &global.GVA_CONFIG.Mongo.MaxPoolSize,
|
||||
SocketTimeoutMS: &global.GVA_CONFIG.Mongo.SocketTimeoutMs,
|
||||
ConnectTimeoutMS: &global.GVA_CONFIG.Mongo.ConnectTimeoutMs,
|
||||
Auth: &qmgo.Credential{
|
||||
Username: global.GVA_CONFIG.Mongo.Username,
|
||||
Password: global.GVA_CONFIG.Mongo.Password,
|
||||
AuthSource: global.GVA_CONFIG.Mongo.AuthSource,
|
||||
},
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "链接mongodb数据库失败!")
|
||||
}
|
||||
global.GVA_MONGO = client
|
||||
err = m.Indexes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mongo) CreateIndexes(ctx context.Context, name string, indexes [][]string) error {
|
||||
collection, err := global.GVA_MONGO.Database.Collection(name).CloneCollection()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "获取[%s]的表对象失败!", name)
|
||||
}
|
||||
list, err := collection.Indexes().List(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "获取[%s]的索引对象失败!", name)
|
||||
}
|
||||
var entities []Index
|
||||
err = list.All(ctx, &entities)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "获取[%s]的索引列表失败!", name)
|
||||
}
|
||||
length := len(indexes)
|
||||
indexMap1 := make(map[string][]string, length)
|
||||
for i := 0; i < length; i++ {
|
||||
sort.Strings(indexes[i]) // 对索引key进行排序, 在使用bson.M搜索时, bson会自动按照key的字母顺序进行排序
|
||||
length1 := len(indexes[i])
|
||||
keys := make([]string, 0, length1)
|
||||
for j := 0; j < length1; j++ {
|
||||
if indexes[i][i][0] == '-' {
|
||||
keys = append(keys, indexes[i][j], "-1")
|
||||
continue
|
||||
}
|
||||
keys = append(keys, indexes[i][j], "1")
|
||||
}
|
||||
key := strings.Join(keys, "_")
|
||||
_, o1 := indexMap1[key]
|
||||
if o1 {
|
||||
return errors.Errorf("索引[%s]重复!", key)
|
||||
}
|
||||
indexMap1[key] = indexes[i]
|
||||
}
|
||||
length = len(entities)
|
||||
indexMap2 := make(map[string]map[string]string, length)
|
||||
for i := 0; i < length; i++ {
|
||||
v1, o1 := indexMap2[entities[i].Name]
|
||||
if !o1 {
|
||||
keyLength := len(entities[i].Key)
|
||||
v1 = make(map[string]string, keyLength)
|
||||
for j := 0; j < keyLength; j++ {
|
||||
v2, o2 := v1[entities[i].Key[j].Key]
|
||||
if !o2 {
|
||||
v1 = make(map[string]string)
|
||||
}
|
||||
v2 = entities[i].Key[j].Key
|
||||
v1[entities[i].Key[j].Key] = v2
|
||||
indexMap2[entities[i].Name] = v1
|
||||
}
|
||||
}
|
||||
}
|
||||
for k1, v1 := range indexMap1 {
|
||||
_, o2 := indexMap2[k1]
|
||||
if o2 {
|
||||
continue
|
||||
} // 索引存在
|
||||
if len(fmt.Sprintf("%s.%s.$%s", collection.Name(), name, v1)) > 127 {
|
||||
err = global.GVA_MONGO.Database.Collection(name).CreateOneIndex(ctx, options.IndexModel{
|
||||
Key: v1,
|
||||
IndexOptions: option.Index().SetName(utils.MD5V([]byte(k1))),
|
||||
// IndexOptions: option.Index().SetName(utils.MD5V([]byte(k1))).SetExpireAfterSeconds(86400), // SetExpireAfterSeconds(86400) 设置索引过期时间, 86400 = 1天
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建索引[%s]失败!", k1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = global.GVA_MONGO.Database.Collection(name).CreateOneIndex(ctx, options.IndexModel{
|
||||
Key: v1,
|
||||
IndexOptions: option.Index().SetExpireAfterSeconds(86400),
|
||||
// IndexOptions: option.Index().SetName(utils.MD5V([]byte(k1))).SetExpireAfterSeconds(86400), // SetExpireAfterSeconds(86400) 设置索引过期时间(秒), 86400 = 1天
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建索引[%s]失败!", k1)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package initialize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/email"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils/plugin"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -16,12 +16,10 @@ func PluginInit(group *gin.RouterGroup, Plugin ...plugin.Plugin) {
|
||||
}
|
||||
}
|
||||
|
||||
func InstallPlugin(Router *gin.Engine) {
|
||||
PublicGroup := Router.Group("")
|
||||
fmt.Println("无鉴权插件安装==》", PublicGroup)
|
||||
PrivateGroup := Router.Group("")
|
||||
func InstallPlugin(PrivateGroup *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
fmt.Println("无鉴权插件安装==》", PublicRouter)
|
||||
|
||||
fmt.Println("鉴权插件安装==》", PrivateGroup)
|
||||
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
|
||||
// 添加跟角色挂钩权限的插件 示例 本地示例模式于在线仓库模式注意上方的import 可以自行切换 效果相同
|
||||
PluginInit(PrivateGroup, email.CreateEmailPlug(
|
||||
global.GVA_CONFIG.Email.To,
|
||||
|
||||
@@ -5,20 +5,31 @@ import (
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Redis() {
|
||||
redisCfg := global.GVA_CONFIG.Redis
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: redisCfg.Addr,
|
||||
Password: redisCfg.Password, // no password set
|
||||
DB: redisCfg.DB, // use default DB
|
||||
})
|
||||
var client redis.UniversalClient
|
||||
// 使用集群模式
|
||||
if redisCfg.UseCluster {
|
||||
client = redis.NewClusterClient(&redis.ClusterOptions{
|
||||
Addrs: redisCfg.ClusterAddrs,
|
||||
Password: redisCfg.Password,
|
||||
})
|
||||
} else {
|
||||
// 使用单例模式
|
||||
client = redis.NewClient(&redis.Options{
|
||||
Addr: redisCfg.Addr,
|
||||
Password: redisCfg.Password,
|
||||
DB: redisCfg.DB,
|
||||
})
|
||||
}
|
||||
pong, err := client.Ping(context.Background()).Result()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("redis connect ping failed, err:", zap.Error(err))
|
||||
panic(err)
|
||||
} else {
|
||||
global.GVA_LOG.Info("redis connect ping response:", zap.String("pong", pong))
|
||||
global.GVA_REDIS = client
|
||||
|
||||
+55
-35
@@ -2,79 +2,99 @@ package initialize
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
_ "github.com/flipped-aurora/gin-vue-admin/server/docs"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/docs"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/swaggo/gin-swagger"
|
||||
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
|
||||
type justFilesFilesystem struct {
|
||||
fs http.FileSystem
|
||||
}
|
||||
|
||||
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
|
||||
f, err := fs.fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stat, err := f.Stat()
|
||||
if stat.IsDir() {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// 初始化总路由
|
||||
|
||||
func Routers() *gin.Engine {
|
||||
Router := gin.Default()
|
||||
Router := gin.New()
|
||||
Router.Use(gin.Recovery())
|
||||
if gin.Mode() == gin.DebugMode {
|
||||
Router.Use(gin.Logger())
|
||||
}
|
||||
|
||||
systemRouter := router.RouterGroupApp.System
|
||||
exampleRouter := router.RouterGroupApp.Example
|
||||
// 如果想要不使用nginx代理前端网页,可以修改 web/.env.production 下的
|
||||
// VUE_APP_BASE_API = /
|
||||
// VUE_APP_BASE_PATH = http://localhost
|
||||
// 然后执行打包命令 npm run build。在打开下面4行注释
|
||||
// Router.LoadHTMLGlob("./dist/*.html") // npm打包成dist的路径
|
||||
// Router.Static("/favicon.ico", "./dist/favicon.ico")
|
||||
// Router.Static("/static", "./dist/assets") // dist里面的静态资源
|
||||
// Router.StaticFile("/", "./dist/index.html") // 前端网页入口页面
|
||||
// 然后执行打包命令 npm run build。在打开下面3行注释
|
||||
//Router.Static("/favicon.ico", "./dist/favicon.ico")
|
||||
//Router.Static("/assets", "./dist/assets") // dist里面的静态资源
|
||||
//Router.StaticFile("/", "./dist/index.html") // 前端网页入口页面
|
||||
|
||||
Router.StaticFS(global.GVA_CONFIG.Local.Path, http.Dir(global.GVA_CONFIG.Local.StorePath)) // 为用户头像和文件提供静态地址
|
||||
// Router.Use(middleware.LoadTls()) // 如果需要使用https 请打开此中间件 然后前往 core/server.go 将启动模式 更变为 Router.RunTLS("端口","你的cre/pem文件","你的key文件")
|
||||
Router.StaticFS(global.GVA_CONFIG.Local.StorePath, justFilesFilesystem{http.Dir(global.GVA_CONFIG.Local.StorePath)}) // Router.Use(middleware.LoadTls()) // 如果需要使用https 请打开此中间件 然后前往 core/server.go 将启动模式 更变为 Router.RunTLS("端口","你的cre/pem文件","你的key文件")
|
||||
// 跨域,如需跨域可以打开下面的注释
|
||||
// Router.Use(middleware.Cors()) // 直接放行全部跨域请求
|
||||
//Router.Use(middleware.CorsByRules()) // 按照配置的规则放行跨域请求
|
||||
// Router.Use(middleware.CorsByRules()) // 按照配置的规则放行跨域请求
|
||||
//global.GVA_LOG.Info("use middleware cors")
|
||||
Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
docs.SwaggerInfo.BasePath = global.GVA_CONFIG.System.RouterPrefix
|
||||
Router.GET(global.GVA_CONFIG.System.RouterPrefix+"/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
global.GVA_LOG.Info("register swagger handler")
|
||||
// 方便统一添加路由组前缀 多服务器上线使用
|
||||
|
||||
PublicGroup := Router.Group("")
|
||||
PublicGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
|
||||
{
|
||||
// 健康监测
|
||||
PublicGroup.GET("/health", func(c *gin.Context) {
|
||||
c.JSON(200, "ok")
|
||||
c.JSON(http.StatusOK, "ok")
|
||||
})
|
||||
}
|
||||
{
|
||||
systemRouter.InitBaseRouter(PublicGroup) // 注册基础功能路由 不做鉴权
|
||||
systemRouter.InitInitRouter(PublicGroup) // 自动初始化相关
|
||||
}
|
||||
PrivateGroup := Router.Group("")
|
||||
PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
|
||||
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
|
||||
{
|
||||
systemRouter.InitApiRouter(PrivateGroup) // 注册功能api路由
|
||||
systemRouter.InitJwtRouter(PrivateGroup) // jwt相关路由
|
||||
systemRouter.InitUserRouter(PrivateGroup) // 注册用户路由
|
||||
systemRouter.InitMenuRouter(PrivateGroup) // 注册menu路由
|
||||
systemRouter.InitSystemRouter(PrivateGroup) // system相关路由
|
||||
systemRouter.InitCasbinRouter(PrivateGroup) // 权限相关路由
|
||||
systemRouter.InitAutoCodeRouter(PrivateGroup) // 创建自动化代码
|
||||
systemRouter.InitAuthorityRouter(PrivateGroup) // 注册角色路由
|
||||
systemRouter.InitSysDictionaryRouter(PrivateGroup) // 字典管理
|
||||
systemRouter.InitAutoCodeHistoryRouter(PrivateGroup) // 自动化代码历史
|
||||
systemRouter.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
|
||||
systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
|
||||
systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 字典详情管理
|
||||
|
||||
exampleRouter.InitExcelRouter(PrivateGroup) // 表格导入导出
|
||||
systemRouter.InitApiRouter(PrivateGroup, PublicGroup) // 注册功能api路由
|
||||
systemRouter.InitJwtRouter(PrivateGroup) // jwt相关路由
|
||||
systemRouter.InitUserRouter(PrivateGroup) // 注册用户路由
|
||||
systemRouter.InitMenuRouter(PrivateGroup) // 注册menu路由
|
||||
systemRouter.InitSystemRouter(PrivateGroup) // system相关路由
|
||||
systemRouter.InitCasbinRouter(PrivateGroup) // 权限相关路由
|
||||
systemRouter.InitAutoCodeRouter(PrivateGroup) // 创建自动化代码
|
||||
systemRouter.InitAuthorityRouter(PrivateGroup) // 注册角色路由
|
||||
systemRouter.InitSysDictionaryRouter(PrivateGroup) // 字典管理
|
||||
systemRouter.InitAutoCodeHistoryRouter(PrivateGroup) // 自动化代码历史
|
||||
systemRouter.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
|
||||
systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
|
||||
systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 字典详情管理
|
||||
systemRouter.InitSysExportTemplateRouter(PrivateGroup) // 导出模板
|
||||
exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由
|
||||
exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
|
||||
|
||||
// Code generated by github.com/flipped-aurora/gin-vue-admin/server Begin; DO NOT EDIT.
|
||||
|
||||
// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
|
||||
}
|
||||
|
||||
InstallPlugin(Router) // 安装插件
|
||||
//插件路由安装
|
||||
InstallPlugin(PrivateGroup, PublicGroup)
|
||||
|
||||
global.GVA_LOG.Info("router register success")
|
||||
return Router
|
||||
|
||||
+24
-20
@@ -2,32 +2,36 @@ package initialize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/task"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
)
|
||||
|
||||
func Timer() {
|
||||
if global.GVA_CONFIG.Timer.Start {
|
||||
for i := range global.GVA_CONFIG.Timer.Detail {
|
||||
go func(detail config.Detail) {
|
||||
var option []cron.Option
|
||||
if global.GVA_CONFIG.Timer.WithSeconds {
|
||||
option = append(option, cron.WithSeconds())
|
||||
}
|
||||
_, err := global.GVA_Timer.AddTaskByFunc("ClearDB", global.GVA_CONFIG.Timer.Spec, func() {
|
||||
err := utils.ClearTable(global.GVA_DB, detail.TableName, detail.CompareField, detail.Interval)
|
||||
if err != nil {
|
||||
fmt.Println("timer error:", err)
|
||||
}
|
||||
}, option...)
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
}(global.GVA_CONFIG.Timer.Detail[i])
|
||||
go func() {
|
||||
var option []cron.Option
|
||||
option = append(option, cron.WithSeconds())
|
||||
// 清理DB定时任务
|
||||
_, err := global.GVA_Timer.AddTaskByFunc("ClearDB", "@daily", func() {
|
||||
err := task.ClearTable(global.GVA_DB) // 定时任务方法定在task文件包中
|
||||
if err != nil {
|
||||
fmt.Println("timer error:", err)
|
||||
}
|
||||
}, "定时清理数据库【日志,黑名单】内容", option...)
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 其他定时任务定在这里 参考上方使用方法
|
||||
|
||||
//_, err := global.GVA_Timer.AddTaskByFunc("定时任务标识", "corn表达式", func() {
|
||||
// 具体执行内容...
|
||||
// ......
|
||||
//}, option...)
|
||||
//if err != nil {
|
||||
// fmt.Println("add timer error:", err)
|
||||
//}
|
||||
}()
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "go.uber.org/automaxprocs"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/core"
|
||||
@@ -13,9 +14,9 @@ import (
|
||||
//go:generate go mod tidy
|
||||
//go:generate go mod download
|
||||
|
||||
// @title Swagger Example API
|
||||
// @version 0.0.1
|
||||
// @description This is a sample Server pets
|
||||
// @title Gin-Vue-Admin Swagger API接口文档
|
||||
// @version v2.6.5
|
||||
// @description 使用gin+vue进行极速开发的全栈开发基础平台
|
||||
// @securityDefinitions.apikey ApiKeyAuth
|
||||
// @in header
|
||||
// @name x-token
|
||||
@@ -29,7 +30,7 @@ func main() {
|
||||
initialize.Timer()
|
||||
initialize.DBList()
|
||||
if global.GVA_DB != nil {
|
||||
initialize.RegisterTables(global.GVA_DB) // 初始化表
|
||||
initialize.RegisterTables() // 初始化表
|
||||
// 程序结束前关闭数据库链接
|
||||
db, _ := global.GVA_DB.DB()
|
||||
defer db.Close()
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService
|
||||
|
||||
// 拦截器
|
||||
// CasbinHandler 拦截器
|
||||
func CasbinHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
waitUse, _ := utils.GetClaims(c)
|
||||
// 获取请求的PATH
|
||||
obj := c.Request.URL.Path
|
||||
//获取请求的PATH
|
||||
path := c.Request.URL.Path
|
||||
obj := strings.TrimPrefix(path, global.GVA_CONFIG.System.RouterPrefix)
|
||||
// 获取请求方法
|
||||
act := c.Request.Method
|
||||
// 获取用户的角色
|
||||
sub := strconv.Itoa(int(waitUse.AuthorityId))
|
||||
e := casbinService.Casbin() // 判断策略中是否存在
|
||||
success, _ := e.Enforce(sub, obj, act)
|
||||
if global.GVA_CONFIG.System.Env == "develop" || success {
|
||||
c.Next()
|
||||
} else {
|
||||
if !success {
|
||||
response.FailWithDetailed(gin.H{}, "权限不足", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func CorsByRules() gin.HandlerFunc {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
} else {
|
||||
// 非严格白名单模式,无论是否通过检查均放行所有 OPTIONS 方法
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
if c.Request.Method == http.MethodOptions {
|
||||
c.AbortWithStatus(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
+27
-15
@@ -1,18 +1,19 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"go.uber.org/zap"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var jwtService = service.ServiceGroupApp.SystemServiceGroup.JwtService
|
||||
@@ -20,14 +21,15 @@ var jwtService = service.ServiceGroupApp.SystemServiceGroup.JwtService
|
||||
func JWTAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
|
||||
token := c.Request.Header.Get("x-token")
|
||||
token := utils.GetToken(c)
|
||||
if token == "" {
|
||||
response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
|
||||
response.NoAuth("未登录或非法访问", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
if jwtService.IsBlacklist(token) {
|
||||
response.FailWithDetailed(gin.H{"reload": true}, "您的帐户异地登陆或令牌失效", c)
|
||||
response.NoAuth("您的帐户异地登陆或令牌失效", c)
|
||||
utils.ClearToken(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -35,12 +37,14 @@ func JWTAuth() gin.HandlerFunc {
|
||||
// parseToken 解析token包含的信息
|
||||
claims, err := j.ParseToken(token)
|
||||
if err != nil {
|
||||
if err == utils.TokenExpired {
|
||||
response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c)
|
||||
if errors.Is(err, utils.TokenExpired) {
|
||||
response.NoAuth("授权已过期", c)
|
||||
utils.ClearToken(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c)
|
||||
response.NoAuth(err.Error(), c)
|
||||
utils.ClearToken(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -53,13 +57,15 @@ func JWTAuth() gin.HandlerFunc {
|
||||
// response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c)
|
||||
// c.Abort()
|
||||
//}
|
||||
if claims.ExpiresAt-time.Now().Unix() < claims.BufferTime {
|
||||
c.Set("claims", claims)
|
||||
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
||||
dr, _ := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
||||
claims.ExpiresAt = time.Now().Add(dr).Unix()
|
||||
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(dr))
|
||||
newToken, _ := j.CreateTokenByOldToken(token, *claims)
|
||||
newClaims, _ := j.ParseToken(newToken)
|
||||
c.Header("new-token", newToken)
|
||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt, 10))
|
||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10))
|
||||
utils.SetToken(c, newToken, int(dr.Seconds()))
|
||||
if global.GVA_CONFIG.System.UseMultipoint {
|
||||
RedisJwtToken, err := jwtService.GetRedisJWT(newClaims.Username)
|
||||
if err != nil {
|
||||
@@ -71,7 +77,13 @@ func JWTAuth() gin.HandlerFunc {
|
||||
_ = jwtService.SetRedisJWT(newToken, newClaims.Username)
|
||||
}
|
||||
}
|
||||
c.Set("claims", claims)
|
||||
c.Next()
|
||||
|
||||
if newToken, exists := c.Get("new-token"); exists {
|
||||
c.Header("new-token", newToken.(string))
|
||||
}
|
||||
if newExpiresAt, exists := c.Get("new-expires-at"); exists {
|
||||
c.Header("new-expires-at", newExpiresAt.(string))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,10 @@ func (l Logger) SetLoggerMiddleware() gin.HandlerFunc {
|
||||
if l.Filter != nil && !l.Filter(c) {
|
||||
layout.Body = string(body)
|
||||
}
|
||||
// 处理鉴权需要的信息
|
||||
l.AuthProcess(c, &layout)
|
||||
if l.AuthProcess != nil {
|
||||
// 处理鉴权需要的信息
|
||||
l.AuthProcess(c, &layout)
|
||||
}
|
||||
if l.FilterKeyword != nil {
|
||||
// 自行判断key/value 脱敏等
|
||||
l.FilterKeyword(&layout)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 处理跨域请求,支持options访问
|
||||
func NeedInit() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if global.GVA_DB == nil {
|
||||
response.OkWithDetailed(gin.H{
|
||||
"needInit": true,
|
||||
}, "前往初始化数据库", c)
|
||||
c.Abort()
|
||||
} else {
|
||||
c.Next()
|
||||
}
|
||||
// 处理请求
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,11 @@ import (
|
||||
var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
|
||||
|
||||
var respPool sync.Pool
|
||||
var bufferSize = 1024
|
||||
|
||||
func init() {
|
||||
respPool.New = func() interface{} {
|
||||
return make([]byte, 1024)
|
||||
return make([]byte, bufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +57,8 @@ func OperationRecord() gin.HandlerFunc {
|
||||
body, _ = json.Marshal(&m)
|
||||
}
|
||||
claims, _ := utils.GetClaims(c)
|
||||
if claims.ID != 0 {
|
||||
userId = int(claims.ID)
|
||||
if claims != nil && claims.BaseClaims.ID != 0 {
|
||||
userId = int(claims.BaseClaims.ID)
|
||||
} else {
|
||||
id, err := strconv.Atoi(c.Request.Header.Get("x-user-id"))
|
||||
if err != nil {
|
||||
@@ -70,18 +71,18 @@ func OperationRecord() gin.HandlerFunc {
|
||||
Method: c.Request.Method,
|
||||
Path: c.Request.URL.Path,
|
||||
Agent: c.Request.UserAgent(),
|
||||
Body: string(body),
|
||||
Body: "",
|
||||
UserID: userId,
|
||||
}
|
||||
|
||||
// 上传文件时候 中间件日志进行裁断操作
|
||||
if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
|
||||
if len(record.Body) > 1024 {
|
||||
// 截断
|
||||
newBody := respPool.Get().([]byte)
|
||||
copy(newBody, record.Body)
|
||||
record.Body = string(newBody)
|
||||
defer respPool.Put(newBody[:0])
|
||||
if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
|
||||
record.Body = "[文件]"
|
||||
} else {
|
||||
if len(body) > bufferSize {
|
||||
record.Body = "[超出记录长度]"
|
||||
} else {
|
||||
record.Body = string(body)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,21 +101,18 @@ func OperationRecord() gin.HandlerFunc {
|
||||
record.Latency = latency
|
||||
record.Resp = writer.body.String()
|
||||
|
||||
if strings.Contains(c.Writer.Header().Get("Pragma"), "public") ||
|
||||
strings.Contains(c.Writer.Header().Get("Expires"), "0") ||
|
||||
if strings.Contains(c.Writer.Header().Get("Pragma"), "public") ||
|
||||
strings.Contains(c.Writer.Header().Get("Expires"), "0") ||
|
||||
strings.Contains(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") ||
|
||||
strings.Contains(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") {
|
||||
if len(record.Resp) > 1024 {
|
||||
if len(record.Resp) > bufferSize {
|
||||
// 截断
|
||||
newBody := respPool.Get().([]byte)
|
||||
copy(newBody, record.Resp)
|
||||
record.Body = string(newBody)
|
||||
defer respPool.Put(newBody[:0])
|
||||
record.Body = "超出记录长度"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package common
|
||||
|
||||
type ClearDB struct {
|
||||
TableName string
|
||||
CompareField string
|
||||
Interval string
|
||||
}
|
||||
@@ -50,6 +50,14 @@ func FailWithMessage(message string, c *gin.Context) {
|
||||
Result(ERROR, map[string]interface{}{}, message, c)
|
||||
}
|
||||
|
||||
func NoAuth(message string, c *gin.Context) {
|
||||
c.JSON(http.StatusUnauthorized, Response{
|
||||
7,
|
||||
nil,
|
||||
message,
|
||||
})
|
||||
}
|
||||
|
||||
func FailWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
Result(ERROR, data, message, c)
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package example
|
||||
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
|
||||
type ExcelInfo struct {
|
||||
FileName string `json:"fileName"` // 文件名
|
||||
InfoList []system.SysBaseMenu `json:"infoList"`
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"github.com/gofrs/uuid/v5"
|
||||
jwt "github.com/golang-jwt/jwt/v4"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
// Custom claims structure
|
||||
type CustomClaims struct {
|
||||
BaseClaims
|
||||
BufferTime int64
|
||||
jwt.StandardClaims
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type BaseClaims struct {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
)
|
||||
|
||||
type SysDictionarySearch struct {
|
||||
system.SysDictionary
|
||||
request.PageInfo
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SysExportTemplateSearch struct {
|
||||
system.SysExportTemplate
|
||||
StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"`
|
||||
EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"`
|
||||
request.PageInfo
|
||||
}
|
||||
@@ -2,17 +2,19 @@ package request
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||
"os"
|
||||
)
|
||||
|
||||
type InitDB struct {
|
||||
DBType string `json:"dbType"` // 数据库类型
|
||||
Host string `json:"host"` // 服务器地址
|
||||
Port string `json:"port"` // 数据库连接端口
|
||||
UserName string `json:"userName" binding:"required"` // 数据库用户名
|
||||
Password string `json:"password"` // 数据库密码
|
||||
DBName string `json:"dbName" binding:"required"` // 数据库名
|
||||
AdminPassword string `json:"adminPassword" binding:"required"`
|
||||
DBType string `json:"dbType"` // 数据库类型
|
||||
Host string `json:"host"` // 服务器地址
|
||||
Port string `json:"port"` // 数据库连接端口
|
||||
UserName string `json:"userName"` // 数据库用户名
|
||||
Password string `json:"password"` // 数据库密码
|
||||
DBName string `json:"dbName" binding:"required"` // 数据库名
|
||||
DBPath string `json:"dbPath"` // sqlite数据库文件路径
|
||||
}
|
||||
|
||||
// MysqlEmptyDsn msyql 空数据库 建库链接
|
||||
@@ -39,6 +41,17 @@ func (i *InitDB) PgsqlEmptyDsn() string {
|
||||
return "host=" + i.Host + " user=" + i.UserName + " password=" + i.Password + " port=" + i.Port + " dbname=" + "postgres" + " " + "sslmode=disable TimeZone=Asia/Shanghai"
|
||||
}
|
||||
|
||||
// SqliteEmptyDsn sqlite 空数据库 建库链接
|
||||
// Author Kafumio
|
||||
func (i *InitDB) SqliteEmptyDsn() string {
|
||||
separator := string(os.PathSeparator)
|
||||
return i.DBPath + separator + i.DBName + ".db"
|
||||
}
|
||||
|
||||
func (i *InitDB) MssqlEmptyDsn() string {
|
||||
return "sqlserver://" + i.UserName + ":" + i.Password + "@" + i.Host + ":" + i.Port + "?database=" + i.DBName + "&encrypt=disable"
|
||||
}
|
||||
|
||||
// ToMysqlConfig 转换 config.Mysql
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func (i *InitDB) ToMysqlConfig() config.Mysql {
|
||||
@@ -74,3 +87,37 @@ func (i *InitDB) ToPgsqlConfig() config.Pgsql {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ToSqliteConfig 转换 config.Sqlite
|
||||
// Author [Kafumio](https://github.com/Kafumio)
|
||||
func (i *InitDB) ToSqliteConfig() config.Sqlite {
|
||||
return config.Sqlite{
|
||||
GeneralDB: config.GeneralDB{
|
||||
Path: i.DBPath,
|
||||
Port: i.Port,
|
||||
Dbname: i.DBName,
|
||||
Username: i.UserName,
|
||||
Password: i.Password,
|
||||
MaxIdleConns: 10,
|
||||
MaxOpenConns: 100,
|
||||
LogMode: "error",
|
||||
Config: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InitDB) ToMssqlConfig() config.Mssql {
|
||||
return config.Mssql{
|
||||
GeneralDB: config.GeneralDB{
|
||||
Path: i.DBPath,
|
||||
Port: i.Port,
|
||||
Dbname: i.DBName,
|
||||
Username: i.UserName,
|
||||
Password: i.Password,
|
||||
MaxIdleConns: 10,
|
||||
MaxOpenConns: 100,
|
||||
LogMode: "error",
|
||||
Config: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type AddMenuAuthorityInfo struct {
|
||||
func DefaultMenu() []system.SysBaseMenu {
|
||||
return []system.SysBaseMenu{{
|
||||
GVA_MODEL: global.GVA_MODEL{ID: 1},
|
||||
ParentId: "0",
|
||||
ParentId: 0,
|
||||
Path: "dashboard",
|
||||
Name: "dashboard",
|
||||
Component: "view/dashboard/index.vue",
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package request
|
||||
|
||||
import model "github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
)
|
||||
|
||||
// User register structure
|
||||
// Register User register structure
|
||||
type Register struct {
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"passWord"`
|
||||
NickName string `json:"nickName" gorm:"default:'QMPlusUser'"`
|
||||
HeaderImg string `json:"headerImg" gorm:"default:'https://qmplusimg.henrongyi.top/gva_header.jpg'"`
|
||||
AuthorityId uint `json:"authorityId" gorm:"default:888"`
|
||||
Enable int `json:"enable"`
|
||||
AuthorityIds []uint `json:"authorityIds"`
|
||||
Username string `json:"userName" example:"用户名"`
|
||||
Password string `json:"passWord" example:"密码"`
|
||||
NickName string `json:"nickName" example:"昵称"`
|
||||
HeaderImg string `json:"headerImg" example:"头像链接"`
|
||||
AuthorityId uint `json:"authorityId" swaggertype:"string" example:"int 角色id"`
|
||||
Enable int `json:"enable" swaggertype:"string" example:"int 是否启用"`
|
||||
AuthorityIds []uint `json:"authorityIds" swaggertype:"string" example:"[]uint 角色id"`
|
||||
Phone string `json:"phone" example:"电话号码"`
|
||||
Email string `json:"email" example:"电子邮箱"`
|
||||
}
|
||||
|
||||
// User login structure
|
||||
@@ -40,13 +44,13 @@ type SetUserAuthorities struct {
|
||||
}
|
||||
|
||||
type ChangeUserInfo struct {
|
||||
ID uint `gorm:"primarykey"` // 主键ID
|
||||
NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
|
||||
Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
|
||||
AuthorityIds []uint `json:"authorityIds" gorm:"-"` // 角色ID
|
||||
Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
|
||||
HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
|
||||
SideMode string `json:"sideMode" gorm:"comment:用户侧边主题"` // 用户侧边主题
|
||||
Enable int `json:"enable" gorm:"comment:冻结用户"` //冻结用户
|
||||
Authorities []model.SysAuthority `json:"-" gorm:"many2many:sys_user_authority;"`
|
||||
ID uint `gorm:"primarykey"` // 主键ID
|
||||
NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
|
||||
Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
|
||||
AuthorityIds []uint `json:"authorityIds" gorm:"-"` // 角色ID
|
||||
Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
|
||||
HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
|
||||
SideMode string `json:"sideMode" gorm:"comment:用户侧边主题"` // 用户侧边主题
|
||||
Enable int `json:"enable" gorm:"comment:冻结用户"` //冻结用户
|
||||
Authorities []system.SysAuthority `json:"-" gorm:"many2many:sys_user_authority;"`
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ type Column struct {
|
||||
ColumnName string `json:"columnName" gorm:"column:column_name"`
|
||||
DataTypeLong string `json:"dataTypeLong" gorm:"column:data_type_long"`
|
||||
ColumnComment string `json:"columnComment" gorm:"column:column_comment"`
|
||||
PrimaryKey bool `json:"primaryKey" gorm:"column:primary_key"`
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ type AutoCodeHistory struct {
|
||||
ID uint `json:"ID" gorm:"column:id"`
|
||||
CreatedAt time.Time `json:"CreatedAt" gorm:"column:created_at"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" gorm:"column:updated_at"`
|
||||
BusinessDB string `json:"businessDB" gorm:"column:business_db"`
|
||||
TableName string `json:"tableName" gorm:"column:table_name"`
|
||||
StructName string `json:"structName" gorm:"column:struct_name"`
|
||||
StructCNName string `json:"structCNName" gorm:"column:struct_cn_name"`
|
||||
|
||||
@@ -3,5 +3,6 @@ package response
|
||||
type SysCaptchaResponse struct {
|
||||
CaptchaId string `json:"captchaId"`
|
||||
PicPath string `json:"picPath"`
|
||||
CaptchaLength int `json:"captchaLength""`
|
||||
CaptchaLength int `json:"captchaLength"`
|
||||
OpenCaptcha bool `json:"openCaptcha"`
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user