完成基本的创建使用功能

This commit is contained in:
2024-09-11 20:19:47 +08:00
parent 28a84ad4d7
commit 951572a1f5
22 changed files with 783 additions and 31 deletions
+1
View File
@@ -3,3 +3,4 @@
/work_cation.exe
/work_cation.iml
/work_cation_0.1.2.zip
/data.db
+27
View File
@@ -0,0 +1,27 @@
package cfg
import (
"fmt"
"gopkg.in/ini.v1"
)
type Config struct {
DbPath string `ini:"dbPath"`
}
var T = Config{
DbPath: "./data.db",
}
func init() {
cfg, err := ini.Load("conf.ini")
if err != nil {
fmt.Println("读取配置错误1", err)
return
}
err = cfg.MapTo(&T)
if err != nil {
fmt.Println("读取配置错误2", err)
return
}
}
+30
View File
@@ -0,0 +1,30 @@
package global
import (
"gorm.io/gorm"
"work_cation/cfg"
"work_cation/models"
"work_cation/models/repo"
"work_cation/pkg/gormx"
)
var DB *gorm.DB
func InitDB() {
var err error
DB, err = gormx.New(gormx.Config{DSN: cfg.T.DbPath, Type: "sqlite3"})
if err != nil {
panic(err)
}
err = DB.AutoMigrate(
&models.ErlangCards{},
&models.ErlangCardCollections{},
&models.History{},
&models.Users{},
&models.UserFollows{},
)
if err != nil {
panic(err)
}
repo.UserRepo.GetUserInfo(DB)
}
+19 -3
View File
@@ -2,12 +2,21 @@ module work_cation
go 1.21.1
require fyne.io/fyne/v2 v2.5.1
require (
fyne.io/fyne/v2 v2.5.1
github.com/atotto/clipboard v0.1.4
github.com/google/uuid v1.6.0
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.8.1
gorm.io/driver/mysql v1.5.7
gorm.io/driver/sqlite v1.5.6
gorm.io/gorm v1.25.12
)
require (
fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
@@ -16,14 +25,20 @@ require (
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/go-text/render v0.1.1-0.20240418202334-dd62631dae9b // indirect
github.com/go-text/typesetting v0.1.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/lestrrat-go/strftime v1.1.0 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rymdport/portal v0.2.6 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
@@ -35,5 +50,6 @@ require (
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+31
View File
@@ -96,6 +96,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-text/render v0.1.1-0.20240418202334-dd62631dae9b h1:daoFn+Aw8EIQZO9kYWwHL01FqwwpCl2nTeVEYbsgRHk=
github.com/go-text/render v0.1.1-0.20240418202334-dd62631dae9b/go.mod h1:jqEuNMenrmj6QRnkdpeaP0oKGFLDNhDkVKwGjsWWYU4=
github.com/go-text/typesetting v0.1.0 h1:vioSaLPYcHwPEPLT7gsjCGDCoYSbljxoHJzMnKwVvHw=
@@ -203,6 +205,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 h1:Po+wkNdMmN+Zj1tDsJQy7mJlPlwGNQd9JZoPjObagf8=
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49/go.mod h1:YiutDnxPRLk5DLUFj6Rw4pRBBURZY07GFr54NdV9mQg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@@ -216,9 +224,17 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg=
github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -239,6 +255,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
@@ -247,6 +264,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -258,6 +277,8 @@ github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxr
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
@@ -426,6 +447,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -639,6 +661,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -648,6 +672,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+104 -6
View File
@@ -1,20 +1,28 @@
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"work_cation/assets"
"work_cation/global"
"work_cation/version"
"work_cation/views"
)
const preferenceCurrentTutorial = "currentTutorial"
func main() {
global.InitDB()
a := app.NewWithID("io.fyne.workCation")
a.Settings().SetTheme(&assets.MyTheme{})
a.SetIcon(assets.LogoDataSR)
w := a.NewWindow("主页 " + version.NowVersion)
w.Resize(fyne.NewSize(380, 300))
w.Resize(fyne.NewSize(800, 550))
w.SetContent(mainView(w))
w.CenterOnScreen()
w.SetMaster()
@@ -23,11 +31,101 @@ func main() {
a.Run()
}
// 主界面
func mainView(w fyne.Window) fyne.CanvasObject {
return container.NewBorder(nil, nil, nil, nil,
container.NewVBox(
views.ErlangCardView(w, nil),
views.ErlangCardView(w, nil),
),
var (
content = container.NewMax()
a = fyne.CurrentApp()
topWindow = w
//title = widget.NewLabel("Component name")
//intro = widget.NewLabel("An introduction would probably go\nhere, as well as a")
)
setTutorial := func(t views.Tutorial) {
if fyne.CurrentDevice().IsMobile() {
child := a.NewWindow(t.Title)
topWindow = child
child.SetContent(t.View(topWindow))
child.Show()
child.SetOnClosed(func() {
topWindow = w
})
return
}
//title.SetText(t.Title)
//intro.SetText(t.Intro)
content.Objects = []fyne.CanvasObject{t.View(w)}
content.Refresh()
}
tutorial := container.NewBorder(nil, nil, nil, nil, content)
//container.NewVBox(title, widget.NewSeparator(), intro)
split := container.NewHSplit(makeNav(setTutorial, true), tutorial)
split.Offset = 0.2
return container.NewBorder(nil, nil, nil, nil, split)
}
// 左侧菜单
func makeNav(setTutorial func(tutorial views.Tutorial), loadPrevious bool) fyne.CanvasObject {
a := fyne.CurrentApp()
tree := &widget.Tree{
ChildUIDs: func(uid string) []string {
return views.TutorialIndex[uid]
},
IsBranch: func(uid string) bool {
children, ok := views.TutorialIndex[uid]
return ok && len(children) > 0
},
CreateNode: func(branch bool) fyne.CanvasObject {
return widget.NewLabel("Collection Widgets")
},
UpdateNode: func(uid string, branch bool, obj fyne.CanvasObject) {
t, ok := views.Tutorials[uid]
if !ok {
fyne.LogError("Missing tutorial panel: "+uid, nil)
return
}
obj.(*widget.Label).SetText(t.Title)
if unsupportedTutorial(t) {
obj.(*widget.Label).TextStyle = fyne.TextStyle{Italic: true}
} else {
obj.(*widget.Label).TextStyle = fyne.TextStyle{}
}
},
OnSelected: func(uid string) {
if t, ok := views.Tutorials[uid]; ok {
if unsupportedTutorial(t) {
return
}
a.Preferences().SetString(preferenceCurrentTutorial, uid)
fmt.Println(t)
setTutorial(t)
}
},
}
if loadPrevious {
currentPref := a.Preferences().StringWithFallback(preferenceCurrentTutorial, "welcome")
tree.Select(currentPref)
}
//themes := container.NewGridWithColumns(2,
// widget.NewButton("Dark", func() {
// a.Settings().SetTheme(theme.DarkTheme())
// }),
// widget.NewButton("Light", func() {
// a.Settings().SetTheme(theme.LightTheme())
// }),
//)
return container.NewBorder(nil, nil, nil, nil, tree)
}
func unsupportedTutorial(t views.Tutorial) bool {
return !t.SupportWeb && fyne.CurrentDevice().IsBrowser()
}
+15 -13
View File
@@ -1,17 +1,19 @@
package models
type ErlangCards struct {
UUID string `json:"uuid"` // id ip加时间戳生成
UserIp string `json:"user_ip"` // 用户ip
Title string `json:"title"` // 标题
Text string `json:"text"` // 内容
Covers []string `json:"covers"` // 封面
Template string `json:"template"` // 模版
VarName []string `json:"var_name"` // 变量
VarContent []string `json:"var_content"` // 变量内容
IsShowOut bool `json:"is_show_out"` // 是否展示
import "work_cation/pkg/gormx"
Number string `json:"number"` // 数量
Goods string `json:"goods"` // 点赞
Collection string `json:"collection"` // 收藏
type ErlangCards struct {
UUID string `json:"uuid"` // id ip加时间戳生成
UserIp string `json:"user_ip"` // 用户ip
Title string `json:"title"` // 标题
Text string `json:"text"` // 内容
Covers gormx.ListString `json:"covers"` // 封面
Template string `json:"template"` // 模版
VarName gormx.ListString `json:"var_name"` // 变量
VarContent gormx.ListString `json:"var_content"` // 变量内容
IsShowOut bool `json:"is_show_out"` // 是否展示
Number int `json:"number"` // 数量
Goods int `json:"goods"` // 点赞
Collection int `json:"collection"` // 收藏
}
+4 -2
View File
@@ -1,6 +1,8 @@
package models
import "work_cation/pkg/gormx"
type History struct {
UUID string `json:"uuid"`
Vars []string `json:"vars"`
UUID string `json:"uuid"`
Vars gormx.ListString `json:"vars"`
}
+20
View File
@@ -0,0 +1,20 @@
package repo
import (
"gorm.io/gorm"
"work_cation/models"
)
type ErlangCard struct{}
var ErlangCardRepo *ErlangCard
func (*ErlangCard) FindAll(db *gorm.DB) []models.ErlangCards {
var cards []models.ErlangCards
db.Find(&cards)
return cards
}
func (*ErlangCard) Create(db *gorm.DB, erlangCard *models.ErlangCards) error {
return db.Create(erlangCard).Error
}
+35
View File
@@ -0,0 +1,35 @@
package repo
import (
"gorm.io/gorm"
"os/user"
"work_cation/models"
"work_cation/pkg/utils"
)
type User struct{}
var UserRepo *User
func (*User) GetUserInfo(db *gorm.DB) *models.Users {
var users models.Users
db.Find(&users)
ip := utils.Get192Ip()
if users.Ip != ip {
current, err := user.Current()
if err != nil {
current = &user.User{Name: ip}
}
users = models.Users{
Ip: ip,
Name: current.Username,
Avatar: "",
Cover: "",
Email: "",
Phone: "",
Address: "友嘉",
}
db.Create(&users)
}
return &users
}
+1 -1
View File
@@ -1,7 +1,7 @@
package models
type Users struct {
Ip string `json:"ip"`
Ip string `gorm:"primarykey" json:"ip"`
Name string `json:"name"` // 昵称
Avatar string `json:"avatar"` // 头像
Cover string `json:"cover"` // 封面
+60
View File
@@ -0,0 +1,60 @@
package gormx
import (
"gorm.io/gorm"
)
type LimitHandler func(db *gorm.DB) *gorm.DB
func Finder[T any](model T, db *gorm.DB, objs ...LimitHandler) (int64, []T, error) {
for _, obj := range objs {
db = obj(db)
}
var models []T
err := db.Model(&model).Find(&models).Error
if err != nil {
return 0, nil, err
}
var sum int64
err = db.Model(&model).Count(&sum).Error
return sum, models, err
}
// FinderPage 分页查找
func FinderPage[T any](db *gorm.DB, page, limit int, objs ...LimitHandler) (int64, []T, error) {
return pageFinder[T](db, pageHandle(page, limit), objs...)
}
func pageFinder[T any](db *gorm.DB, limit LimitHandler, objs ...LimitHandler) (int64, []T, error) {
// 定义表
var model T
db = db.Model(&model)
for _, obj := range objs {
db = obj(db)
}
// 查找全部数量
var sum int64
if err := db.Model(&model).Count(&sum).Error; err != nil {
return 0, nil, err
}
// 分页查找
db = limit(db)
var models []T
if err := db.Find(&models).Error; err != nil {
return 0, nil, err
}
return sum, models, nil
}
func pageHandle(page, limit int) LimitHandler {
return func(db *gorm.DB) *gorm.DB {
// 用户输入起始位
var beginIndex int
if page < 0 {
beginIndex = -1
} else {
beginIndex = (page - 1) * limit
}
return db.Offset(beginIndex).Limit(limit)
}
}
+27
View File
@@ -0,0 +1,27 @@
package gormx
import (
"errors"
"gorm.io/driver/mysql"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Config struct {
Type string `ini:"type"`
DSN string `ini:"dsn"`
}
func New(cfg Config) (db *gorm.DB, err error) {
switch cfg.Type {
case "sqlite3":
// dsn := "exe.db"
db, err = gorm.Open(sqlite.Open(cfg.DSN), &gorm.Config{})
case "mysql":
// dsn := "userRepo:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err = gorm.Open(mysql.Open(cfg.DSN), &gorm.Config{})
default:
err = errors.New("mode not supported")
}
return
}
+108
View File
@@ -0,0 +1,108 @@
package gormx
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
)
type ListInt64 []int64
// Value 接口,Value 返回 json value any -> string
func (j ListInt64) Value() (driver.Value, error) {
return json.Marshal(j)
}
// Scan 接口,Scan 将 value 扫描至 Jsonb
func (j *ListInt64) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(bytes, j)
if err != nil {
return err
}
return nil
}
type ListUint []uint
// Value 接口,Value 返回 json value any -> string
func (j ListUint) Value() (driver.Value, error) {
return json.Marshal(j)
}
// Scan 接口,Scan 将 value 扫描至 Jsonb
func (j *ListUint) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(bytes, j)
if err != nil {
return err
}
return nil
}
type ListInt []int
// Value 接口,Value 返回 json value any -> string
func (j ListInt) Value() (driver.Value, error) {
return json.Marshal(j)
}
// Scan 接口,Scan 将 value 扫描至 Jsonb
func (j *ListInt) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(bytes, j)
if err != nil {
return err
}
return nil
}
type ListString []string
// Value 接口,Value 返回 json value any -> string
func (j ListString) Value() (driver.Value, error) {
return json.Marshal(j)
}
// Scan 接口,Scan 将 value 扫描至 Jsonb
func (j *ListString) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(bytes, j)
if err != nil {
return err
}
return nil
}
type MapString map[string]string
// Value 接口,Value 返回 json value any -> string
func (j MapString) Value() (driver.Value, error) {
return json.Marshal(j)
}
// Scan 接口,Scan 将 value 扫描至 Jsonb
func (j *MapString) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(bytes, j)
if err != nil {
return err
}
return nil
}
+54
View File
@@ -0,0 +1,54 @@
package logger
import (
"io"
"log"
"os"
"path/filepath"
"time"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
)
func Init() {
// 添加日志切割输出
var hook = NewLfsHook("glogs", time.Hour*12, 6)
logrus.AddHook(hook)
// 忽略控制台打印
logrus.SetOutput(io.Discard)
// 展示日志行数
logrus.SetReportCaller(true)
}
// NewLfsHook 日志钩子(日志拦截,并重定向)
func NewLfsHook(logName string, rotationTime time.Duration, leastDay uint) logrus.Hook {
_ = os.Mkdir(logName, os.ModeDir)
// 可设置按不同level创建不同的文件名,咱们把6中日志都写到同一个writer中
lfsHook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: NewWriter(filepath.Join(logName, "debug"), rotationTime, leastDay),
logrus.InfoLevel: NewWriter(filepath.Join(logName, "info"), rotationTime, leastDay),
logrus.WarnLevel: NewWriter(filepath.Join(logName, "warn"), rotationTime, leastDay),
logrus.ErrorLevel: NewWriter(filepath.Join(logName, "error"), rotationTime, leastDay),
logrus.FatalLevel: NewWriter(filepath.Join(logName, "fatal"), rotationTime, leastDay),
logrus.PanicLevel: NewWriter(filepath.Join(logName, "panic"), rotationTime, leastDay),
}, nil) //&logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}
return lfsHook
}
func NewWriter(logName string, rotationTime time.Duration, leastDay uint) io.Writer {
writer, err := rotatelogs.New(
// 1 日志文件名字
logName+".%Y-%m-%d_%H_%M", // _%S
// 2 日志周期(默认每86400秒/一天旋转一次)
rotatelogs.WithRotationTime(rotationTime),
// 3 清除历史 (WithMaxAge和WithRotationCount只能选其一)
//rotatelogs.WithMaxAge(time.Hour*24*7), //默认每7天清除下日志文件
rotatelogs.WithRotationCount(leastDay), //只保留最近的N个日志文件
)
if err != nil {
log.Panic(err)
}
return writer
}
+27
View File
@@ -0,0 +1,27 @@
package logger
import (
"fmt"
"runtime/debug"
"testing"
"time"
"github.com/sirupsen/logrus"
)
func TestLogger(t *testing.T) {
Init()
logrus.Infoln("asdadsasd")
time.Sleep(5 * time.Second)
logrus.Infoln(string(debug.Stack()))
logrus.WithFields(logrus.Fields{"RoleUid": "12313123123"}).Warn("asdasd")
}
func TestLogger2(t *testing.T) {
str := "goroutine 68 [running]:\\nruntime/debug.Stack()\\n\\tD:/work/environment/GO/src/runtime/debug/stack.go:24 +0x65\\ncolly_v2/pkg/zlib.Try.func1()\\n\\tE:/gopackage2/2023.10/colly_v2/pkg/zlib/try.go:12 "
fmt.Println(len([]byte(str)))
}
func TestLogger3(t *testing.T) {
fmt.Println(time.Now().Unix() - 259200)
}
+31
View File
@@ -0,0 +1,31 @@
package hash
import (
"crypto/md5"
"crypto/sha1"
"fmt"
)
// MD5 MD5哈希值
func MD5(b []byte) string {
h := md5.New()
_, _ = h.Write(b)
return fmt.Sprintf("%x", h.Sum(nil))
}
// MD5String MD5哈希值
func MD5String(s string) string {
return MD5([]byte(s))
}
// SHA1 SHA1哈希值
func SHA1(b []byte) string {
h := sha1.New()
_, _ = h.Write(b)
return fmt.Sprintf("%x", h.Sum(nil))
}
// SHA1String SHA1哈希值
func SHA1String(s string) string {
return SHA1([]byte(s))
}
-1
View File
@@ -18,7 +18,6 @@ func CreateUUID() string {
// 生成基于字符串的 UUID
key := fmt.Sprintln(Get192Ip(), time.Now().Format("2006-01-02_15-04-05"), uuidint)
uuidint++
fmt.Println("key:", key)
u1 := uuid.NewSHA1(uuid.Nil, []byte(key))
return u1.String()
}
+101
View File
@@ -0,0 +1,101 @@
package views
import (
"errors"
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
"regexp"
"work_cation/global"
"work_cation/models"
"work_cation/models/repo"
"work_cation/pkg/utils"
)
func CreateErlangCard(w fyne.Window) fyne.CanvasObject {
// user := repo.UserRepo.GetUserInfo(global.DB)
var erlangCard = models.ErlangCards{
UUID: utils.CreateUUID(),
UserIp: utils.Get192Ip(),
}
var items = []*widget.FormItem{
{Text: "名称", Widget: widget.NewEntry()},
{Text: "描述", Widget: widget.NewEntry()},
{Text: "封面", Widget: widget.NewEntry(), HintText: "暂未支持可不填"},
{Text: "是否默认展示", Widget: widget.NewEntry()},
{Text: "模版内容", Widget: widget.NewEntry()},
}
var items2 []*widget.FormItem
form2 := &widget.Form{
Items: items2,
SubmitText: "保存创建",
OnSubmit: func() {
for _, item := range items {
switch item.Text {
case "名称":
erlangCard.Title = item.Widget.(*widget.Entry).Text
case "描述":
erlangCard.Text = item.Widget.(*widget.Entry).Text
case "封面":
erlangCard.Covers = []string{item.Widget.(*widget.Entry).Text}
case "是否默认展示":
erlangCard.IsShowOut = item.Widget.(*widget.Entry).Text == "1"
case "模版内容":
erlangCard.Template = item.Widget.(*widget.Entry).Text
default:
}
}
if countVarOccurrences(erlangCard.Template) != len(items2) {
dialog.ShowError(errors.New("变量名数量异常"), w)
return
}
for _, item2 := range items2 {
fmt.Println("key:", item2.Text, "value:", item2.Widget.(*widget.Entry).Text)
erlangCard.VarName = append(erlangCard.VarName, item2.Widget.(*widget.Entry).Text)
}
err := repo.ErlangCardRepo.Create(global.DB, &erlangCard)
if err != nil {
dialog.ShowError(err, w)
}
},
}
form := &widget.Form{
Items: items,
SubmitText: "生成变量表单",
OnSubmit: func() {
for _, item := range items {
switch item.Text {
case "模版内容":
varSum := countVarOccurrences(item.Widget.(*widget.Entry).Text)
for i := 0; i < varSum; i++ {
newItem := &widget.FormItem{Text: fmt.Sprintf("变量%d", i+1), Widget: widget.NewEntry()}
items2 = append(items2, newItem)
form2.AppendItem(newItem)
}
default:
}
}
},
}
return container.NewBorder(widget.NewSeparator(), nil, nil, nil, container.NewScroll(
container.NewVBox(
form,
form2,
)))
}
func countVarOccurrences(input string) int {
re := regexp.MustCompile(`\$var`)
matches := re.FindAllStringIndex(input, -1)
return len(matches)
}
+29
View File
@@ -0,0 +1,29 @@
package views
import (
"fyne.io/fyne/v2"
)
// Tutorial 定义教程的数据结构
type Tutorial struct {
Title, Intro string
View func(w fyne.Window) fyne.CanvasObject
SupportWeb bool
}
var (
// Tutorials 定义每个教程的元数据
Tutorials = map[string]Tutorial{
"welcome": {"主页", "", UserViews, true},
"canvas": {"我的", "", myCardsViews, true},
"create": {"新建", "", CreateErlangCard, true},
}
// TutorialIndex 定义我们的教程应该如何在索引树中布局
TutorialIndex = map[string][]string{
"": {"welcome", "canvas", "create"},
//"collections": {"list", "table", "tree"},
//"containers": {"apptabs", "border", "box", "center", "doctabs", "grid", "scroll", "split"},
//"widgets": {"accordion", "button", "card", "entry", "form", "input", "progress", "text", "toolbar"},
}
)
+27 -5
View File
@@ -5,13 +5,27 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/data/binding"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
"github.com/atotto/clipboard"
"strings"
"work_cation/global"
"work_cation/models"
"work_cation/utils"
"work_cation/models/repo"
"work_cation/pkg/utils"
)
func myCardsViews(w fyne.Window) fyne.CanvasObject {
var items []fyne.CanvasObject
for _, i := range repo.ErlangCardRepo.FindAll(global.DB) {
var i2 = i
items = append(items, ErlangCardView(w, &i2))
}
return container.NewBorder(nil, nil, nil, nil, container.NewScroll(
container.NewGridWrap(fyne.NewSize(200, 200), items...)))
}
func ErlangCardView(_ fyne.Window, data *models.ErlangCards) fyne.CanvasObject {
if data == nil {
data = &models.ErlangCards{
@@ -32,10 +46,15 @@ func ErlangCardView(_ fyne.Window, data *models.ErlangCards) fyne.CanvasObject {
txtWid := widget.NewEntryWithData(txtBound)
txtWid.Wrapping = fyne.TextWrapOff
card := widget.NewCard(data.Title, data.Text, widget.NewButton("OPEN", func() {
cardButton := widget.NewButton("OPEN", func() {
go UseErlangCard(data)
}))
//card.SetImage(assets.LogoDataSR)
})
card := widget.NewCard(data.Title, data.Text, cardButton)
//image := canvas.NewImageFromResource(assets.LogoDataSR)
//image.FillMode = canvas.ImageFillContain
//card.SetImage(image)
return card
}
@@ -91,7 +110,10 @@ func UseErlangCard(data *models.ErlangCards) {
data.VarContent = values
//out.SetText(replaceVars(template, data.VarContent))
err := clipboard.WriteAll(replaceVars(template, data.VarContent))
fmt.Print("复制:", replaceVars(template, data.VarContent), err)
if err != nil {
dialog.ShowError(err, myWindow)
}
upOut()
},
}
+32
View File
@@ -0,0 +1,32 @@
package views
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"work_cation/assets"
"work_cation/global"
"work_cation/models/repo"
)
func UserViews(w fyne.Window) fyne.CanvasObject {
image := canvas.NewImageFromResource(assets.LogoDataSR)
image.FillMode = canvas.ImageFillContain
user := repo.UserRepo.GetUserInfo(global.DB)
userCard := widget.NewCard(
user.Name,
user.Ip,
nil)
userCard.SetImage(image)
return container.NewBorder(nil,
nil,
nil,
nil,
userCard,
)
}