提交 910c857e 编写于 作者: Mr.奇淼('s avatar Mr.奇淼(

Merge remote-tracking branch 'origin/gva_gormv2_dev' into gva_gormv2_dev

server {
listen 8000;
listen 8080;
server_name localhost;
#charset koi8-r;
......
......@@ -7,87 +7,111 @@ filename="./config.yaml"
cat>"${filename}"<<EOF
# Gin-Vue-Admin Global Configuration
# casbin configuration
casbin:
model-path: './resource/rbac_model.conf'
# jwt configuration
jwt:
signing-key: 'qmPlus'
# mysql connect configuration
mysql:
username: root
password: 'Aa@6447985'
path: mysql
db-name: 'qmPlus'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
max-idle-conns: 10
max-open-conns: 10
log-mode: true
#sqlite 配置
sqlite:
path: db.db
log-mode: true
config: 'loc=Asia/Shanghai'
# oss configuration
# 切换本地与七牛云上传,分配头像和文件路径
localupload:
local: false
avatar-path: uploads/avatar
file-path: uploads/file
# 请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址
qiniu:
access-key: '25j8dYBZ2wuiy0yhwShytjZDTX662b8xiFguwxzZ'
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
bucket: 'qm-plus-img'
img-path: 'http://qmplusimg.henrongyi.top'
# redis configuration
redis:
addr: redis:6379
password: ''
db: 0
# system configuration
system:
use-multipoint: true
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: "mysql" # support mysql/sqlite
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
signing-key: 'qmPlus'
# zap logger configuration
zap:
# 可使用 "debug", "info", "warn", "error", "dpanic", "panic", "fatal",
level: 'info'
# console: 控制台, json: json格式输出
format: 'console'
prefix: '[GIN-VUE-ADMIN]'
director: 'log'
link-name: 'latest_log'
show-line: true
# LowercaseLevelEncoder:小写, LowercaseColorLevelEncoder:小写带颜色,CapitalLevelEncoder: 大写, CapitalColorLevelEncoder: 大写带颜色,
encode-level: 'LowercaseColorLevelEncoder'
stacktrace-key: 'stacktrace'
log-in-console: true
# redis configuration
redis:
db: 0
addr: '177.7.0.14:6379'
password: ''
# email configuration
email:
email-from: 'xxx@163.com'
email-nickname: 'test'
email-secret: 'xxx'
email-to: 'xxx@qq.com'
email-host: 'smtp.163.com'
email-port: 465
email-isSSL: true
to: 'xxx@qq.com'
port: 465
from: 'xxx@163.com'
host: 'smtp.163.com'
is-ssl: true
secret: 'xxx'
nickname: 'test'
# casbin configuration
casbin:
model-path: './resource/rbac_model.conf'
# system configuration
system:
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: 'mysql'
oss-type: 'local'
config-env: 'GVA_CONFIG'
need-init-data: true
use-multipoint: false
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
# mysql connect configuration
mysql:
path: '177.7.0.13:3306'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
db-name: 'qmPlus'
username: 'root'
password: 'Aa@6447985'
max-idle-conns: 10
max-open-conns: 10
log-mode: false
# sqlite connect configuration (sqlite需要gcc支持 windows用户需要自行安装gcc)
sqlite:
path: 'db.db'
max-idle-conns: 10
max-open-conns: 10
logger: true
# Sqlserver connect configuration
sqlserver:
path: 'localhost:9930'
db-name: 'gorm'
username: 'gorm'
password: 'LoremIpsum86'
max-idle-conns: 10
max-open-conns: 10
logger: true
# Postgresql connect configuration
postgresql:
host: '127.0.0.1'
port: '9920'
config: 'sslmode=disable TimeZone=Asia/Shanghai'
db-name: 'gorm'
username: 'gorm'
password: 'gorm'
max-idle-conns: 10
max-open-conns: 10
prefer-simple-protocol: true
logger: false
# local configuration
local:
path: 'uploads/file'
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
qiniu:
zone: 'ZoneHuadong'
bucket: 'qm-plus-img'
img-path: 'http://qmplusimg.henrongyi.top'
use-https: false
access-key: '25j8dYBZ2wuiy0yhwShytjZDTX662b8xiFguwxzZ'
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
use-cdn-domains: false
EOF
name: gin-vue-admin build test
on:
push:
branches:
- '*'
paths-ignore:
- './db/**'
- '**.md'
pull_request:
branches:
- '*'
paths-ignore:
- './db/**'
- '**.md'
push:
branches:
- "*"
paths-ignore:
- "./db/**"
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "./db/**"
- "**.md"
jobs:
frontend:
name: Frontend build
name: Frontend build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- name: Check out branch
uses: actions/checkout@v2
- 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: 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
- 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.14
uses: actions/setup-go@v1
with:
go-version: 1.14
id: go
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go
- name: Check out branch
uses: actions/checkout@v2
- 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: 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
\ No newline at end of file
- name: Test and Build
run: |
go build -v -race
working-directory: ./server
......@@ -15,7 +15,7 @@ services:
container_name: gva-web
restart: always
ports:
- '8000:8000'
- '8080:8080'
depends_on:
- server
command: [ 'nginx-debug', '-g', 'daemon off;' ]
......@@ -34,6 +34,9 @@ services:
depends_on:
- mysql
- redis
links:
- mysql
- redis
networks:
network:
ipv4_address: 177.7.0.12
......@@ -48,8 +51,6 @@ services:
environment:
MYSQL_DATABASE: 'qmPlus' # 初始化启动时要创建的数据库的名称
MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
volumes:
- '.docker-compose/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d'
networks:
network:
ipv4_address: 177.7.0.13
......@@ -59,7 +60,7 @@ services:
container_name: gva-redis # 容器名
restart: always
ports:
- '6379:6379'
- '16379:6379'
networks:
network:
ipv4_address: 177.7.0.14
\ No newline at end of file
......@@ -24,6 +24,8 @@ COPY --from=0 /go/src/gin-vue-admin/server ./
COPY --from=0 /go/src/gin-vue-admin/config.yaml ./
COPY --from=0 /go/src/gin-vue-admin/resource ./resource
EXPOSE 8888
ENTRYPOINT ./server
# 根据Dockerfile生成Docker镜像
......
......@@ -60,3 +60,19 @@ func ReloadSystem(c *gin.Context) {
response.OkWithMessage("设置成功", c)
}
}
// @Tags system
// @Summary 获取服务器信息
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /system/getServerInfo [post]
func GetServerInfo(c *gin.Context) {
server, err := service.GetServerInfo()
if err != nil {
response.FailWithMessage(fmt.Sprintf("获取失败,%v", err), c)
return
}
response.OkDetailed(gin.H{"server":server}, "获取成功",c)
}
\ No newline at end of file
# Gin-Vue-Admin Global Configuration
# jwt configuration
jwt:
signing-key: 'qmPlus'
# zap logger configuration
zap:
level: 'info'
format: 'console'
prefix: '[GIN-VUE-ADMIN]'
director: 'log'
link-name: 'latest_log'
show-line: true
encode-level: 'LowercaseColorLevelEncoder'
stacktrace-key: 'stacktrace'
log-in-console: true
# redis configuration
redis:
db: 0
addr: '127.0.0.1:6379'
password: ''
# email configuration
email:
to: 'xxx@qq.com'
port: 465
from: 'xxx@163.com'
host: 'smtp.163.com'
is-ssl: true
secret: 'xxx'
nickname: 'test'
# casbin configuration
casbin:
model-path: './resource/rbac_model.conf'
# jwt configuration
jwt:
signing-key: 'qmPlus'
# system configuration
system:
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: 'mysql'
oss-type: 'local'
config-env: 'GVA_CONFIG'
need-init-data: false
use-multipoint: false
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
# mysql connect configuration
mysql:
username: root
password: 'Aa@6447985'
path: '127.0.0.1:3306'
db-name: 'qmPlus'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
db-name: 'qmPlus'
username: 'root'
password: 'Aa@6447985'
max-idle-conns: 10
max-open-conns: 10
log-mode: false
# Postgresql connect configuration
postgresql:
username: 'gorm'
password: 'gorm'
db-name: 'gorm'
port: '9920'
config: 'sslmode=disable TimeZone=Asia/Shanghai'
max-idle-conns: 10
max-open-conns: 10
logger: false
prefer-simple-protocol: true
# sqlite connect configuration
# sqlite需要gcc支持 windows用户需要自行安装gcc
# sqlite connect configuration (sqlite需要gcc支持 windows用户需要自行安装gcc)
sqlite:
# path: 'file::memory:?cache=shared' # 内存模式
path: 'db.db'
max-idle-conns: 10
max-open-conns: 10
......@@ -42,70 +72,37 @@ sqlite:
# Sqlserver connect configuration
sqlserver:
path: 'localhost:9930'
db-name: 'gorm'
username: 'gorm'
password: 'LoremIpsum86'
db-name: 'gorm'
path: 'localhost:9930'
max-idle-conns: 10
max-open-conns: 10
logger: true
# oss configuration
# Postgresql connect configuration
postgresql:
host: '127.0.0.1'
port: '9920'
config: 'sslmode=disable TimeZone=Asia/Shanghai'
db-name: 'gorm'
username: 'gorm'
password: 'gorm'
max-idle-conns: 10
max-open-conns: 10
prefer-simple-protocol: true
logger: false
# 切换本地与七牛云上传,分配头像和文件路径
localupload:
local: false
file-path: uploads/file
# local configuration
local:
path: 'uploads/file'
# 请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
qiniu:
access-key: '25j8dYBZ2wuiy0yhwShytjZDTX662b8xiFguwxzZ'
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
zone: 'ZoneHuadong'
bucket: 'qm-plus-img'
img-path: 'http://qmplusimg.henrongyi.top'
# redis configuration
redis:
addr: '127.0.0.1:6379'
password: ''
db: 0
# system configuration
system:
use-multipoint: false
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: "mysql" # support mysql/postgresql/sqlite/sqlserver
need-init-data: false
error-to-email: false
config-env: "GVA_CONFIG"
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
# zap logger configuration
zap:
# 可使用 "debug", "info", "warn", "error", "dpanic", "panic", "fatal",
level: 'info'
# console: 控制台, json: json格式输出
format: 'console'
prefix: '[GIN-VUE-ADMIN]'
director: 'log'
link-name: 'latest_log'
show-line: true
# LowercaseLevelEncoder:小写, LowercaseColorLevelEncoder:小写带颜色,CapitalLevelEncoder: 大写, CapitalColorLevelEncoder: 大写带颜色,
encode-level: 'LowercaseColorLevelEncoder'
stacktrace-key: 'stacktrace'
log-in-console: true
email:
email-from: 'xxx@163.com'
email-nickname: 'test'
email-secret: 'xxx'
email-to: 'xxx@qq.com'
email-host: 'smtp.163.com'
email-port: 465
email-is-ssl: true
\ No newline at end of file
use-https: false
access-key: '25j8dYBZ2wuiy0yhwShytjZDTX662b8xiFguwxzZ'
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
use-cdn-domains: false
\ No newline at end of file
package config
type Captcha struct {
KeyLong int `mapstructure:"key-long" json:"keyLong" yaml:"key-long"`
ImgWidth int `mapstructure:"img-width" json:"imgWidth" yaml:"img-width"`
ImgHeight int `mapstructure:"img-height" json:"imgHeight" yaml:"img-height"`
}
package config
type Casbin struct {
ModelPath string `mapstructure:"model-path" json:"modelPath" yaml:"model-path"`
}
package config
type Server struct {
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
Postgresql Postgresql `mapstructure:"postgresql" json:"postgresql" yaml:"postgresql"`
Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"`
Sqlserver Sqlserver `mapstructure:"sqlserver" json:"sqlserver" yaml:"sqlserver"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
Casbin Casbin `mapstructure:"casbin" json:"casbin" yaml:"casbin"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
System System `mapstructure:"system" json:"system" yaml:"system"`
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
LocalUpload LocalUpload `mapstructure:"localUpload" json:"localUpload" yaml:"localUpload"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
}
type System struct {
UseMultipoint bool `mapstructure:"use-multipoint" json:"useMultipoint" yaml:"use-multipoint"`
Env string `mapstructure:"env" json:"env" yaml:"env"`
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"`
DbType string `mapstructure:"db-type" json:"dbType" yaml:"db-type"`
NeedInitData bool `mapstructure:"need-init-data" json:"needInitData" yaml:"need-init-data"`
ErrorToEmail bool `mapstructure:"error-to-email" json:"errorToEmail" yaml:"error-to-email"`
ConfigEnv string `mapstructure:"config-env" json:"configEnv" yaml:"config-env"`
}
type JWT struct {
SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
}
type Casbin struct {
ModelPath string `mapstructure:"model-path" json:"modelPath" yaml:"model-path"`
}
type Mysql struct {
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
Path string `mapstructure:"path" json:"path" yaml:"path"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
Config string `mapstructure:"config" json:"config" yaml:"config"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
}
type Postgresql struct {
Host string `mapstructure:"host" json:"host" yaml:"host"`
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
Port string `mapstructure:"port" json:"port" yaml:"port"`
Config string `mapstructure:"config" json:"config" yaml:"config"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
PreferSimpleProtocol bool `mapstructure:"prefer-simple-protocol" json:"preferSimpleProtocol" yaml:"prefer-simple-protocol"`
}
type Sqlite struct {
Path string `mapstructure:"path" json:"path" yaml:"path"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
}
type Sqlserver struct {
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
Path string `mapstructure:"path" json:"path" yaml:"path"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
}
type Redis struct {
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
DB int `mapstructure:"db" json:"db" yaml:"db"`
}
type LocalUpload struct {
Local bool `mapstructure:"local" json:"local" yaml:"local"`
FilePath string `mapstructure:"file-path" json:"filePath" yaml:"file-path"`
}
type Qiniu struct {
AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"`
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
ImgPath string `mapstructure:"img-path" json:"imgPath" yaml:"img-path"`
}
type Captcha struct {
KeyLong int `mapstructure:"key-long" json:"keyLong" yaml:"key-long"`
ImgWidth int `mapstructure:"img-width" json:"imgWidth" yaml:"img-width"`
ImgHeight int `mapstructure:"img-height" json:"imgHeight" yaml:"img-height"`
}
type Zap struct {
Level string `mapstructure:"level" json:"level" yaml:"level"`
Format string `mapstructure:"format" json:"format" yaml:"format"`
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`
Director string `mapstructure:"director" json:"director" yaml:"director"`
LinkName string `mapstructure:"link-name" json:"linkName" yaml:"link-name"`
ShowLine bool `mapstructure:"show-line" json:"showLine" yaml:"showLine"`
EncodeLevel string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"`
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"`
LogInConsole bool `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"`
}
type Email struct {
EmailFrom string `mapstructure:"email-from" json:"emailFrom" yaml:"email-from"`
EmailNickname string `mapstructure:"email-nickname" json:"emailNickname" yaml:"email-nickname"`
EmailSecret string `mapstructure:"email-secret" json:"emailSecret" yaml:"email-secret"`
EmailTo string `mapstructure:"email-to" json:"emailTo" yaml:"email-to"`
EmailHost string `mapstructure:"email-host" json:"emailHost" yaml:"email-host"`
EmailPort int `mapstructure:"email-port" json:"emailPort" yaml:"email-port"`
EmailIsSSL bool `mapstructure:"email-is-ssl" json:"emailIsSSL" yaml:"email-is-ssl"`
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
Casbin Casbin `mapstructure:"casbin" json:"casbin" yaml:"casbin"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
// gorm
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"`
Sqlserver Sqlserver `mapstructure:"sqlserver" json:"sqlserver" yaml:"sqlserver"`
Postgresql Postgresql `mapstructure:"postgresql" json:"postgresql" yaml:"postgresql"`
// oss
Local Local `mapstructure:"local" json:"local" yaml:"local"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
}
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:"isSSL" yaml:"is-ssl"`
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"`
Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"`
}
package config
type Mysql struct {
Path string `mapstructure:"path" json:"path" yaml:"path"`
Config string `mapstructure:"config" json:"config" yaml:"config"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
}
type Sqlite struct {
Path string `mapstructure:"path" json:"path" yaml:"path"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
}
type Sqlserver struct {
Path string `mapstructure:"path" json:"path" yaml:"path"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
}
type Postgresql struct {
Host string `mapstructure:"host" json:"host" yaml:"host"`
Port string `mapstructure:"port" json:"port" yaml:"port"`
Config string `mapstructure:"config" json:"config" yaml:"config"`
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
Username string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
PreferSimpleProtocol bool `mapstructure:"prefer-simple-protocol" json:"preferSimpleProtocol" yaml:"prefer-simple-protocol"`
Logger bool `mapstructure:"logger" json:"logger" yaml:"logger"`
}
package config
type JWT struct {
SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
}
package config
type Local struct {
Path string `mapstructure:"path" json:"path" yaml:"path" `
}
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:"imgPath" yaml:"img-path"`
UseHTTPS bool `mapstructure:"use-https" json:"useHttps" yaml:"use-https"`
AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"`
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"useCdnDomains" yaml:"use-cdn-domains"`
}
package config
type Redis struct {
DB int `mapstructure:"db" json:"db" yaml:"db"`
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
}
\ No newline at end of file
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:"dbType" yaml:"db-type"`
OssType string `mapstructure:"oss-type" json:"ossType" yaml:"oss-type"`
ConfigEnv string `mapstructure:"config-env" json:"configEnv" yaml:"config-env"`
NeedInitData bool `mapstructure:"need-init-data" json:"needInitData" yaml:"need-init-data"`
UseMultipoint bool `mapstructure:"use-multipoint" json:"useMultipoint" yaml:"use-multipoint"`
}
package config
type Zap struct {
Level string `mapstructure:"level" json:"level" yaml:"level"`
Format string `mapstructure:"format" json:"format" yaml:"format"`
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`
Director string `mapstructure:"director" json:"director" yaml:"director"`
LinkName string `mapstructure:"link-name" json:"linkName" yaml:"link-name"`
ShowLine bool `mapstructure:"show-line" json:"showLine" yaml:"showLine"`
EncodeLevel string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"`
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"`
LogInConsole bool `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"`
}
......@@ -87,6 +87,8 @@ func InitSysApi() (err error) {
{gorm.Model{ID: 63, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/simpleUploader/checkFileMd5", "文件完整度验证", "simpleUploader", "GET"},
{gorm.Model{ID: 64, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/simpleUploader/mergeFileMd5", "上传完成合并文件", "simpleUploader", "GET"},
{gorm.Model{ID: 65, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserInfo", "设置用户信息", "user", "PUT"},
{gorm.Model{ID: 66, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getServerInfo", "获取服务器信息", "system", "POST"},
{gorm.Model{ID: 67, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/email/emailTest", "发送测试邮件", "email", "POST"},
}
if tx.Create(&insert).Error != nil { // 遇到错误时回滚事务
tx.Rollback()
......@@ -161,6 +163,7 @@ func InitCasbinModel() (err error) {
{"p", "888", "/jwt/jsonInBlacklist", "POST"},
{"p", "888", "/system/getSystemConfig", "POST"},
{"p", "888", "/system/setSystemConfig", "POST"},
{"p", "888", "/system/getServerInfo", "POST"},
{"p", "888", "/customer/customer", "POST"},
{"p", "888", "/customer/customer", "PUT"},
{"p", "888", "/customer/customer", "DELETE"},
......@@ -187,6 +190,7 @@ func InitCasbinModel() (err error) {
{"p", "888", "/sysOperationRecord/getSysOperationRecordList", "GET"},
{"p", "888", "/sysOperationRecord/deleteSysOperationRecordByIds", "DELETE"},
{"p", "888", "/user/setUserInfo", "PUT"},
{"p", "888", "/email/emailTest", "POST"},
{"p", "8881", "/base/login", "POST"},
{"p", "8881", "/base/register", "POST"},
{"p", "8881", "/api/createApi", "POST"},
......@@ -311,6 +315,7 @@ func InitSysBaseMenus() (err error) {
{Model: gorm.Model{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "operation", Name: "operation", Component: "view/superAdmin/operation/sysOperationRecord.vue", Sort: 6, Meta: model.Meta{Title: "操作历史", Icon: "time"}},
{Model: gorm.Model{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "simpleUploader", Name: "simpleUploader", Component: "view/example/simpleUploader/simpleUploader", Sort: 6, Meta: model.Meta{Title: "断点续传(插件版)", Icon: "upload"}},
{Model: gorm.Model{ID: 26, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Hidden: false, Component: "/", Sort: 0, Meta: model.Meta{Title: "官方网站", Icon: "s-home"}},
{Model: gorm.Model{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "state", Name: "state", Hidden: false, Component: "view/system/state.vue", Sort: 6, Meta: model.Meta{Title: "服务器状态", Icon: "cloudy"}},
}
if tx.Create(&insert).Error != nil { // 遇到错误时回滚事务
tx.Rollback()
......@@ -369,6 +374,7 @@ func InitSysAuthorityMenus() (err error) {
{"888", 24},
{"888", 25},
{"888", 26},
{"888", 27},
{"8881", 1},
{"8881", 2},
{"8881", 8},
......
......@@ -25,6 +25,8 @@ func Gorm() {
// GormSqlite()
case "sqlserver":
GormSqlServer()
default:
GormMysql()
}
}
......
......@@ -15,8 +15,7 @@ import (
func Routers() *gin.Engine {
var Router = gin.Default()
// 为用户头像和文件提供静态地址
Router.StaticFS(global.GVA_CONFIG.LocalUpload.FilePath, http.Dir(global.GVA_CONFIG.LocalUpload.FilePath))
Router.StaticFS(global.GVA_CONFIG.Local.Path, http.Dir(global.GVA_CONFIG.Local.Path)) // 为用户头像和文件提供静态地址
// Router.Use(middleware.LoadTls()) // 打开就能玩https了
global.GVA_LOG.Info("use middleware logger")
// 跨域
......
......@@ -19,10 +19,10 @@ func ErrorToEmail() gin.HandlerFunc {
if claims, ok := c.Get("claims"); ok {
waitUse := claims.(*request.CustomClaims)
username = waitUse.Username
}else {
} else {
id, _ := strconv.Atoi(c.Request.Header.Get("x-user-id"))
err, user := service.FindUserById(id)
if err != nil{
if err != nil {
username = "Unknown"
}
username = user.Username
......@@ -43,12 +43,10 @@ func ErrorToEmail() gin.HandlerFunc {
status := c.Writer.Status()
record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
str := "接收到的请求为" + record.Body + "\n" + "请求方式为" + record.Method + "\n" + "报错信息如下" + record.ErrorMessage + "\n" + "耗时" + latency.String() + "\n"
if global.GVA_CONFIG.System.ErrorToEmail {
if status != 200 {
subject := username + "" +record.Ip + "调用了" + record.Path + "报错了"
if err := utils.ErrorToEmail(subject, str); err != nil {
global.GVA_LOG.Error("ErrorToEmail Failed, err:", zap.Any("err", err))
}
if status != 200 {
subject := username + "" + record.Ip + "调用了" + record.Path + "报错了"
if err := utils.ErrorToEmail(subject, str); err != nil {
global.GVA_LOG.Error("ErrorToEmail Failed, err:", zap.Any("err", err))
}
}
}
......
......@@ -49,6 +49,12 @@ func JWTAuth() gin.HandlerFunc {
c.Abort()
return
}
if err, _ = service.FindUserByUuid(claims.UUID.String()); err != nil{
response.Result(response.ERROR, gin.H{
"reload": true,
}, err.Error(), c)
c.Abort()
}
if claims.ExpiresAt - time.Now().Unix()<claims.BufferTime {
claims.ExpiresAt = time.Now().Unix() + 60*60*24*7
newToken,_ := j.CreateToken(*claims)
......
......@@ -47,7 +47,7 @@ func OperationRecord() gin.HandlerFunc {
UserID: userId,
}
values := c.Request.Header.Values("content-type")
if strings.Contains(values[0], "boundary"){
if len(values) >0 && strings.Contains(values[0], "boundary") {
record.Body = "file"
}
writer := responseBodyWriter{
......
......@@ -2,14 +2,14 @@ package router
import (
"gin-vue-admin/api/v1"
"gin-vue-admin/middleware"
"github.com/gin-gonic/gin"
)
func InitSystemRouter(Router *gin.RouterGroup) {
UserRouter := Router.Group("system").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
SystemRouter := Router.Group("system")
{
UserRouter.POST("getSystemConfig", v1.GetSystemConfig) // 获取配置文件内容
UserRouter.POST("setSystemConfig", v1.SetSystemConfig) // 设置配置文件内容
SystemRouter.POST("getSystemConfig", v1.GetSystemConfig) // 获取配置文件内容
SystemRouter.POST("setSystemConfig", v1.SetSystemConfig) // 设置配置文件内容
SystemRouter.POST("getServerInfo", v1.GetServerInfo) // 获取服务器信息
}
}
......@@ -5,9 +5,8 @@ import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/utils"
"gin-vue-admin/utils/upload"
"mime/multipart"
"os"
"strings"
)
......@@ -43,19 +42,9 @@ func FindFile(id uint) (error, model.ExaFileUploadAndDownload) {
func DeleteFile(file model.ExaFileUploadAndDownload) (err error) {
var fileFromDb model.ExaFileUploadAndDownload
err, fileFromDb = FindFile(file.ID)
if err != nil {
return errors.New("文件不存在")
}
if global.GVA_CONFIG.LocalUpload.Local { // 删除本地文件
if strings.Contains(fileFromDb.Url, global.GVA_CONFIG.LocalUpload.FilePath) {
if err = os.Remove(fileFromDb.Url); err != nil {
err = errors.New("本地文件删除失败, err:" + err.Error())
}
}
} else {
if err = utils.DeleteFile(file.Key); err != nil { // 删除七牛云文件
err = errors.New("七牛云文件删除失败, err:" + err.Error())
}
oss := upload.NewOss()
if err = oss.DeleteFile(fileFromDb.Key); err != nil{
return errors.New("文件删除失败")
}
err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(file).Error
return err
......@@ -88,19 +77,19 @@ func GetFileRecordInfoList(info request.PageInfo) (err error, list interface{},
// @return file file model.ExaFileUploadAndDownload
func UploadFile(header *multipart.FileHeader, noSave string) (err error, file model.ExaFileUploadAndDownload) {
var filePath, key string
var f model.ExaFileUploadAndDownload
if global.GVA_CONFIG.LocalUpload.Local { // 本地上传
err, filePath, key = utils.UploadFileLocal(header)
} else { // 七牛云上传
err, filePath, key = utils.UploadRemote(header)
oss := upload.NewOss()
filePath, key, uploadErr := oss.UploadFile(header)
if uploadErr != nil {
panic(err)
}
if noSave == "0" {
f.Url = filePath
f.Name = header.Filename
s := strings.Split(f.Name, ".")
f.Tag = s[len(s)-1]
f.Key = key
s := strings.Split(header.Filename, ".")
f := model.ExaFileUploadAndDownload{
Url: filePath,
Name: header.Filename,
Tag: s[len(s)-1],
Key: key,
}
return Upload(f), f
}
return
......
......@@ -5,6 +5,7 @@ import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/utils"
"go.uber.org/zap"
)
// @title GetSystemConfig
......@@ -31,3 +32,30 @@ func SetSystemConfig(system model.System) (err error) {
err = global.GVA_VP.WriteConfig()
return err
}
// @title GetServerInfo
// @description get server info , 获取服务器信息
// @auth (2020/04/05 20:22)
// @return server *utils.Server
// @return err error
func GetServerInfo() (server *utils.Server, err error) {
var s utils.Server
s.Os = utils.InitOS()
if s.Cpu, err = utils.InitCPU(); err != nil{
global.GVA_LOG.Error("func utils.InitCPU() Failed!", zap.String("err", err.Error()))
return &s, err
}
if s.Rrm, err = utils.InitRAM(); err != nil{
global.GVA_LOG.Error("func utils.InitRAM() Failed!", zap.String("err", err.Error()))
return &s, err
}
if s.Disk, err = utils.InitDisk(); err != nil{
global.GVA_LOG.Error("func utils.InitDisk() Failed!", zap.String("err", err.Error()))
return &s, err
}
return &s, nil
}
......@@ -125,3 +125,18 @@ func FindUserById(id int) (err error, user *model.SysUser) {
err = global.GVA_DB.Where("`id` = ?", id).First(&u).Error
return err, &u
}
// @title FindUserByUuid
// @description Get user information by uuid, 通过uuid获取用户信息
// @auth (2020/04/05 20:22)
// @param uuid string
// @return err error
// @return user *model.SysUser
func FindUserByUuid(uuid string) (err error, user *model.SysUser) {
var u model.SysUser
if err = global.GVA_DB.Where("`uuid` = ?", uuid).First(&u).Error; err != nil{
return errors.New("用户不存在"), &u
}
return nil, &u
}
\ No newline at end of file
......@@ -12,13 +12,13 @@ import (
)
func Email(subject string, body string) error {
to := strings.Split(global.GVA_CONFIG.Email.EmailTo, ",")
to := strings.Split(global.GVA_CONFIG.Email.To, ",")
return send(to, subject, body)
}
// ErrorToEmail Error 发送邮件
func ErrorToEmail(subject string, body string) error {
to := strings.Split(global.GVA_CONFIG.Email.EmailTo, ",")
to := strings.Split(global.GVA_CONFIG.Email.To, ",")
if to[len(to)-1] == "" { // 判断切片的最后一个元素是否为空,为空则移除
to = to[:len(to)-1]
}
......@@ -26,17 +26,17 @@ func ErrorToEmail(subject string, body string) error {
}
func EmailTest(subject string, body string) error {
to := []string{global.GVA_CONFIG.Email.EmailFrom}
to := []string{global.GVA_CONFIG.Email.From}
return send(to, subject, body)
}
func send(to []string, subject string, body string) error {
from := global.GVA_CONFIG.Email.EmailFrom
nickname := global.GVA_CONFIG.Email.EmailNickname
secret := global.GVA_CONFIG.Email.EmailSecret
host := global.GVA_CONFIG.Email.EmailHost
port := global.GVA_CONFIG.Email.EmailPort
isSSL := global.GVA_CONFIG.Email.EmailIsSSL
from := global.GVA_CONFIG.Email.From
nickname := global.GVA_CONFIG.Email.Nickname
secret := global.GVA_CONFIG.Email.Secret
host := global.GVA_CONFIG.Email.Host
port := global.GVA_CONFIG.Email.Port
isSSL := global.GVA_CONFIG.Email.IsSSL
auth := smtp.PlainAuth("", from, secret, host)
e := email.NewEmail()
......
package utils
import (
"fmt"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem"
"runtime"
"time"
)
const (
B = 1
KB = 1024 * B
......@@ -16,47 +15,88 @@ const (
GB = 1024 * MB
)
//服务器硬盘使用量
func DiskCheck() {
u, _ := disk.Usage("/")
usedMB := int(u.Used) / MB
usedGB := int(u.Used) / GB
totalMB := int(u.Total) / MB
totalGB := int(u.Total) / GB
usedPercent := int(u.UsedPercent)
fmt.Printf("Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%\n", usedMB, usedGB, totalMB, totalGB, usedPercent)
type Server struct {
Os Os `json:"os"`
Cpu Cpu `json:"cpu"`
Rrm Rrm `json:"ram"`
Disk Disk `json:"disk"`
}
type Os struct {
GOOS string `json:"goos"`
NumCPU int `json:"numCpu"`
Compiler string `json:"compiler"`
GoVersion string `json:"goVersion"`
NumGoroutine int `json:"numGoroutine"`
}
type Cpu struct {
Cpus []float64 `json:"cpus"`
Cores int `json:"cores"`
}
type Rrm struct {
UsedMB int `json:"usedMb"`
TotalMB int `json:"totalMb"`
UsedPercent int `json:"usedPercent"`
}
//OS
func OSCheck() {
fmt.Printf("goOs:%s,compiler:%s,numCpu:%d,version:%s,numGoroutine:%d\n", runtime.GOOS, runtime.Compiler, runtime.NumCPU(), runtime.Version(), runtime.NumGoroutine())
type Disk struct {
UsedMB int `json:"usedMb"`
UsedGB int `json:"usedGb"`
TotalMB int `json:"totalMb"`
TotalGB int `json:"totalGb"`
UsedPercent int `json:"usedPercent"`
}
//CPU 使用量
func CPUCheck() {
cores, _ := cpu.Counts(false)
// InitOS OS信息
func InitOS() (o Os) {
o.GOOS = runtime.GOOS
o.NumCPU = runtime.NumCPU()
o.Compiler = runtime.Compiler
o.GoVersion = runtime.Version()
o.NumGoroutine = runtime.NumGoroutine()
return o
}
// InitCPU CPU信息
func InitCPU() (c Cpu, err error) {
if cores, err := cpu.Counts(false); err != nil {
return c, err
} else {
c.Cores = cores
}
if cpus, err := cpu.Percent(time.Duration(200)*time.Millisecond, true); err != nil {
return c, err
} else {
c.Cpus = cpus
}
return c, nil
}
// InitRAM ARM信息
func InitRAM() (r Rrm, err error) {
if u, err := mem.VirtualMemory(); err != nil{
return r, err
}else {
r.UsedMB = int(u.Used) / MB
r.TotalMB = int(u.Total) / MB
r.UsedPercent = int(u.UsedPercent)
}
return r, nil
}
cpus, err := cpu.Percent(time.Duration(200)*time.Millisecond, true)
if err == nil {
for i, c := range cpus {
fmt.Printf("cpu%d : %f%%\n", i, c)
}
// InitDisk 硬盘信息
func InitDisk() (d Disk, err error) {
if u, err := disk.Usage("/"); err != nil{
return d, err
} else {
d.UsedMB = int(u.Used) / MB
d.UsedGB = int(u.Used) / GB
d.TotalMB = int(u.Total) / MB
d.TotalGB = int(u.Total) / GB
d.UsedPercent = int(u.UsedPercent)
}
a, _ := load.Avg()
l1 := a.Load1
l5 := a.Load5
l15 := a.Load15
fmt.Println(l1)
fmt.Println(l5)
fmt.Println(l15)
fmt.Println(cores)
}
//内存使用量
func RAMCheck() {
u, _ := mem.VirtualMemory()
usedMB := int(u.Used) / MB
totalMB := int(u.Total) / MB
usedPercent := int(u.UsedPercent)
fmt.Printf("usedMB:%d,totalMB:%d,usedPercent:%d", usedMB, totalMB, usedPercent)
return d, nil
}
\ No newline at end of file
package upload
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/utils"
"go.uber.org/zap"
"io"
"mime/multipart"
"os"
"path"
"strings"
"time"
)
type Local struct{}
// UploadFile 上传文件
func (l Local) UploadFile(file *multipart.FileHeader) (string, string, error) {
// 读取文件后缀
ext := path.Ext(file.Filename)
// 读取文件名并加密
name := strings.TrimSuffix(file.Filename, ext)
name = utils.MD5V([]byte(name))
// 拼接新文件名
filename := name + "_" + time.Now().Format("20060102150405") + ext
// 尝试创建此路径
mkdirErr := os.MkdirAll(global.GVA_CONFIG.Local.Path, os.ModePerm)
if mkdirErr != nil {
global.GVA_LOG.Error("function os.MkdirAll() Filed", zap.Any("err", mkdirErr.Error()))
return "", "", errors.New("function os.MkdirAll() Filed, err:" + mkdirErr.Error())
}
// 拼接路径和文件名
p := global.GVA_CONFIG.Local.Path + "/" + filename
f, openError := file.Open() // 读取文件
if openError != nil {
global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error()))
return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
}
defer f.Close() // 创建文件 defer 关闭
out, createErr := os.Create(p)
if createErr != nil {
global.GVA_LOG.Error("function os.Create() Filed", zap.Any("err", createErr.Error()))
return "", "", errors.New("function os.Create() Filed, err:" + createErr.Error())
}
defer out.Close() // 创建文件 defer 关闭
_, copyErr := io.Copy(out, f) // 传输(拷贝)文件
if copyErr != nil {
global.GVA_LOG.Error("function io.Copy() Filed", zap.Any("err", copyErr.Error()))
return "", "", errors.New("function io.Copy() Filed, err:" + copyErr.Error())
}
return p, filename, nil
}
// DeleteFile 删除文件
func (l Local) DeleteFile(key string) error {
p := global.GVA_CONFIG.Local.Path + "/" + key
if strings.Contains(p, global.GVA_CONFIG.Local.Path) {
if err := os.Remove(p); err != nil {
return errors.New("本地文件删除失败, err:" + err.Error())
}
}
return nil
}
package upload
import (
"context"
"errors"
"fmt"
"gin-vue-admin/global"
"github.com/qiniu/api.v7/v7/auth/qbox"
"github.com/qiniu/api.v7/v7/storage"
"go.uber.org/zap"
"mime/multipart"
"time"
)
type Qiniu struct{}
// Upload 上传文件
func (*Qiniu) UploadFile(file *multipart.FileHeader) (string, string, error) {
putPolicy := storage.PutPolicy{Scope: global.GVA_CONFIG.Qiniu.Bucket}
mac := qbox.NewMac(global.GVA_CONFIG.Qiniu.AccessKey, global.GVA_CONFIG.Qiniu.SecretKey)
upToken := putPolicy.UploadToken(mac)
cfg := qiniuConfig()
formUploader := storage.NewFormUploader(cfg)
ret := storage.PutRet{}
putExtra := storage.PutExtra{Params: map[string]string{"x:name": "github logo"}}
f, openError := file.Open()
if openError != nil {
global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error()))
return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
}
fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) // 文件名格式 自己可以改 建议保证唯一性
putErr := formUploader.Put(context.Background(), &ret, upToken, fileKey, f, file.Size, &putExtra)
if putErr != nil {
global.GVA_LOG.Error("function formUploader.Put() Filed", zap.Any("err", putErr.Error()))
return "", "", errors.New("function formUploader.Put() Filed, err:" + putErr.Error())
}
return global.GVA_CONFIG.Qiniu.ImgPath + "/" + ret.Key, ret.Key, nil
}
// DeleteFile 删除文件
func (*Qiniu) DeleteFile(key string) error {
mac := qbox.NewMac(global.GVA_CONFIG.Qiniu.AccessKey, global.GVA_CONFIG.Qiniu.SecretKey)
cfg := qiniuConfig()
bucketManager := storage.NewBucketManager(mac, cfg)
if err := bucketManager.Delete(global.GVA_CONFIG.Qiniu.Bucket, key); err != nil{
global.GVA_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error()))
return errors.New("function bucketManager.Delete() Filed, err:" + err.Error())
}
return nil
}
// config 根据配置文件进行返回七牛云的配置
func qiniuConfig() *storage.Config {
cfg := storage.Config{
UseHTTPS: global.GVA_CONFIG.Qiniu.UseHTTPS,
UseCdnDomains: global.GVA_CONFIG.Qiniu.UseCdnDomains,
}
switch global.GVA_CONFIG.Qiniu.Zone { // 根据配置文件进行初始化空间对应的机房
case "ZoneHuadong":
cfg.Zone = &storage.ZoneHuadong
case "ZoneHuabei":
cfg.Zone = &storage.ZoneHuabei
case "ZoneHuanan":
cfg.Zone = &storage.ZoneHuanan
case "ZoneBeimei":
cfg.Zone = &storage.ZoneBeimei
case "ZoneXinjiapo":
cfg.Zone = &storage.ZoneXinjiapo
}
return &cfg
}
\ No newline at end of file
package upload
import (
"gin-vue-admin/global"
"mime/multipart"
)
var Oss OSS
type OSS interface {
UploadFile(file *multipart.FileHeader) (string, string, error)
DeleteFile(key string) error
}
func NewOss() OSS {
switch global.GVA_CONFIG.System.OssType {
case "local":
return &Local{}
case "qiniu":
return &Qiniu{}
default:
return &Local{}
}
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ func UploadFileLocal(file *multipart.FileHeader) (err error, localPath string, k
// 拼接新文件名
lastName := fileName + "_" + time.Now().Format("20060102150405") + ext
// 读取全局变量的定义路径
savePath := global.GVA_CONFIG.LocalUpload.FilePath
savePath := global.GVA_CONFIG.Local.Path
// 尝试创建此路径
err = os.MkdirAll(savePath, os.ModePerm)
if err != nil {
......
import service from '@/utils/request'
import service from "@/utils/request";
// @Tags systrm
// @Summary 获取配置文件内容
......@@ -7,11 +7,11 @@ import service from '@/utils/request'
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getSystemConfig [post]
export const getSystemConfig = () => {
return service({
url: "/system/getSystemConfig",
method: 'post',
})
}
return service({
url: "/system/getSystemConfig",
method: "post",
});
};
// @Tags system
// @Summary 设置配置文件内容
......@@ -21,9 +21,22 @@ export const getSystemConfig = () => {
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/setSystemConfig [post]
export const setSystemConfig = (data) => {
return service({
url: "/system/setSystemConfig",
method: 'post',
data
})
}
\ No newline at end of file
return service({
url: "/system/setSystemConfig",
method: "post",
data,
});
};
// @Tags system
// @Summary 获取服务器运行状态
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getServerInfo [post]
export const getSystemState = () => {
return service({
url: "/system/getServerInfo",
method: "post",
});
};
......@@ -94,7 +94,7 @@ export default {
return false;
}
md5 = SparkMD5.ArrayBuffer.hash(e.target.result, false);
file.uniqueIdentifier = md5;
if (md5 != "") {
const res = await checkFileMd5({ md5: md5 });
......
<template>
<div>
<el-row :gutter="15" class="system_state">
<el-col :span="12">
<el-card v-if="state.os" class="card_item">
<div slot="header">Runtime</div>
<div>
<el-row :gutter="10">
<el-col :span="12">os:</el-col>
<el-col :span="12" v-text="state.os.goos"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">cpu nums:</el-col>
<el-col :span="12" v-text="state.os.numCpu"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">compiler:</el-col>
<el-col :span="12" v-text="state.os.compiler"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">go version:</el-col>
<el-col :span="12" v-text="state.os.goVersion"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">goroutine nums:</el-col>
<el-col :span="12" v-text="state.os.numGoroutine"></el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card v-if="state.disk" class="card_item">
<div slot="header">Disk</div>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="12">total (MB)</el-col>
<el-col :span="12" v-text="state.disk.totalMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (MB)</el-col>
<el-col :span="12" v-text="state.disk.usedMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (GB)</el-col>
<el-col :span="12" v-text="state.disk.totalGb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (GB)</el-col>
<el-col :span="12" v-text="state.disk.usedGb"></el-col>
</el-row>
</el-col>
<el-col :span="12">
<el-progress
type="dashboard"
:percentage="state.disk.usedPercent"
:color="colors"
></el-progress>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="15" class="system_state">
<el-col :span="12">
<el-card
class="card_item"
v-if="state.cpu"
:body-style="{ height: '180px', 'overflow-y': 'scroll' }"
>
<div slot="header">CPU</div>
<div>
<el-row :gutter="10">
<el-col :span="12">physical number of cores:</el-col>
<el-col :span="12" v-text="state.cpu.cores"> </el-col>
</el-row>
<template v-for="(item, index) in state.cpu.cpus">
<el-row :key="index" :gutter="10">
<el-col :span="12">core {{ index }}:</el-col>
<el-col :span="12"
><el-progress
type="line"
:percentage="+item.toFixed(0)"
:color="colors"
></el-progress
></el-col>
</el-row>
</template>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="card_item" v-if="state.ram">
<div slot="header">Ram</div>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="12">total (MB)</el-col>
<el-col :span="12" v-text="state.ram.totalMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (MB)</el-col>
<el-col :span="12" v-text="state.ram.usedMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (GB)</el-col>
<el-col :span="12" v-text="state.ram.totalMb / 1024"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (GB)</el-col>
<el-col
:span="12"
v-text="(state.ram.usedMb / 1024).toFixed(2)"
></el-col>
</el-row>
</el-col>
<el-col :span="12">
<el-progress
type="dashboard"
:percentage="state.ram.usedPercent"
:color="colors"
></el-progress>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getSystemState } from "@/api/system.js";
export default {
name: "State",
data() {
return {
state: {},
colors: [
{ color: "#5cb87a", percentage: 20 },
{ color: "#e6a23c", percentage: 40 },
{ color: "#f56c6c", percentage: 80 },
],
};
},
created() {
this.reload();
},
methods: {
async reload() {
const { data } = await getSystemState();
this.state = data.server;
},
},
};
</script>
<style>
.system_state {
padding: 10px;
}
.card_item {
height: 280px;
}
</style>
<template>
<div class="system">
<el-form :model="config" label-width="100px" ref="form" class="system">
<!-- System start -->
<h2>系统配置</h2>
<el-form-item label="多点登录拦截">
<el-checkbox v-model="config.system.useMultipoint">开启</el-checkbox>
</el-form-item>
<el-form-item label="环境值">
<el-input v-model="config.system.env"></el-input>
</el-form-item>
......@@ -13,20 +11,126 @@
</el-form-item>
<el-form-item label="数据库类型">
<el-select v-model="config.system.dbType">
<el-option value="sqlite"></el-option>
<el-option value="mysql"></el-option>
<el-option value="postgresql"></el-option>
<el-option value="sqlite"></el-option>
<el-option value="sqlserver"></el-option>
<el-option value="postgresql"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Oss类型">
<el-select v-model="config.system.ossType">
<el-option value="local"></el-option>
<el-option value="qiniu"></el-option>
</el-select>
</el-form-item>
<el-form-item label="配置文件环境变量名">
<el-input v-model.number="config.system.configEnv"></el-input>
</el-form-item>
<el-form-item label="数据初始化">
<el-checkbox v-model="config.system.needInitData">开启</el-checkbox>
</el-form-item>
<el-form-item label="多点登录拦截">
<el-checkbox v-model="config.system.useMultipoint">开启</el-checkbox>
</el-form-item>
<!-- System end -->
<!-- JWT start -->
<h2>jwt签名</h2>
<el-form-item label="jwt签名">
<el-input v-model="config.jwt.signingKey"></el-input>
</el-form-item>
<!-- JWT end -->
<!-- Zap start -->
<h2>Zap日志配置</h2>
<el-form-item label="级别">
<el-input v-model.number="config.zap.level"></el-input>
</el-form-item>
<el-form-item label="输出">
<el-input v-model="config.zap.format"></el-input>
</el-form-item>
<el-form-item label="日志前缀">
<el-input v-model="config.zap.prefix"></el-input>
</el-form-item>
<el-form-item label="日志文件夹">
<el-input v-model="config.zap.director"></el-input>
</el-form-item>
<el-form-item label="软链接名称">
<el-input v-model="config.zap.linkName"></el-input>
</el-form-item>
<el-form-item label="编码级">
<el-input v-model="config.zap.encodeLevel"></el-input>
</el-form-item>
<el-form-item label="栈名">
<el-input v-model="config.zap.stacktraceKey"></el-input>
</el-form-item>
<el-form-item label="显示行">
<el-checkbox v-model="config.zap.showLine"></el-checkbox>
</el-form-item>
<el-form-item label="输出控制台">
<el-checkbox v-model="config.zap.logInConsole"></el-checkbox>
</el-form-item>
<!-- Zap end -->
<!-- Redis start -->
<h2>Redis admin数据库配置</h2>
<el-form-item label="db">
<el-input v-model="config.redis.db"></el-input>
</el-form-item>
<el-form-item label="addr">
<el-input v-model="config.redis.addr"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.redis.password"></el-input>
</el-form-item>
<!-- Redis end -->
<!-- Email start -->
<h2>邮箱配置</h2>
<el-form-item label="接收者邮箱">
<el-input v-model="config.email.to" placeholder="可多个,以逗号分隔"></el-input>
</el-form-item>
<el-form-item label="端口">
<el-input v-model.number="config.email.port"></el-input>
</el-form-item>
<el-form-item label="发送者邮箱">
<el-input v-model="config.email.from"></el-input>
</el-form-item>
<el-form-item label="host">
<el-input v-model="config.email.host"></el-input>
</el-form-item>
<el-form-item label="是否为ssl">
<el-checkbox v-model="config.email.isSSL"></el-checkbox>
</el-form-item>
<el-form-item label="secret">
<el-input v-model="config.email.secret"></el-input>
</el-form-item>
<el-form-item label="测试邮件">
<el-button @click="email">测试邮件</el-button>
</el-form-item>
<!-- Email end -->
<!-- Casbin start -->
<h2>casbin配置</h2>
<el-form-item label="模型地址">
<el-input v-model="config.casbin.modelPath"></el-input>
</el-form-item>
<!-- Casbin end -->
<!-- Captcha start -->
<h2>验证码配置</h2>
<el-form-item label="keyLong">
<el-input v-model.number="config.captcha.keyLong"></el-input>
</el-form-item>
<el-form-item label="imgWidth">
<el-input v-model.number="config.captcha.imgWidth"></el-input>
</el-form-item>
<el-form-item label="imgHeight">
<el-input v-model.number="config.captcha.imgHeight"></el-input>
</el-form-item>
<!-- Captcha end -->
<!-- dbType start -->
<template v-if="config.system.dbType == 'mysql'">
<h2>mysql admin数据库配置</h2>
<el-form-item label="username">
......@@ -51,6 +155,45 @@
<el-checkbox v-model="config.mysql.logMode"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlite'">
<h2>sqlite admin数据库配置</h2>
<el-form-item label="path">
<el-input v-model="config.mysql.path"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.mysql.logger"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlserver'">
<h2>sqlserver admin数据库配置</h2>
<el-form-item label="username">
<el-input v-model="config.sqlserver.username"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.sqlserver.password"></el-input>
</el-form-item>
<el-form-item label="path">
<el-input v-model="config.sqlserver.path"></el-input>
</el-form-item>
<el-form-item label="dbname">
<el-input v-model="config.sqlserver.dbname"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.sqlserver.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.sqlserver.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.sqlserver.logger"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'postgresql'">
<h2>postgresql admin数据库配置</h2>
<el-form-item label="username">
......@@ -81,132 +224,41 @@
<el-checkbox v-model="config.mysql.preferSimpleProtocol"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlite'">
<h2>sqlite admin数据库配置</h2>
<el-form-item label="path">
<el-input v-model="config.mysql.path"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.mysql.logger"></el-checkbox>
<!-- dbType end -->
<!-- ossType start -->
<template v-if="config.system.ossType == 'local'">
<h2>本地上传配置</h2>
<el-form-item label="本地文件路径">
<el-input v-model="config.local.path"></el-input>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlserver'">
<h2>sqlserver admin数据库配置</h2>
<el-form-item label="username">
<el-input v-model="config.sqlserver.username"></el-input>
<template v-if="config.system.ossType == 'qiniu'">
<h2>qiniu上传配置</h2>
<el-form-item label="存储区域">
<el-input v-model="config.qiniu.zone"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.sqlserver.password"></el-input>
<el-form-item label="空间名称">
<el-input v-model="config.qiniu.bucket"></el-input>
</el-form-item>
<el-form-item label="path">
<el-input v-model="config.sqlserver.path"></el-input>
<el-form-item label="CDN加速域名">
<el-input v-model="config.qiniu.imgPath"></el-input>
</el-form-item>
<el-form-item label="dbname">
<el-input v-model="config.sqlserver.dbname"></el-input>
<el-form-item label="是否使用https">
<el-checkbox v-model="config.qiniu.imgPath">开启</el-checkbox>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.sqlserver.maxIdleConns"></el-input>
<el-form-item label="accessKey">
<el-input v-model="config.qiniu.accessKey"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.sqlserver.maxOpenConns"></el-input>
<el-form-item label="secretKey">
<el-input v-model="config.qiniu.secretKey"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.sqlserver.logger"></el-checkbox>
<el-form-item label="上传是否使用CDN上传加速">
<el-checkbox v-model="config.qiniu.useCdnDomains">开启</el-checkbox>
</el-form-item>
</template>
<h2>Redis admin数据库配置</h2>
<el-form-item label="addr">
<el-input v-model="config.redis.addr"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.redis.password"></el-input>
</el-form-item>
<el-form-item label="db">
<el-input v-model="config.redis.db"></el-input>
</el-form-item>
<h2>上传配置</h2>
<el-form-item label="本地或七牛云">
<el-checkbox v-model="config.localUpload.local">本地</el-checkbox>
</el-form-item>
<el-form-item label="本地文件路径">
<el-input v-model="config.localUpload.filePath"></el-input>
</el-form-item>
<h2>七牛密钥配置</h2>
<el-form-item label="accessKey">
<el-input v-model="config.qiniu.accessKey"></el-input>
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config.qiniu.secretKey"></el-input>
</el-form-item>
<h2>验证码配置</h2>
<el-form-item label="keyLong">
<el-input v-model.number="config.captcha.keyLong"></el-input>
</el-form-item>
<el-form-item label="imgWidth">
<el-input v-model.number="config.captcha.imgWidth"></el-input>
</el-form-item>
<el-form-item label="imgHeight">
<el-input v-model.number="config.captcha.imgHeight"></el-input>
</el-form-item>
<h2>日志配置</h2>
<el-form-item label="level">
<el-input v-model.number="config.zap.level"></el-input>
</el-form-item>
<el-form-item label="format">
<el-input v-model="config.zap.format"></el-input>
</el-form-item>
<el-form-item label="prefix">
<el-input v-model="config.zap.prefix"></el-input>
</el-form-item>
<el-form-item label="director">
<el-input v-model="config.zap.director"></el-input>
</el-form-item>
<el-form-item label="link-name">
<el-input v-model="config.zap.linkName"></el-input>
</el-form-item>
<el-form-item label="encode-level">
<el-input v-model="config.zap.encodeLevel"></el-input>
</el-form-item>
<el-form-item label="stacktrace-key">
<el-input v-model="config.zap.stacktraceKey"></el-input>
</el-form-item>
<el-form-item label="show-line">
<el-checkbox v-model="config.zap.showLine"></el-checkbox>
</el-form-item>
<el-form-item label="log-in-console">
<el-checkbox v-model="config.zap.logInConsole"></el-checkbox>
</el-form-item>
<h2>邮箱配置</h2>
<el-form-item label="emailFrom">
<el-input v-model="config.email.emailFrom"></el-input>
</el-form-item>
<el-form-item label="emailNickName">
<el-input v-model="config.email.emailNickName"></el-input>
</el-form-item>
<el-form-item label="emailSecret">
<el-input v-model="config.email.emailSecret"></el-input>
</el-form-item>
<el-form-item label="emailTo">
<el-input v-model="config.email.emailTo" placeholder="可多个,以逗号分隔"></el-input>
</el-form-item>
<el-form-item label="emailHost">
<el-input v-model="config.email.emailHost"></el-input>
</el-form-item>
<el-form-item label="emailPort">
<el-input v-model.number="config.email.emailPort"></el-input>
</el-form-item>
<el-form-item label="emailIsSSL">
<el-checkbox v-model="config.email.emailIsSSL"></el-checkbox>
</el-form-item>
<el-form-item label="测试邮件">
<el-button @click="email">测试邮件</el-button>
</el-form-item>
<!-- ossType end -->
<el-form-item>
<el-button @click="update" type="primary">立即更新</el-button>
<el-button @click="reload" type="primary">重启服务(开发中)</el-button>
......@@ -231,8 +283,8 @@ export default {
redis: {},
qiniu: {},
captcha: {},
log: {},
localUpload: {},
zap: {},
local: {},
email: {}
}
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册