Browse Source

Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into develop

main
pixel 4 years ago
parent
commit
804e28d2e9
  1. 1
      server/config.yaml
  2. 1
      server/config/gorm.go
  3. 6
      server/initialize/gorm.go
  4. 150
      server/initialize/logger.go
  5. 1
      web/src/App.vue
  6. 3
      web/src/style/basics.scss
  7. 16
      web/src/style/main.scss
  8. 89
      web/src/style/mobile.scss
  9. 83
      web/src/view/dashboard/index.vue
  10. 34
      web/src/view/example/form/form.vue
  11. 13
      web/src/view/layout/index.vue

1
server/config.yaml

@ -60,6 +60,7 @@ mysql:
max-idle-conns: 10 max-idle-conns: 10
max-open-conns: 100 max-open-conns: 100
log-mode: false log-mode: false
log-zap: false
# local configuration # local configuration
local: local:

1
server/config/gorm.go

@ -9,4 +9,5 @@ type Mysql struct {
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
} }

6
server/initialize/gorm.go

@ -73,6 +73,12 @@ func GormMysql() *gorm.DB {
// gormConfig 根据配置决定是否开启日志 // gormConfig 根据配置决定是否开启日志
func gormConfig(mod bool) *gorm.Config { func gormConfig(mod bool) *gorm.Config {
if global.GVA_CONFIG.Mysql.LogZap {
return &gorm.Config{
Logger: Default.LogMode(logger.Info),
DisableForeignKeyConstraintWhenMigrating: true,
}
}
if mod { if mod {
return &gorm.Config{ return &gorm.Config{
Logger: logger.Default.LogMode(logger.Info), Logger: logger.Default.LogMode(logger.Info),

150
server/initialize/logger.go

@ -0,0 +1,150 @@
package initialize
import (
"context"
"fmt"
"gin-vue-admin/global"
"go.uber.org/zap"
"gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"io/ioutil"
"log"
"os"
"time"
)
var (
Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), GormConfig{})
Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), GormConfig{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
Colorful: true,
})
Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
)
type traceRecorder struct {
logger.Interface
BeginAt time.Time
SQL string
RowsAffected int64
Err error
}
func New(writer Writer, config GormConfig) logger.Interface {
var (
infoStr = "%s\n[info] "
warnStr = "%s\n[warn] "
errStr = "%s\n[error] "
traceStr = "%s\n[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
)
if config.Colorful {
infoStr = logger.Green + "%s\n" + logger.Reset + logger.Green + "[info] " + logger.Reset
warnStr = logger.BlueBold + "%s\n" + logger.Reset + logger.Magenta + "[warn] " + logger.Reset
errStr = logger.Magenta + "%s\n" + logger.Reset + logger.Red + "[error] " + logger.Reset
traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s" + logger.Reset
traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
}
return &GormLogger{
Writer: writer,
GormConfig: config,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
// Writer log writer interface
type Writer interface {
Printf(string, ...interface{})
}
type GormConfig struct {
SlowThreshold time.Duration
Colorful bool
LogLevel logger.LogLevel
}
type GormLogger struct {
Writer
GormConfig
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
}
func (g *GormLogger) LogMode(level logger.LogLevel) logger.Interface {
newLogger := *g
newLogger.LogLevel = level
return &newLogger
}
func (g *GormLogger) Info(ctx context.Context, message string, data ...interface{}) {
if g.LogLevel >= logger.Info {
g.Printf(g.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
func (g *GormLogger) Warn(ctx context.Context, message string, data ...interface{}) {
if g.LogLevel >= logger.Warn {
g.Printf(g.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
func (g *GormLogger) Error(ctx context.Context, message string, data ...interface{}) {
if g.LogLevel >= logger.Error {
g.Printf(g.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
func (g *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
if g.LogLevel > 0 {
elapsed := time.Since(begin)
switch {
case err != nil && g.LogLevel >= logger.Error:
sql, rows := fc()
if rows == -1 {
g.Printf(g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
g.Printf(g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case elapsed > g.SlowThreshold && g.SlowThreshold != 0 && g.LogLevel >= logger.Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", g.SlowThreshold)
if rows == -1 {
g.Printf(g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
g.Printf(g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case g.LogLevel >= logger.Info:
sql, rows := fc()
if rows == -1 {
g.Printf(g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
g.Printf(g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
}
}
}
func (g *GormLogger) Printf(message string, data ...interface{}) {
switch len(data) {
case 0:
global.GVA_LOG.Info(message)
case 1:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]))
case 2:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]))
case 3:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]))
case 4:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]), zap.Any("sql", data[3]))
}
}

1
web/src/App.vue

@ -15,6 +15,7 @@ export default {
// //
@import '@/style/main.scss'; @import '@/style/main.scss';
@import '@/style/base.scss'; @import '@/style/base.scss';
@import '@/style/mobile.scss';
#app { #app {
background: #eee; background: #eee;
height: 100vh; height: 100vh;

3
web/src/style/basics.scss

@ -32,3 +32,6 @@ $color-table-tbody:#595959;
$color-table-thead:#262626; $color-table-thead:#262626;
// dashboard // dashboard
$height-car:68px; $height-car:68px;
// mobile
$padding-xs: 5px;
$margin-xs: 5px;

16
web/src/style/main.scss

@ -1204,6 +1204,14 @@ $mainHight: 100vh;
top: 0; top: 0;
box-sizing: border-box; box-sizing: border-box;
z-index: 999; z-index: 999;
>.el-row{
padding: 0;
.el-col-lg-14{
height: 60px;
}
}
} }
@ -1387,14 +1395,14 @@ $mainHight: 100vh;
.car-left { .car-left {
height: $height-car; height: $height-car;
width: 70%;
float: left;
// width: 70%;
// float: left;
} }
.car-right { .car-right {
height: $height-car; height: $height-car;
width: 29%;
float: left;
// width: 29%;
// float: left;
.flow, .flow,
.user-number, .user-number,

89
web/src/style/mobile.scss

@ -0,0 +1,89 @@
@import '@/style/basics.scss';
@media screen and (min-width: 320px)and (max-width: 750px){
.el-header{
padding: 0 $padding-xs;
}
.layout-cont {
.main-cont{
.breadcrumb{
padding: 0 $padding-xs;
}
}
}
.layout-cont{
.right-box{
margin-right: $margin-xs;
}
}
.search-component{
width: 30px;
}
.screenfull{
width: 26px;
text-align: center;
}
.el-main{
.admin-box{
margin-left: 0;
margin-right: 0;
}
.big.admin-box{
padding: 0 0 15px 0;
}
.big {
.bottom {
.chart-player{
height: auto!important;
margin-bottom: 15px;
}
.todoapp{
background-color: #fff;
padding-bottom: 10px;
}
}
}
}
.card .car-left,
.card .car-right{
width: 100%;
height: 100%;
}
.card{
padding-left: $padding-xs;
padding-right: $padding-xs;
}
.card {
.text{
width: 100%;
h4{
white-space: break-spaces;
}
}
}
.shadow{
margin-left: 5px;
margin-right: 5px;
.grid-content{
margin-bottom: 10px;
padding: 0;
}
}
.el-dialog{
width: 90%;
}
.el-transfer{
.el-transfer-panel{
width: 40%;
display: inline-block;
}
.el-transfer__buttons{
padding: 0 5px;
display: inline-block;
}
}
}

83
web/src/view/dashboard/index.vue

@ -1,44 +1,72 @@
<template> <template>
<div class="big"> <div class="big">
<el-row>
<div class="card"> <div class="card">
<el-col :xs="24" :lg="16" :md="16" >
<div class="car-left"> <div class="car-left">
<el-row>
<div> <div>
<span class="card-img"> <img :src="userInfo.headerImg" alt="" > </span>
<div class="text"><h4>早安管理员 请开始您一天的工作吧</h4>
<el-col :xs="4" :md="3" :lg="3">
<span class="card-img">
<img :src="userInfo.headerImg" alt="" />
</span>
</el-col>
<el-col :xs="20" :lg="12" :md="12">
<div class="text">
<h4>早安管理员 请开始您一天的工作吧</h4>
<p class="tips-text"> <p class="tips-text">
<i class="el-icon-sunny el-icon"></i> <i class="el-icon-sunny el-icon"></i>
<span>今日晴0 - 10天气寒冷注意添加衣物</span> <span>今日晴0 - 10天气寒冷注意添加衣物</span>
</p> </p>
</div> </div>
</el-col>
</div> </div>
</el-row>
</div> </div>
</el-col>
<el-col :xs="24" :lg='8' :md="8">
<div class="car-right"> <div class="car-right">
<el-row> <el-row>
<el-col :span="8"><div class="car-item">
<el-col :span="8"
><div class="car-item">
<span class="flow"><i class="el-icon-s-grid"></i></span> <span class="flow"><i class="el-icon-s-grid"></i></span>
<span>今日流量 </span> <span>今日流量 </span>
<b>13260</b> <b>13260</b>
</div></el-col>
<el-col :span="8"><div class="car-item">
</div></el-col
>
<el-col :span="8"
><div class="car-item">
<span class="user-number"> <span class="user-number">
<i class="el-icon-s-custom"></i> <i class="el-icon-s-custom"></i>
</span> </span>
<span>总用户 </span> <span>总用户 </span>
<b>48286</b> <b>48286</b>
</div></el-col>
<el-col :span="8"><div class="car-item ">
</div></el-col
>
<el-col :span="8"
><div class="car-item">
<span class="feedback"> <span class="feedback">
<i class="el-icon-star-on"></i> <i class="el-icon-star-on"></i>
</span> </span>
<span>好评率 </span> <span>好评率 </span>
<b>98%</b> <b>98%</b>
</div></el-col>
</div></el-col
>
</el-row> </el-row>
</div> </div>
</el-col>
</div> </div>
</el-row>
<div class="shadow"> <div class="shadow">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4" v-for="(card,key) in toolCards" :key="key" @click.native="toTarget(card.name)">
<el-col
:span="4"
v-for="(card, key) in toolCards"
:key="key"
@click.native="toTarget(card.name)"
:xs="8"
>
<el-card shadow="hover" class="grid-content"> <el-card shadow="hover" class="grid-content">
<i :class="card.icon" :style="{ color: card.color }"></i> <i :class="card.icon" :style="{ color: card.color }"></i>
<p>{{ card.label }}</p> <p>{{ card.label }}</p>
@ -61,15 +89,14 @@
</el-row> </el-row>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import musicPlayer from "./component/musicPlayer"
import TodoList from "./component/todoList"
import { mapGetters } from 'vuex'
import musicPlayer from "./component/musicPlayer";
import TodoList from "./component/todoList";
import { mapGetters } from "vuex";
export default { export default {
name: 'Dashboard',
name: "Dashboard",
data() { data() {
return { return {
toolCards: [ toolCards: [
@ -77,44 +104,43 @@ export default {
label: "用户管理", label: "用户管理",
icon: "el-icon el-icon-monitor", icon: "el-icon el-icon-monitor",
name: "user", name: "user",
color:"#ff9c6e"
color: "#ff9c6e",
}, },
{ {
label: "角色管理", label: "角色管理",
icon: "el-icon el-icon-setting", icon: "el-icon el-icon-setting",
name: "authority", name: "authority",
color:"#69c0ff"
color: "#69c0ff",
}, },
{ {
label: "菜单管理", label: "菜单管理",
icon: "el-icon el-icon-menu", icon: "el-icon el-icon-menu",
name: "menu", name: "menu",
color:"#b37feb"
color: "#b37feb",
}, },
{ {
label: "代码生成器", label: "代码生成器",
icon: "el-icon el-icon-cpu", icon: "el-icon el-icon-cpu",
name: "autoCode", name: "autoCode",
color:"#ffd666"
color: "#ffd666",
}, },
{ {
label: "表单生成器", label: "表单生成器",
icon: "el-icon el-icon-document-checked", icon: "el-icon el-icon-document-checked",
name: "formCreate", name: "formCreate",
color:"#ff85c0"
color: "#ff85c0",
}, },
{ {
label: "关于我们", label: "关于我们",
icon: "el-icon el-icon-user", icon: "el-icon el-icon-user",
name: "about", name: "about",
color:"#5cdbd3"
}
]
}
color: "#5cdbd3",
},
],
};
}, },
computed: { computed: {
...mapGetters('user', ['userInfo'])
...mapGetters("user", ["userInfo"]),
}, },
components: { components: {
musicPlayer, // musicPlayer, //
@ -125,10 +151,10 @@ export default {
}, },
methods: { methods: {
toTarget(name) { toTarget(name) {
this.$router.push({name})
}
this.$router.push({ name });
}, },
}
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -175,5 +201,4 @@ export default {
} }
} }
} }
</style> </style>

34
web/src/view/example/form/form.vue

@ -2,12 +2,12 @@
<div> <div>
<el-form :model="form" label-width="80px" ref="form"> <el-form :model="form" label-width="80px" ref="form">
<el-row> <el-row>
<el-col :span="3"><label for="">活动名称</label></el-col>
<el-col :span="10"><el-input v-model="form.name"></el-input></el-col>
<el-col :span="3" :xs="6"><label for="">活动名称</label></el-col>
<el-col :span="10" :xs="14"><el-input v-model="form.name"></el-input></el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">活动区域</label></el-col>
<el-col :span="10">
<el-col :span="3" :xs="6"><label for="">活动区域</label></el-col>
<el-col :span="10" :xs="14">
<el-select placeholder="请选择活动区域" v-model="form.region"> <el-select placeholder="请选择活动区域" v-model="form.region">
<el-option label="上海" value="shanghai"></el-option> <el-option label="上海" value="shanghai"></el-option>
<el-option label="北京" value="beijing"></el-option> <el-option label="北京" value="beijing"></el-option>
@ -15,8 +15,8 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">活动时间</label></el-col>
<el-col :span="10">
<el-col :span="3" :xs="6"><label for="">活动时间</label></el-col>
<el-col :span="10" :xs="18">
<el-col :span="11"> <el-col :span="11">
<el-date-picker placeholder="选择日期" style="width: 100%;" type="date" v-model="form.date1"></el-date-picker> <el-date-picker placeholder="选择日期" style="width: 100%;" type="date" v-model="form.date1"></el-date-picker>
</el-col> </el-col>
@ -27,12 +27,12 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">即时配送</label></el-col>
<el-col :span="10"><el-switch v-model="form.delivery"></el-switch></el-col>
<el-col :span="3" :xs="6"><label for="">即时配送</label></el-col>
<el-col :span="10" :xs="14"><el-switch v-model="form.delivery"></el-switch></el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">活动性质</label></el-col>
<el-col :span="10">
<el-col :span="3" :xs="6"><label for="">活动性质</label></el-col>
<el-col :span="10" :xs="14">
<el-checkbox-group v-model="form.type"> <el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox> <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox> <el-checkbox label="地推活动" name="type"></el-checkbox>
@ -42,8 +42,8 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">特殊资源</label></el-col>
<el-col :span="10">
<el-col :span="3" :xs="6"><label for="">特殊资源</label></el-col>
<el-col :span="10" :xs="14">
<el-radio-group v-model="form.resource"> <el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio> <el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio> <el-radio label="线下场地免费"></el-radio>
@ -51,12 +51,12 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">活动形式</label></el-col>
<el-col :span="10"><el-input type="textarea" v-model="form.desc"></el-input></el-col>
<el-col :span="3" :xs="6"><label for="">活动形式</label></el-col>
<el-col :span="10" :xs="14"><el-input type="textarea" v-model="form.desc"></el-input></el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">穿梭框</label></el-col>
<el-col :span="20">
<el-col :span="3" :xs="6"><label for="">穿梭框</label></el-col>
<el-col :span="20" :xs="24">
<el-transfer <el-transfer
:data="data" :data="data"
:filter-method="filterMethod" :filter-method="filterMethod"
@ -67,7 +67,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="3"><label for="">活动时间</label></el-col>
<el-col :span="3" :xs="6"><label for="">活动时间</label></el-col>
<el-col :span="10"><el-input v-model="form.name"></el-input></el-col> <el-col :span="10"><el-input v-model="form.name"></el-input></el-col>
</el-row> </el-row>
<el-row type="flex" justify="center"> <el-row type="flex" justify="center">

13
web/src/view/layout/index.vue

@ -16,17 +16,24 @@
:style="{width: `calc(100% - ${isMobile?'0px':isCollapse?'54px':'220px'})`}" :style="{width: `calc(100% - ${isMobile?'0px':isCollapse?'54px':'220px'})`}"
class="topfix" class="topfix"
> >
<el-row>
<!-- :xs="8" :sm="6" :md="4" :lg="3" :xl="1" -->
<el-header class="header-cont"> <el-header class="header-cont">
<el-col :xs="2" :lg="1" :md="1" :sm="1" :xl="1">
<div @click="totalCollapse" class="menu-total"> <div @click="totalCollapse" class="menu-total">
<i class="el-icon-s-unfold" v-if="isCollapse"></i> <i class="el-icon-s-unfold" v-if="isCollapse"></i>
<i class="el-icon-s-fold" v-else></i> <i class="el-icon-s-fold" v-else></i>
</div> </div>
</el-col>
<el-col :xs="10" :lg="14" :md='14' :sm="9" :xl="14">
<el-breadcrumb class="breadcrumb" separator-class="el-icon-arrow-right"> <el-breadcrumb class="breadcrumb" separator-class="el-icon-arrow-right">
<el-breadcrumb-item <el-breadcrumb-item
:key="item.path" :key="item.path"
v-for="item in matched.slice(1,matched.length)" v-for="item in matched.slice(1,matched.length)"
>{{item.meta.title}}</el-breadcrumb-item> >{{item.meta.title}}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</el-col>
<el-col :xs="12" :lg="9" :md="9" :sm="14" :xl="9">
<div class="fl-right right-box"> <div class="fl-right right-box">
<Search /> <Search />
<Screenfull class="screenfull"></Screenfull> <Screenfull class="screenfull"></Screenfull>
@ -48,7 +55,10 @@
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
</el-col>
</el-header> </el-header>
</el-row>
<!-- 当前面包屑用路由自动生成可根据需求修改 --> <!-- 当前面包屑用路由自动生成可根据需求修改 -->
<!-- <!--
:to="{ path: item.path }" 暂时注释不用--> :to="{ path: item.path }" 暂时注释不用-->
@ -172,8 +182,9 @@ export default {
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@import '@/style/mobile.scss';
// $headerHigh: 52px; // $headerHigh: 52px;
// $mainHight: 100vh; // $mainHight: 100vh;
// .dropdown-group { // .dropdown-group {

Loading…
Cancel
Save