mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-09-25 12:46:40 +08:00
发布v2.16.10版本,更新内容请查看:https://github.com/bufanyun/hotgo/blob/v2.0/docs/guide-zh-CN/start-update-log.md
This commit is contained in:
parent
5301bedff2
commit
62af998991
@ -6,13 +6,13 @@
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://goframe.org/pages/viewpage.action?pageId=1114119" target="_blank">
|
||||
<img src="https://img.shields.io/badge/goframe-2.8-green" alt="goframe">
|
||||
<img src="https://img.shields.io/badge/goframe-2.9.0-green" alt="goframe">
|
||||
</a>
|
||||
<a href="https://v3.vuejs.org/" target="_blank">
|
||||
<img src="https://img.shields.io/badge/vue.js-vue3.4-green" alt="vue">
|
||||
</a>
|
||||
<a href="https://www.naiveui.com" target="_blank">
|
||||
<img src="https://img.shields.io/badge/naiveui-%3E2.39.0-blue" alt="naiveui">
|
||||
<img src="https://img.shields.io/badge/naiveui-%3E2.41.0-blue" alt="naiveui">
|
||||
</a>
|
||||
<a href="https://www.tslang.cn/" target="_blank">
|
||||
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
|
||||
@ -136,7 +136,7 @@
|
||||
|
||||
* 本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
* 版权所有Copyright © 2020-2024 by Ms (https://github.com/bufanyun/hotgo)
|
||||
* 版权所有Copyright © 2020-2025 by Ms (https://github.com/bufanyun/hotgo)
|
||||
|
||||
* All rights reserved。
|
||||
|
||||
@ -154,7 +154,7 @@
|
||||
|
||||
|
||||
## [感谢JetBrains提供的免费GoLand](https://jb.gg/OpenSource)
|
||||
[](https://jb.gg/OpenSource)
|
||||
[](https://jb.gg/OpenSource)
|
||||
|
||||
|
||||
## License
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
> 需要本地具有 git node golang 环境
|
||||
|
||||
- node版本 >= 16.0.0
|
||||
- node版本 >= 20.0.0
|
||||
- golang版本 >= 1.23
|
||||
- mysql版本 >= 5.7,引擎需要是 innoDB
|
||||
- IDE推荐:Goland
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
### 环境要求
|
||||
|
||||
- node版本 >= v16.0.0
|
||||
- node版本 >= v20.0.0
|
||||
- golang版本 >= v1.23
|
||||
- goframe版本 >=v2.7.0
|
||||
- mysql版本 >=5.7
|
||||
|
@ -11,6 +11,20 @@
|
||||
|
||||
> 如果升级(覆盖)代码后打开会出现 sql 报错, 请检查更新的数据库格式或自行调整
|
||||
|
||||
### v2.16.10
|
||||
updated 2025.3.22
|
||||
|
||||
- 增加:增加组合下拉用户筛选组件
|
||||
- 优化:文件上传类型限制改为统一由后台配置控制
|
||||
- 优化:websocket重连时间调整为10秒,初始化数据库中的网站地址调整为`127.0.0.1`
|
||||
- 优化:优化访问日志字段展示方式
|
||||
- 优化:系统公告发送编辑模态框调整为抽屉
|
||||
- 优化:gf版本升级到v2.9.0
|
||||
- 优化:naive-ui版本升级到2.41.0
|
||||
- 修复:修复vue路由`Redirect`命名重复问题
|
||||
- 修复:优化代码生成在插件中`使用生成字典选项`时model包名重复问题
|
||||
|
||||
|
||||
### v2.15.11
|
||||
updated 2024.11.27
|
||||
|
||||
|
@ -14,10 +14,10 @@ require (
|
||||
github.com/forgoer/openssl v1.6.0
|
||||
github.com/go-pay/crypto v0.0.1
|
||||
github.com/go-pay/gopay v1.5.104
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.1
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.1
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0
|
||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4
|
||||
github.com/gogf/gf/v2 v2.8.1
|
||||
github.com/gogf/gf/v2 v2.9.0
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
@ -26,6 +26,7 @@ require (
|
||||
github.com/mojocn/base64Captcha v1.3.6
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/qiniu/go-sdk/v7 v7.21.1
|
||||
github.com/schollz/progressbar/v3 v3.18.0
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
github.com/silenceper/wechat/v2 v2.1.6
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.993
|
||||
@ -35,7 +36,7 @@ require (
|
||||
github.com/xuri/excelize/v2 v2.6.0
|
||||
go.opentelemetry.io/otel v1.32.0
|
||||
golang.org/x/mod v0.20.0
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/net v0.32.0
|
||||
golang.org/x/tools v0.24.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@ -98,12 +99,13 @@ require (
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@ -136,11 +138,12 @@ require (
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.29.0 // indirect
|
||||
golang.org/x/crypto v0.30.0 // indirect
|
||||
golang.org/x/image v0.19.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
|
@ -78,6 +78,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@ -162,14 +164,14 @@ github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.1 h1:jbaPawkb8qmaYzrmBDbTa8Zkhzacq1RBOZw+qRJExI4=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.1/go.mod h1:s2aI1fV9AvKi4NtMpv3pV0EHtazkvfUNVQmzapr7UJQ=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.1 h1:1vPFyN0GLv24JD3WGhvKzXvKG+fmuixDTawbtfzCzRQ=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.1/go.mod h1:IWyGxzplp06tRc6Ah/eCLuBntnKSw9sn1maH0vzPPtw=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0 h1:1f7EeD0lfPHoXfaJDSL7cxRcSRelbsAKgF3MGXY+Uyo=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0/go.mod h1:tToO1PjGkLIR+9DbJ0wrKicYma0H/EUHXOpwel6Dw+0=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0 h1:EEZqu1PNRSmm+7Cqm9A/8+ObgfbMzhE1ps9Z3LD7HgM=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0/go.mod h1:LHrxY+2IzNTHVTPG/s5yaz1VmXbj+CQ7Hr5SeVkHiTw=
|
||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4 h1:JnUjXb7C9vmwcZFwXqnxi9H4/I0rir9LmRryIX7xNds=
|
||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4/go.mod h1:A3NhV8u45twLq5VdqObhYNhT4szLFLCROw4LzHM+lYg=
|
||||
github.com/gogf/gf/v2 v2.8.1 h1:1oVQg3G5OgCats4qWFTH3pHLe92nfUQeUDta05tUs1g=
|
||||
github.com/gogf/gf/v2 v2.8.1/go.mod h1:6iYuZZ+A0ZcH8+4MDS/P0SvTPCvKzRvyAsY1kbkJYJc=
|
||||
github.com/gogf/gf/v2 v2.9.0 h1:semN5Q5qGjDQEv4620VzxcJzJlSD07gmyJ9Sy9zfbHk=
|
||||
github.com/gogf/gf/v2 v2.9.0/go.mod h1:sWGQw+pLILtuHmbOxoe0D+0DdaXxbleT57axOLH2vKI=
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
@ -274,8 +276,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY=
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f h1:B0OD7nYl2FPQEVrw8g2uyc1lGEzNbvrKh7fspGZcbvY=
|
||||
github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f/go.mod h1:aEt7p9Rvh67BYApmZwNDPpgircTO2kgdmDUoF/1QmwA=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
@ -290,6 +292,8 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.76 h1:9nxHH2XDai61cT/EFhyIw/wW4vJfpPNvl7lSFpRt+Ng=
|
||||
github.com/minio/minio-go/v7 v7.0.76/go.mod h1:AVM3IUN6WwKzmwBxVdjzhH8xq+f57JSbbvzqvUzR6eg=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
@ -356,10 +360,12 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
@ -395,8 +401,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.993 h1:+iJMmF0q1MPyhLs0+J7CcJ47w/vq6ICsCxnV4gc0dKw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.993/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
@ -468,8 +474,8 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
|
||||
@ -511,8 +517,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -523,8 +529,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -559,8 +565,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -568,6 +574,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@ -579,8 +587,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -7,5 +7,5 @@ package consts
|
||||
|
||||
// VersionApp HotGo版本
|
||||
const (
|
||||
VersionApp = "2.15.11"
|
||||
VersionApp = "2.16.10"
|
||||
)
|
||||
|
@ -49,7 +49,7 @@ func Dao(ctx context.Context) (err error) {
|
||||
inp.ImportPrefix = utils.GetImportPath(inp.Path)
|
||||
inp.Path = tempPathPrefix + "/" + inp.Path
|
||||
|
||||
if err = gfile.Remove(inp.Path); err != nil {
|
||||
if err = gfile.RemoveAll(inp.Path); err != nil {
|
||||
err = gerror.Newf("清理临时生成目录失败:%v", err)
|
||||
return err
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package cmd provides the management of CLI commands for `gf` tool.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@ -19,9 +20,8 @@ import (
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
GF = cGF{}
|
||||
)
|
||||
// GF is the management object for `gf` command line tool.
|
||||
var GF = cGF{}
|
||||
|
||||
type cGF struct {
|
||||
g.Meta `name:"gf" ad:"{cGFAd}"`
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/encoding/gcompress"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
|
@ -9,13 +9,13 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
|
@ -8,13 +8,15 @@ package cmd
|
||||
|
||||
import (
|
||||
//_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
|
||||
// _ "github.com/gogf/gf/contrib/drivers/dm/v2" // precompilation does not support certain target platforms.
|
||||
//_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
//_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
|
||||
//_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
||||
//_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
|
||||
// do not add dm in cli pre-compilation,
|
||||
// the dm driver does not support certain target platforms.
|
||||
// _ "github.com/gogf/gf/contrib/drivers/dm/v2"
|
||||
"hotgo/internal/library/hggen/internal/cmd/gendao"
|
||||
)
|
||||
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/allyes"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
@ -1,38 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
testDB gdb.DB
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
testDB, err = gdb.New(gdb.ConfigNode{
|
||||
Link: link,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropTableWithDb(db gdb.DB, table string) {
|
||||
dropTableStmt := fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)
|
||||
if _, err := db.Exec(ctx, dropTableStmt); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
func Test_Build_Single(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `t.test`
|
||||
binaryPath = gtest.DataPath(`build`, `single`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: cBuildDefaultFile,
|
||||
Name: binaryName,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Output(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `tt`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, `tt`)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, `tt`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Output: "./tt/tt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Path(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
dirName = "ttt"
|
||||
binaryName = `main`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, dirName)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, dirName, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Path: "ttt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_VarMap(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `varmap`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `main`
|
||||
binaryPath = gtest.DataPath(`build`, `varmap`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
VarMap: map[string]interface{}{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
|
||||
result, err := gproc.ShellExec(ctx, binaryPath)
|
||||
t.AssertNil(err)
|
||||
t.Assert(gstr.Contains(result, `a: 1`), true)
|
||||
t.Assert(gstr.Contains(result, `b: 2`), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Multiple(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `multiple`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryDirPath = gtest.DataPath(`build`, `multiple`, `temp`)
|
||||
binaryPathLinux = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `linux_amd64`, `ttt`)
|
||||
binaryPathWindows = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `windows_amd64`, `ttt.exe`)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPathLinux), false)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: "multiple.go",
|
||||
Name: "ttt",
|
||||
Version: "v1.1",
|
||||
Arch: "amd64",
|
||||
System: "linux, windows",
|
||||
Path: "temp",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPathLinux), true)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), true)
|
||||
})
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Fix_doFixV25Content(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
content = gtest.DataContent(`fix`, `fix25_content.go`)
|
||||
f = cFix{}
|
||||
)
|
||||
_, err := f.doFixV25Content(content)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
@ -1,309 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genctrl"
|
||||
)
|
||||
|
||||
func Test_Gen_Ctrl_Default(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
apiFolder = gtest.DataPath("genctrl", "api")
|
||||
in = genctrl.CGenCtrlInput{
|
||||
SrcFolder: apiFolder,
|
||||
DstFolder: path,
|
||||
WatchFile: "",
|
||||
SdkPath: "",
|
||||
SdkStdVersion: false,
|
||||
SdkNoV1: false,
|
||||
Clear: false,
|
||||
Merge: false,
|
||||
}
|
||||
)
|
||||
err := gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// apiInterface file
|
||||
var (
|
||||
genApi = apiFolder + filepath.FromSlash("/article/article.go")
|
||||
genApiExpect = apiFolder + filepath.FromSlash("/article/article_expect.go")
|
||||
)
|
||||
defer gfile.Remove(genApi)
|
||||
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + filepath.FromSlash("/article/article.go"),
|
||||
path + filepath.FromSlash("/article/article_new.go"),
|
||||
path + filepath.FromSlash("/article/article_v1_create.go"),
|
||||
path + filepath.FromSlash("/article/article_v1_get_list.go"),
|
||||
path + filepath.FromSlash("/article/article_v1_get_one.go"),
|
||||
path + filepath.FromSlash("/article/article_v1_update.go"),
|
||||
path + filepath.FromSlash("/article/article_v2_create.go"),
|
||||
path + filepath.FromSlash("/article/article_v2_update.go"),
|
||||
})
|
||||
|
||||
// content
|
||||
testPath := gtest.DataPath("genctrl", "controller")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/article/article.go"),
|
||||
testPath + filepath.FromSlash("/article/article_new.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v1_create.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v1_get_list.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v1_get_one.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v1_update.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v2_create.go"),
|
||||
testPath + filepath.FromSlash("/article/article_v2_update.go"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func expectFilesContent(t *gtest.T, paths []string, expectPaths []string) {
|
||||
for i, expectFile := range expectPaths {
|
||||
val := gfile.GetContents(paths[i])
|
||||
expect := gfile.GetContents(expectFile)
|
||||
t.Assert(val, expect)
|
||||
}
|
||||
}
|
||||
|
||||
// gf gen ctrl -m
|
||||
// In the same module, different API files are added
|
||||
func Test_Gen_Ctrl_UseMerge_AddNewFile(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
ctrlPath = gfile.Temp(guid.S())
|
||||
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
|
||||
apiFolder = gtest.DataPath("genctrl-merge", "add_new_file", "api")
|
||||
in = genctrl.CGenCtrlInput{
|
||||
SrcFolder: apiFolder,
|
||||
DstFolder: ctrlPath,
|
||||
Merge: true,
|
||||
}
|
||||
)
|
||||
const testNewApiFile = `
|
||||
package v1
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
type DictTypeAddReq struct {
|
||||
g.Meta
|
||||
}
|
||||
type DictTypeAddRes struct {
|
||||
}
|
||||
`
|
||||
|
||||
err := gfile.Mkdir(ctrlPath)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(ctrlPath)
|
||||
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
var (
|
||||
genApi = filepath.Join(apiFolder, "/dict/dict.go")
|
||||
genApiExpect = filepath.Join(apiFolder, "/dict/dict_expect.go")
|
||||
)
|
||||
defer gfile.Remove(genApi)
|
||||
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
|
||||
|
||||
genCtrlFiles, err := gfile.ScanDir(ctrlPath, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(genCtrlFiles, []string{
|
||||
filepath.Join(ctrlPath, "/dict/dict.go"),
|
||||
filepath.Join(ctrlPath, "/dict/dict_new.go"),
|
||||
filepath.Join(ctrlPath, "/dict/dict_v1_dict_type.go"),
|
||||
})
|
||||
|
||||
expectCtrlPath := gtest.DataPath("genctrl-merge", "add_new_file", "controller")
|
||||
expectFiles := []string{
|
||||
filepath.Join(expectCtrlPath, "/dict/dict.go"),
|
||||
filepath.Join(expectCtrlPath, "/dict/dict_new.go"),
|
||||
filepath.Join(expectCtrlPath, "/dict/dict_v1_dict_type.go"),
|
||||
}
|
||||
|
||||
// Line Feed maybe \r\n or \n
|
||||
expectFilesContent(t, genCtrlFiles, expectFiles)
|
||||
|
||||
// Add a new API file
|
||||
newApiFilePath := filepath.Join(apiFolder, "/dict/v1/test_new.go")
|
||||
err = gfile.PutContents(newApiFilePath, testNewApiFile)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(newApiFilePath)
|
||||
|
||||
// Then execute the command
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
genApi = filepath.Join(apiFolder, "/dict.go")
|
||||
genApiExpect = filepath.Join(apiFolder, "/dict_add_new_ctrl_expect.gotest")
|
||||
|
||||
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
|
||||
|
||||
genCtrlFiles = append(genCtrlFiles, filepath.Join(ctrlPath, "/dict/dict_v1_test_new.go"))
|
||||
// Use the gotest suffix, otherwise the IDE will delete the import
|
||||
expectFiles = append(expectFiles, filepath.Join(expectCtrlPath, "/dict/dict_v1_test_new.gotest"))
|
||||
// Line Feed maybe \r\n or \n
|
||||
expectFilesContent(t, genCtrlFiles, expectFiles)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// gf gen ctrl -m
|
||||
// In the same module, Add the same file to the API
|
||||
func Test_Gen_Ctrl_UseMerge_AddNewCtrl(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
ctrlPath = gfile.Temp(guid.S())
|
||||
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
|
||||
apiFolder = gtest.DataPath("genctrl-merge", "add_new_ctrl", "api")
|
||||
in = genctrl.CGenCtrlInput{
|
||||
SrcFolder: apiFolder,
|
||||
DstFolder: ctrlPath,
|
||||
Merge: true,
|
||||
}
|
||||
)
|
||||
|
||||
err := gfile.Mkdir(ctrlPath)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(ctrlPath)
|
||||
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
var (
|
||||
genApi = filepath.Join(apiFolder, "/dict/dict.go")
|
||||
genApiExpect = filepath.Join(apiFolder, "/dict/dict_expect.go")
|
||||
)
|
||||
defer gfile.Remove(genApi)
|
||||
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
|
||||
|
||||
genCtrlFiles, err := gfile.ScanDir(ctrlPath, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(genCtrlFiles, []string{
|
||||
filepath.Join(ctrlPath, "/dict/dict.go"),
|
||||
filepath.Join(ctrlPath, "/dict/dict_new.go"),
|
||||
filepath.Join(ctrlPath, "/dict/dict_v1_dict_type.go"),
|
||||
})
|
||||
|
||||
expectCtrlPath := gtest.DataPath("genctrl-merge", "add_new_ctrl", "controller")
|
||||
expectFiles := []string{
|
||||
filepath.Join(expectCtrlPath, "/dict/dict.go"),
|
||||
filepath.Join(expectCtrlPath, "/dict/dict_new.go"),
|
||||
filepath.Join(expectCtrlPath, "/dict/dict_v1_dict_type.go"),
|
||||
}
|
||||
|
||||
// Line Feed maybe \r\n or \n
|
||||
expectFilesContent(t, genCtrlFiles, expectFiles)
|
||||
|
||||
const testNewApiFile = `
|
||||
|
||||
type DictTypeAddReq struct {
|
||||
g.Meta
|
||||
}
|
||||
type DictTypeAddRes struct {
|
||||
}
|
||||
`
|
||||
dictModuleFileName := filepath.Join(apiFolder, "/dict/v1/dict_type.go")
|
||||
// Save the contents of the file before the changes
|
||||
apiFileContents := gfile.GetContents(dictModuleFileName)
|
||||
|
||||
// Add a new API file
|
||||
err = gfile.PutContentsAppend(dictModuleFileName, testNewApiFile)
|
||||
t.AssertNil(err)
|
||||
|
||||
//==================================
|
||||
// Then execute the command
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
genApi = filepath.Join(apiFolder, "/dict.go")
|
||||
genApiExpect = filepath.Join(apiFolder, "/dict_add_new_ctrl_expect.gotest")
|
||||
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
|
||||
|
||||
// Use the gotest suffix, otherwise the IDE will delete the import
|
||||
expectFiles[2] = filepath.Join(expectCtrlPath, "/dict/dict_v1_test_new.gotest")
|
||||
// Line Feed maybe \r\n or \n
|
||||
expectFilesContent(t, genCtrlFiles, expectFiles)
|
||||
|
||||
// Restore the contents of the original API file
|
||||
err = gfile.PutContents(dictModuleFileName, apiFileContents)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3460
|
||||
func Test_Gen_Ctrl_UseMerge_Issue3460(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
ctrlPath = gfile.Temp(guid.S())
|
||||
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
|
||||
apiFolder = gtest.DataPath("issue", "3460", "api")
|
||||
in = genctrl.CGenCtrlInput{
|
||||
SrcFolder: apiFolder,
|
||||
DstFolder: ctrlPath,
|
||||
WatchFile: "",
|
||||
SdkPath: "",
|
||||
SdkStdVersion: false,
|
||||
SdkNoV1: false,
|
||||
Clear: false,
|
||||
Merge: true,
|
||||
}
|
||||
)
|
||||
|
||||
err := gfile.Mkdir(ctrlPath)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(ctrlPath)
|
||||
|
||||
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
files, err := gfile.ScanDir(ctrlPath, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.Join(ctrlPath, "/hello/hello.go"),
|
||||
filepath.Join(ctrlPath, "/hello/hello_new.go"),
|
||||
filepath.Join(ctrlPath, "/hello/hello_v1_req.go"),
|
||||
filepath.Join(ctrlPath, "/hello/hello_v2_req.go"),
|
||||
})
|
||||
|
||||
expectCtrlPath := gtest.DataPath("issue", "3460", "controller")
|
||||
expectFiles := []string{
|
||||
filepath.Join(expectCtrlPath, "/hello/hello.go"),
|
||||
filepath.Join(expectCtrlPath, "/hello/hello_new.go"),
|
||||
filepath.Join(expectCtrlPath, "/hello/hello_v1_req.go"),
|
||||
filepath.Join(expectCtrlPath, "/hello/hello_v2_req.go"),
|
||||
}
|
||||
|
||||
// Line Feed maybe \r\n or \n
|
||||
for i, expectFile := range expectFiles {
|
||||
val := gfile.GetContents(files[i])
|
||||
expect := gfile.GetContents(expectFile)
|
||||
t.Assert(val, expect)
|
||||
}
|
||||
})
|
||||
}
|
@ -1,841 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/gendao"
|
||||
)
|
||||
|
||||
func Test_Gen_Dao_Default(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
FieldMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_TypeMapping(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
defer dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
|
||||
"int": {
|
||||
Type: "int64",
|
||||
Import: "",
|
||||
},
|
||||
"decimal": {
|
||||
Type: "decimal.Decimal",
|
||||
Import: "github.com/shopspring/decimal",
|
||||
},
|
||||
},
|
||||
FieldMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user_type_mapping")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_FieldMapping(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
defer dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
|
||||
"int": {
|
||||
Type: "int64",
|
||||
Import: "",
|
||||
},
|
||||
},
|
||||
FieldMapping: map[gendao.DBTableFieldName]gendao.CustomAttributeType{
|
||||
"table_user.score": {
|
||||
Type: "decimal.Decimal",
|
||||
Import: "github.com/shopspring/decimal",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user_field_mapping")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func execSqlFile(db gdb.DB, filePath string, args ...any) error {
|
||||
sqlContent := fmt.Sprintf(
|
||||
gfile.GetContents(filePath),
|
||||
args...,
|
||||
)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err := db.Exec(ctx, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/2572
|
||||
func Test_Gen_Dao_Issue2572(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table1 = "user1"
|
||||
table2 = "user2"
|
||||
issueDirPath = gtest.DataPath(`issue`, `2572`)
|
||||
)
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql1.sql`)))
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql2.sql`)))
|
||||
defer dropTableWithDb(db, table1)
|
||||
defer dropTableWithDb(db, table2)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: "",
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
FieldMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Copy(issueDirPath, path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Remove(path)
|
||||
|
||||
pwd := gfile.Pwd()
|
||||
err = gfile.Chdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Chdir(pwd)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(generatedFiles), 8)
|
||||
for i, generatedFile := range generatedFiles {
|
||||
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
|
||||
}
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/internal/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/internal/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/do/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/do/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/entity/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/entity/user_2.go")), true)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/2616
|
||||
func Test_Gen_Dao_Issue2616(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table1 = "user1"
|
||||
table2 = "user2"
|
||||
issueDirPath = gtest.DataPath(`issue`, `2616`)
|
||||
)
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql1.sql`)))
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql2.sql`)))
|
||||
defer dropTableWithDb(db, table1)
|
||||
defer dropTableWithDb(db, table2)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: "",
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
FieldMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Copy(issueDirPath, path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Remove(path)
|
||||
|
||||
pwd := gfile.Pwd()
|
||||
err = gfile.Chdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Chdir(pwd)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(generatedFiles), 8)
|
||||
for i, generatedFile := range generatedFiles {
|
||||
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
|
||||
}
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/internal/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/internal/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/dao/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/do/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/do/user_2.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/entity/user_1.go")), true)
|
||||
t.Assert(gstr.InArray(generatedFiles,
|
||||
filepath.FromSlash("/model/entity/user_2.go")), true)
|
||||
|
||||
// Key string to check if overwrite the dao files.
|
||||
// dao user1 is not be overwritten as configured in config.yaml.
|
||||
// dao user2 is to be overwritten as configured in config.yaml.
|
||||
var (
|
||||
keyStr = `// I am not overwritten.`
|
||||
daoUser1Content = gfile.GetContents(path + "/dao/user_1.go")
|
||||
daoUser2Content = gfile.GetContents(path + "/dao/user_2.go")
|
||||
)
|
||||
t.Assert(gstr.Contains(daoUser1Content, keyStr), true)
|
||||
t.Assert(gstr.Contains(daoUser2Content, keyStr), false)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/2746
|
||||
func Test_Gen_Dao_Issue2746(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
mdb gdb.DB
|
||||
link2746 = "mariadb:root:12345678@tcp(127.0.0.1:3307)/test?loc=Local&parseTime=true"
|
||||
table = "issue2746"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`issue`, `2746`, `sql.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
mdb, err = gdb.New(gdb.ConfigNode{
|
||||
Link: link2746,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = mdb.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(mdb, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link2746,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: true,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
FieldMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
var (
|
||||
file = filepath.FromSlash(path + "/model/entity/issue_2746.go")
|
||||
expectContent = gtest.DataContent(`issue`, `2746`, `issue_2746.go`)
|
||||
)
|
||||
t.Assert(expectContent, gfile.GetContents(file))
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3459
|
||||
func Test_Gen_Dao_Issue3459(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
confDir = gtest.DataPath("issue", "3459")
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
}
|
||||
)
|
||||
err = g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetPath(confDir)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3749
|
||||
func Test_Gen_Dao_Issue3749(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`issue`, `3749`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Group: group,
|
||||
}
|
||||
)
|
||||
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath(`issue`, `3749`)
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_Sqlite3(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
table = "table_user"
|
||||
path = gfile.Temp(guid.S())
|
||||
linkSqlite3 = fmt.Sprintf("sqlite::@file(%s/db.sqlite3)", path)
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `sqlite3`, `user.sqlite3.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
dbSqlite3, err := gdb.New(gdb.ConfigNode{
|
||||
Link: linkSqlite3,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if _, err = dbSqlite3.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: linkSqlite3,
|
||||
Group: group,
|
||||
Tables: table,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
filepath.FromSlash(path + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(path + "/dao/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(path + "/model/entity/table_user.go"),
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user_sqlite3")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/dao/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/do/table_user.go"),
|
||||
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genpb"
|
||||
)
|
||||
|
||||
func TestGenPbIssue3882(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
outputPath = gfile.Temp(guid.S())
|
||||
outputApiPath = filepath.Join(outputPath, "api")
|
||||
outputCtrlPath = filepath.Join(outputPath, "controller")
|
||||
|
||||
protobufFolder = gtest.DataPath("issue", "3882")
|
||||
in = genpb.CGenPbInput{
|
||||
Path: protobufFolder,
|
||||
OutputApi: outputApiPath,
|
||||
OutputCtrl: outputCtrlPath,
|
||||
}
|
||||
err error
|
||||
)
|
||||
err = gfile.Mkdir(outputApiPath)
|
||||
t.AssertNil(err)
|
||||
err = gfile.Mkdir(outputCtrlPath)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(outputPath)
|
||||
|
||||
_, err = genpb.CGenPb{}.Pb(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
var (
|
||||
genContent = gfile.GetContents(filepath.Join(outputApiPath, "issue3882.pb.go"))
|
||||
exceptText = `dc:"Some comment on field with 'one' 'two' 'three' in the comment."`
|
||||
)
|
||||
t.Assert(gstr.Contains(genContent, exceptText), true)
|
||||
})
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genpbentity"
|
||||
)
|
||||
|
||||
func Test_Gen_Pbentity_Default(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
in = genpbentity.CGenPbEntityInput{
|
||||
Path: path,
|
||||
Package: "unittest",
|
||||
Link: link,
|
||||
Tables: "",
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
RemoveFieldPrefix: "",
|
||||
NameCase: "",
|
||||
JsonCase: "",
|
||||
Option: "",
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.proto", false)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + filepath.FromSlash("/table_user.proto"),
|
||||
})
|
||||
|
||||
// contents
|
||||
testPath := gtest.DataPath("genpbentity", "generated")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/table_user.proto"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Pbentity_NameCase_SnakeScreaming(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
in = genpbentity.CGenPbEntityInput{
|
||||
Path: path,
|
||||
Package: "unittest",
|
||||
Link: link,
|
||||
Tables: "",
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
RemoveFieldPrefix: "",
|
||||
NameCase: "SnakeScreaming",
|
||||
JsonCase: "",
|
||||
Option: "",
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.proto", false)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + filepath.FromSlash("/table_user.proto"),
|
||||
})
|
||||
|
||||
// contents
|
||||
testPath := gtest.DataPath("genpbentity", "generated")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/table_user_snake_screaming.proto"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3545
|
||||
func Test_Issue_3545(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
in = genpbentity.CGenPbEntityInput{
|
||||
Path: path,
|
||||
Package: "",
|
||||
Link: link,
|
||||
Tables: "",
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
RemoveFieldPrefix: "",
|
||||
NameCase: "",
|
||||
JsonCase: "",
|
||||
Option: "",
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.proto", false)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + filepath.FromSlash("/table_user.proto"),
|
||||
})
|
||||
|
||||
// contents
|
||||
testPath := gtest.DataPath("issue", "3545")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/table_user.proto"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genservice"
|
||||
)
|
||||
|
||||
func Test_Gen_Service_Default(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
dstFolder = path + filepath.FromSlash("/service")
|
||||
srvFolder = gtest.DataPath("genservice", "logic")
|
||||
in = genservice.CGenServiceInput{
|
||||
SrcFolder: srvFolder,
|
||||
DstFolder: dstFolder,
|
||||
DstFileNameCase: "Snake",
|
||||
WatchFile: "",
|
||||
StPattern: "",
|
||||
Packages: nil,
|
||||
ImportPrefix: "",
|
||||
Clear: false,
|
||||
}
|
||||
)
|
||||
err := gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genservice.CGenService{}.Service(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// logic file
|
||||
var (
|
||||
genSrv = srvFolder + filepath.FromSlash("/logic.go")
|
||||
genSrvExpect = srvFolder + filepath.FromSlash("/logic_expect.go")
|
||||
)
|
||||
defer gfile.Remove(genSrv)
|
||||
t.Assert(gfile.GetContents(genSrv), gfile.GetContents(genSrvExpect))
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(dstFolder, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
dstFolder + filepath.FromSlash("/article.go"),
|
||||
dstFolder + filepath.FromSlash("/delivery.go"),
|
||||
dstFolder + filepath.FromSlash("/user.go"),
|
||||
})
|
||||
|
||||
// contents
|
||||
testPath := gtest.DataPath("genservice", "service")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/article.go"),
|
||||
testPath + filepath.FromSlash("/delivery.go"),
|
||||
testPath + filepath.FromSlash("/user.go"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3328
|
||||
func Test_Issue3328(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
dstFolder = path + filepath.FromSlash("/service")
|
||||
srvFolder = gtest.DataPath("issue", "3328", "logic")
|
||||
logicGoPath = srvFolder + filepath.FromSlash("/logic.go")
|
||||
in = genservice.CGenServiceInput{
|
||||
SrcFolder: srvFolder,
|
||||
DstFolder: dstFolder,
|
||||
DstFileNameCase: "Snake",
|
||||
WatchFile: "",
|
||||
StPattern: "",
|
||||
Packages: nil,
|
||||
ImportPrefix: "",
|
||||
Clear: false,
|
||||
}
|
||||
)
|
||||
gfile.Remove(logicGoPath)
|
||||
defer gfile.Remove(logicGoPath)
|
||||
|
||||
err := gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genservice.CGenService{}.Service(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
files, err := gfile.ScanDir(srvFolder, "*", true)
|
||||
for _, file := range files {
|
||||
if file == logicGoPath {
|
||||
if gfile.IsDir(logicGoPath) {
|
||||
t.Fatalf("%s should not is folder", logicGoPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3835
|
||||
func Test_Issue3835(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
dstFolder = path + filepath.FromSlash("/service")
|
||||
srvFolder = gtest.DataPath("issue", "3835", "logic")
|
||||
in = genservice.CGenServiceInput{
|
||||
SrcFolder: srvFolder,
|
||||
DstFolder: dstFolder,
|
||||
DstFileNameCase: "Snake",
|
||||
WatchFile: "",
|
||||
StPattern: "",
|
||||
Packages: nil,
|
||||
ImportPrefix: "",
|
||||
Clear: false,
|
||||
}
|
||||
)
|
||||
err := gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
_, err = genservice.CGenService{}.Service(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
// contents
|
||||
var (
|
||||
genFile = dstFolder + filepath.FromSlash("/issue_3835.go")
|
||||
expectFile = gtest.DataPath("issue", "3835", "service", "issue_3835.go")
|
||||
)
|
||||
t.Assert(gfile.GetContents(genFile), gfile.GetContents(expectFile))
|
||||
})
|
||||
}
|
@ -6,7 +6,11 @@
|
||||
|
||||
package genctrl
|
||||
|
||||
import "github.com/gogf/gf/v2/text/gstr"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type apiItem struct {
|
||||
Import string `eg:"demo.com/api/user/v1"`
|
||||
@ -14,6 +18,7 @@ type apiItem struct {
|
||||
Module string `eg:"user"`
|
||||
Version string `eg:"v1"`
|
||||
MethodName string `eg:"GetList"`
|
||||
Comment string `eg:"GetList get list"`
|
||||
}
|
||||
|
||||
func (a apiItem) String() string {
|
||||
@ -21,3 +26,12 @@ func (a apiItem) String() string {
|
||||
a.Import, a.Module, a.Version, a.MethodName,
|
||||
}, ",")
|
||||
}
|
||||
|
||||
// GetComment returns the comment of apiItem.
|
||||
func (a apiItem) GetComment() string {
|
||||
if a.Comment == "" {
|
||||
return ""
|
||||
}
|
||||
// format for handling comments
|
||||
return fmt.Sprintf("\n// %s %s", a.MethodName, a.Comment)
|
||||
}
|
||||
|
@ -17,9 +17,14 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// getStructsNameInSrc retrieves all struct names
|
||||
type structInfo struct {
|
||||
structName string
|
||||
comment string
|
||||
}
|
||||
|
||||
// getStructsNameInSrc retrieves all struct names and comment
|
||||
// that end in "Req" and have "g.Meta" in their body.
|
||||
func (c CGenCtrl) getStructsNameInSrc(filePath string) (structsName []string, err error) {
|
||||
func (c CGenCtrl) getStructsNameInSrc(filePath string) (structInfos []*structInfo, err error) {
|
||||
var (
|
||||
fileContent = gfile.GetContents(filePath)
|
||||
fileSet = token.NewFileSet()
|
||||
@ -32,8 +37,8 @@ func (c CGenCtrl) getStructsNameInSrc(filePath string) (structsName []string, er
|
||||
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
if typeSpec, ok := n.(*ast.TypeSpec); ok {
|
||||
methodName := typeSpec.Name.Name
|
||||
if !gstr.HasSuffix(methodName, "Req") {
|
||||
structName := typeSpec.Name.Name
|
||||
if !gstr.HasSuffix(structName, "Req") {
|
||||
// ignore struct name that do not end in "Req"
|
||||
return true
|
||||
}
|
||||
@ -46,7 +51,19 @@ func (c CGenCtrl) getStructsNameInSrc(filePath string) (structsName []string, er
|
||||
if !gstr.Contains(buf.String(), `g.Meta`) {
|
||||
return true
|
||||
}
|
||||
structsName = append(structsName, methodName)
|
||||
|
||||
comment := typeSpec.Doc.Text()
|
||||
// remove the struct name from the comment
|
||||
if gstr.HasPrefix(comment, structName) {
|
||||
comment = gstr.TrimLeftStr(comment, structName, 1)
|
||||
}
|
||||
// remove the comment \n or space
|
||||
comment = gstr.Trim(comment)
|
||||
|
||||
structInfos = append(structInfos, &structInfo{
|
||||
structName: structName,
|
||||
comment: comment,
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
@ -38,15 +39,16 @@ func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, methodName := range structsInfo {
|
||||
for _, s := range structsInfo {
|
||||
// remove end "Req"
|
||||
methodName = gstr.TrimRightStr(methodName, "Req", 1)
|
||||
methodName := gstr.TrimRightStr(s.structName, "Req", 1)
|
||||
item := apiItem{
|
||||
Import: gstr.Trim(importPath, `"`),
|
||||
FileName: gfile.Name(apiFileFolderPath),
|
||||
Module: gfile.Basename(apiModuleFolderPath),
|
||||
Version: gfile.Basename(apiVersionFolderPath),
|
||||
MethodName: methodName,
|
||||
Comment: s.comment,
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
@ -137,10 +138,11 @@ func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, ite
|
||||
|
||||
if gfile.Exists(methodFilePath) {
|
||||
content = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{
|
||||
"{Module}": item.Module,
|
||||
"{CtrlName}": ctrlName,
|
||||
"{Version}": item.Version,
|
||||
"{MethodName}": item.MethodName,
|
||||
"{Module}": item.Module,
|
||||
"{CtrlName}": ctrlName,
|
||||
"{Version}": item.Version,
|
||||
"{MethodName}": item.MethodName,
|
||||
"{MethodComment}": item.GetComment(),
|
||||
})
|
||||
|
||||
if gstr.Contains(gfile.GetContents(methodFilePath), fmt.Sprintf(`func (c *%v) %v(`, ctrlName, item.MethodName)) {
|
||||
@ -151,11 +153,12 @@ func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, ite
|
||||
}
|
||||
} else {
|
||||
content = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFunc, g.MapStrStr{
|
||||
"{Module}": item.Module,
|
||||
"{ImportPath}": item.Import,
|
||||
"{CtrlName}": ctrlName,
|
||||
"{Version}": item.Version,
|
||||
"{MethodName}": item.MethodName,
|
||||
"{Module}": item.Module,
|
||||
"{ImportPath}": item.Import,
|
||||
"{CtrlName}": ctrlName,
|
||||
"{Version}": item.Version,
|
||||
"{MethodName}": item.MethodName,
|
||||
"{MethodComment}": item.GetComment(),
|
||||
})
|
||||
if err = gfile.PutContents(methodFilePath, gstr.TrimLeft(content)); err != nil {
|
||||
return err
|
||||
@ -191,10 +194,11 @@ func (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string
|
||||
}
|
||||
|
||||
ctrl := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{
|
||||
"{Module}": api.Module,
|
||||
"{CtrlName}": fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version)),
|
||||
"{Version}": api.Version,
|
||||
"{MethodName}": api.MethodName,
|
||||
"{Module}": api.Module,
|
||||
"{CtrlName}": fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version)),
|
||||
"{Version}": api.Version,
|
||||
"{MethodName}": api.MethodName,
|
||||
"{MethodComment}": api.GetComment(),
|
||||
}))
|
||||
ctrlFileItem.controllers.WriteString(ctrl)
|
||||
doneApiSet.Add(api.String())
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
@ -179,6 +180,7 @@ func (c *apiSdkGenerator) doGenerateSdkImplementer(
|
||||
"{Version}": item.Version,
|
||||
"{MethodName}": item.MethodName,
|
||||
"{ImplementerName}": implementerName,
|
||||
"{MethodComment}": item.GetComment(),
|
||||
}))
|
||||
implementerFileContent += "\n"
|
||||
}
|
||||
|
@ -14,115 +14,77 @@ import (
|
||||
"golang.org/x/mod/modfile"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/os/gview"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
CGenDaoConfig = `gfcli.gen.dao`
|
||||
CGenDaoUsage = `gf gen dao [OPTION]`
|
||||
CGenDaoBrief = `automatically generate go files for dao/do/entity`
|
||||
CGenDaoEg = `
|
||||
gf gen dao
|
||||
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
|
||||
gf gen dao -r user_
|
||||
`
|
||||
type (
|
||||
CGenDao struct{}
|
||||
CGenDaoInput struct {
|
||||
g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
ShardingPattern []string `name:"shardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenDaoBriefRemoveFieldPrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
|
||||
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
|
||||
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
|
||||
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
|
||||
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
|
||||
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
|
||||
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
|
||||
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
|
||||
CGenDaoAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "order,products"
|
||||
jsonCase: "CamelLower"
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "./my-app"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
typeMapping:
|
||||
decimal:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
numeric:
|
||||
type: string
|
||||
fieldMapping:
|
||||
table_name.field_name:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
`
|
||||
CGenDaoBriefPath = `directory path for generated files`
|
||||
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
|
||||
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenDaoBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
|
||||
CGenDaoBriefWithTime = `add created time for auto produced go files`
|
||||
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
|
||||
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
|
||||
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
|
||||
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
|
||||
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
|
||||
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
|
||||
CGenDaoBriefModelFile = `custom file name for storing generated model content`
|
||||
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
|
||||
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
|
||||
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
|
||||
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
|
||||
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
|
||||
CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenDaoBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`
|
||||
CGenDaoBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
CGenDaoBriefJsonCase = `
|
||||
generated json tag case for model struct, cases are as follows:
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
CGenDaoBriefTplDaoIndexPath = `template file path for dao index file`
|
||||
CGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`
|
||||
CGenDaoBriefTplDaoDoPathPath = `template file path for dao do file`
|
||||
CGenDaoBriefTplDaoEntityPath = `template file path for dao entity file`
|
||||
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"`
|
||||
|
||||
tplVarTableName = `{TplTableName}`
|
||||
tplVarTableNameCamelCase = `{TplTableNameCamelCase}`
|
||||
tplVarTableNameCamelLowerCase = `{TplTableNameCamelLowerCase}`
|
||||
tplVarPackageImports = `{TplPackageImports}`
|
||||
tplVarImportPrefix = `{TplImportPrefix}`
|
||||
tplVarStructDefine = `{TplStructDefine}`
|
||||
tplVarColumnDefine = `{TplColumnDefine}`
|
||||
tplVarColumnNames = `{TplColumnNames}`
|
||||
tplVarGroupName = `{TplGroupName}`
|
||||
tplVarDatetimeStr = `{TplDatetimeStr}`
|
||||
tplVarCreatedAtDatetimeStr = `{TplCreatedAtDatetimeStr}`
|
||||
tplVarPackageName = `{TplPackageName}`
|
||||
// internal usage purpose.
|
||||
genItems *CGenDaoInternalGenItems
|
||||
}
|
||||
CGenDaoOutput struct{}
|
||||
|
||||
CGenDaoInternalInput struct {
|
||||
CGenDaoInput
|
||||
DB gdb.DB
|
||||
TableNames []string
|
||||
NewTableNames []string
|
||||
ShardingTableSet *gset.StrSet
|
||||
}
|
||||
DBTableFieldName = string
|
||||
DBFieldTypeName = string
|
||||
CustomAttributeType struct {
|
||||
Type string `brief:"custom attribute type name"`
|
||||
Import string `brief:"custom import for this type"`
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
createdAt = gtime.Now()
|
||||
tplView = gview.New()
|
||||
defaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{
|
||||
"decimal": {
|
||||
Type: "float64",
|
||||
@ -139,97 +101,6 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenDaoConfig`: CGenDaoConfig,
|
||||
`CGenDaoUsage`: CGenDaoUsage,
|
||||
`CGenDaoBrief`: CGenDaoBrief,
|
||||
`CGenDaoEg`: CGenDaoEg,
|
||||
`CGenDaoAd`: CGenDaoAd,
|
||||
`CGenDaoBriefPath`: CGenDaoBriefPath,
|
||||
`CGenDaoBriefLink`: CGenDaoBriefLink,
|
||||
`CGenDaoBriefTables`: CGenDaoBriefTables,
|
||||
`CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
|
||||
`CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
|
||||
`CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
|
||||
`CGenDaoBriefRemoveFieldPrefix`: CGenDaoBriefRemoveFieldPrefix,
|
||||
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
|
||||
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
|
||||
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
|
||||
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
|
||||
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
|
||||
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
|
||||
`CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
|
||||
`CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
|
||||
`CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
|
||||
`CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
|
||||
`CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
|
||||
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
|
||||
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
|
||||
`CGenDaoBriefClear`: CGenDaoBriefClear,
|
||||
`CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping,
|
||||
`CGenDaoBriefFieldMapping`: CGenDaoBriefFieldMapping,
|
||||
`CGenDaoBriefGroup`: CGenDaoBriefGroup,
|
||||
`CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
|
||||
`CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath,
|
||||
`CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,
|
||||
`CGenDaoBriefTplDaoDoPathPath`: CGenDaoBriefTplDaoDoPathPath,
|
||||
`CGenDaoBriefTplDaoEntityPath`: CGenDaoBriefTplDaoEntityPath,
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
CGenDao struct{}
|
||||
CGenDaoInput struct {
|
||||
g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenDaoBriefRemoveFieldPrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
|
||||
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
|
||||
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
|
||||
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
|
||||
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
|
||||
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
|
||||
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
|
||||
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
|
||||
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"`
|
||||
|
||||
// internal usage purpose.
|
||||
genItems *CGenDaoInternalGenItems
|
||||
}
|
||||
CGenDaoOutput struct{}
|
||||
|
||||
CGenDaoInternalInput struct {
|
||||
CGenDaoInput
|
||||
DB gdb.DB
|
||||
TableNames []string
|
||||
NewTableNames []string
|
||||
}
|
||||
DBTableFieldName = string
|
||||
DBFieldTypeName = string
|
||||
CustomAttributeType struct {
|
||||
Type string `brief:"custom attribute type name"`
|
||||
Import string `brief:"custom import for this type"`
|
||||
}
|
||||
)
|
||||
|
||||
func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
|
||||
in.genItems = newCGenDaoInternalGenItems()
|
||||
if in.Link != "" {
|
||||
@ -278,9 +149,12 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var tempGroup = gtime.TimestampNanoStr()
|
||||
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
err = gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
Link: in.Link,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatalf(`database configuration failed: %+v`, err)
|
||||
}
|
||||
if db, err = gdb.Instance(tempGroup); err != nil {
|
||||
mlog.Fatalf(`database initialization failed: %+v`, err)
|
||||
}
|
||||
@ -321,24 +195,51 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
}
|
||||
|
||||
// Generating dao & model go files one by one according to given table name.
|
||||
newTableNames := make([]string, len(tableNames))
|
||||
var (
|
||||
newTableNames = make([]string, len(tableNames))
|
||||
shardingNewTableSet = gset.NewStrSet()
|
||||
)
|
||||
for i, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
if len(in.ShardingPattern) > 0 {
|
||||
for _, pattern := range in.ShardingPattern {
|
||||
var (
|
||||
match []string
|
||||
regPattern = gstr.Replace(pattern, "?", `(.+)`)
|
||||
)
|
||||
match, err = gregex.MatchString(regPattern, newTableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`invalid sharding pattern "%s": %+v`, pattern, err)
|
||||
}
|
||||
if len(match) < 2 {
|
||||
continue
|
||||
}
|
||||
newTableName = gstr.Replace(pattern, "?", "")
|
||||
newTableName = gstr.Trim(newTableName, `_.-`)
|
||||
if shardingNewTableSet.Contains(newTableName) {
|
||||
tableNames[i] = ""
|
||||
continue
|
||||
}
|
||||
shardingNewTableSet.Add(newTableName)
|
||||
}
|
||||
}
|
||||
newTableName = in.Prefix + newTableName
|
||||
newTableNames[i] = newTableName
|
||||
}
|
||||
tableNames = garray.NewStrArrayFrom(tableNames).FilterEmpty().Slice()
|
||||
|
||||
in.genItems.Scale()
|
||||
|
||||
// Dao: index and internal.
|
||||
generateDao(ctx, CGenDaoInternalInput{
|
||||
CGenDaoInput: in,
|
||||
DB: db,
|
||||
TableNames: tableNames,
|
||||
NewTableNames: newTableNames,
|
||||
CGenDaoInput: in,
|
||||
DB: db,
|
||||
TableNames: tableNames,
|
||||
NewTableNames: newTableNames,
|
||||
ShardingTableSet: shardingNewTableSet,
|
||||
})
|
||||
// Do.
|
||||
generateDo(ctx, CGenDaoInternalInput{
|
||||
@ -411,13 +312,15 @@ func getImportPartContent(ctx context.Context, source string, isDo bool, appendI
|
||||
return packageImportsStr
|
||||
}
|
||||
|
||||
func replaceDefaultVar(in CGenDaoInternalInput, origin string) string {
|
||||
var tplCreatedAtDatetimeStr string
|
||||
var tplDatetimeStr string = createdAt.String()
|
||||
func assignDefaultVar(view *gview.View, in CGenDaoInternalInput) {
|
||||
var (
|
||||
tplCreatedAtDatetimeStr string
|
||||
tplDatetimeStr = createdAt.String()
|
||||
)
|
||||
if in.WithTime {
|
||||
tplCreatedAtDatetimeStr = fmt.Sprintf(`Created at %s`, tplDatetimeStr)
|
||||
}
|
||||
return gstr.ReplaceByMap(origin, g.MapStrStr{
|
||||
view.Assigns(g.Map{
|
||||
tplVarDatetimeStr: tplDatetimeStr,
|
||||
tplVarCreatedAtDatetimeStr: tplCreatedAtDatetimeStr,
|
||||
})
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gview"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
@ -32,22 +33,30 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
)
|
||||
in.genItems.AppendDirPath(dirPathDao)
|
||||
for i := 0; i < len(in.TableNames); i++ {
|
||||
var (
|
||||
realTableName = in.TableNames[i]
|
||||
newTableName = in.NewTableNames[i]
|
||||
)
|
||||
generateDaoSingle(ctx, generateDaoSingleInput{
|
||||
CGenDaoInternalInput: in,
|
||||
TableName: in.TableNames[i],
|
||||
NewTableName: in.NewTableNames[i],
|
||||
TableName: realTableName,
|
||||
NewTableName: newTableName,
|
||||
DirPathDao: dirPathDao,
|
||||
DirPathDaoInternal: dirPathDaoInternal,
|
||||
IsSharding: in.ShardingTableSet.Contains(newTableName),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type generateDaoSingleInput struct {
|
||||
CGenDaoInternalInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
// TableName specifies the table name of the table.
|
||||
TableName string
|
||||
// NewTableName specifies the prefix-stripped or custom edited name of the table.
|
||||
NewTableName string
|
||||
DirPathDao string
|
||||
DirPathDaoInternal string
|
||||
IsSharding bool
|
||||
}
|
||||
|
||||
// generateDaoSingle generates the dao and model content of given table.
|
||||
@ -109,17 +118,26 @@ func generateDaoIndex(in generateDaoIndexInput) {
|
||||
// It should add path to result slice whenever it would generate the path file or not.
|
||||
in.genItems.AppendGeneratedFilePath(path)
|
||||
if in.OverwriteDao || !gfile.Exists(path) {
|
||||
indexContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent),
|
||||
g.MapStrStr{
|
||||
tplVarImportPrefix: in.ImportPrefix,
|
||||
tplVarTableName: in.TableName,
|
||||
tplVarTableNameCamelCase: in.TableNameCamelCase,
|
||||
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
|
||||
tplVarPackageName: filepath.Base(in.DaoPath),
|
||||
})
|
||||
indexContent = replaceDefaultVar(in.CGenDaoInternalInput, indexContent)
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
tplContent = getTemplateFromPathOrDefault(
|
||||
in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent,
|
||||
)
|
||||
)
|
||||
tplView.ClearAssigns()
|
||||
tplView.Assigns(gview.Params{
|
||||
tplVarTableSharding: in.IsSharding,
|
||||
tplVarImportPrefix: in.ImportPrefix,
|
||||
tplVarTableName: in.TableName,
|
||||
tplVarTableNameCamelCase: in.TableNameCamelCase,
|
||||
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
|
||||
tplVarPackageName: filepath.Base(in.DaoPath),
|
||||
})
|
||||
indexContent, err := tplView.ParseContent(ctx, tplContent)
|
||||
if err != nil {
|
||||
mlog.Fatalf("parsing template content failed: %v", err)
|
||||
}
|
||||
if err = gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
utils.GoFmt(path)
|
||||
@ -138,20 +156,29 @@ type generateDaoInternalInput struct {
|
||||
}
|
||||
|
||||
func generateDaoInternal(in generateDaoInternalInput) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
removeFieldPrefixArray = gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
|
||||
tplContent = getTemplateFromPathOrDefault(
|
||||
in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent,
|
||||
)
|
||||
)
|
||||
tplView.ClearAssigns()
|
||||
tplView.Assigns(gview.Params{
|
||||
tplVarImportPrefix: in.ImportPrefix,
|
||||
tplVarTableName: in.TableName,
|
||||
tplVarGroupName: in.Group,
|
||||
tplVarTableNameCamelCase: in.TableNameCamelCase,
|
||||
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
|
||||
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
})
|
||||
assignDefaultVar(tplView, in.CGenDaoInternalInput)
|
||||
modelContent, err := tplView.ParseContent(ctx, tplContent)
|
||||
if err != nil {
|
||||
mlog.Fatalf("parsing template content failed: %v", err)
|
||||
}
|
||||
path := filepath.FromSlash(gfile.Join(in.DirPathDaoInternal, in.FileName+".go"))
|
||||
removeFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
|
||||
modelContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent),
|
||||
g.MapStrStr{
|
||||
tplVarImportPrefix: in.ImportPrefix,
|
||||
tplVarTableName: in.TableName,
|
||||
tplVarGroupName: in.Group,
|
||||
tplVarTableNameCamelCase: in.TableNameCamelCase,
|
||||
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
|
||||
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
})
|
||||
modelContent = replaceDefaultVar(in.CGenDaoInternalInput, modelContent)
|
||||
in.genItems.AppendGeneratedFilePath(path)
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gview"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
@ -78,16 +78,23 @@ func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
func generateDoContent(
|
||||
ctx context.Context, in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string,
|
||||
) string {
|
||||
doContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoDoPath, consts.TemplateGenDaoDoContent),
|
||||
g.MapStrStr{
|
||||
tplVarTableName: tableName,
|
||||
tplVarPackageImports: getImportPartContent(ctx, structDefine, true, nil),
|
||||
tplVarTableNameCamelCase: tableNameCamelCase,
|
||||
tplVarStructDefine: structDefine,
|
||||
tplVarPackageName: filepath.Base(in.DoPath),
|
||||
},
|
||||
var (
|
||||
tplContent = getTemplateFromPathOrDefault(
|
||||
in.TplDaoDoPath, consts.TemplateGenDaoDoContent,
|
||||
)
|
||||
)
|
||||
doContent = replaceDefaultVar(in, doContent)
|
||||
tplView.ClearAssigns()
|
||||
tplView.Assigns(gview.Params{
|
||||
tplVarTableName: tableName,
|
||||
tplVarPackageImports: getImportPartContent(ctx, structDefine, true, nil),
|
||||
tplVarTableNameCamelCase: tableNameCamelCase,
|
||||
tplVarStructDefine: structDefine,
|
||||
tplVarPackageName: filepath.Base(in.DoPath),
|
||||
})
|
||||
assignDefaultVar(tplView, in)
|
||||
doContent, err := tplView.ParseContent(ctx, tplContent)
|
||||
if err != nil {
|
||||
mlog.Fatalf("parsing template content failed: %v", err)
|
||||
}
|
||||
return doContent
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gview"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
@ -63,16 +63,23 @@ func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
func generateEntityContent(
|
||||
ctx context.Context, in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string, appendImports []string,
|
||||
) string {
|
||||
entityContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoEntityPath, consts.TemplateGenDaoEntityContent),
|
||||
g.MapStrStr{
|
||||
tplVarTableName: tableName,
|
||||
tplVarPackageImports: getImportPartContent(ctx, structDefine, false, appendImports),
|
||||
tplVarTableNameCamelCase: tableNameCamelCase,
|
||||
tplVarStructDefine: structDefine,
|
||||
tplVarPackageName: filepath.Base(in.EntityPath),
|
||||
},
|
||||
var (
|
||||
tplContent = getTemplateFromPathOrDefault(
|
||||
in.TplDaoEntityPath, consts.TemplateGenDaoEntityContent,
|
||||
)
|
||||
)
|
||||
entityContent = replaceDefaultVar(in, entityContent)
|
||||
tplView.ClearAssigns()
|
||||
tplView.Assigns(gview.Params{
|
||||
tplVarTableName: tableName,
|
||||
tplVarPackageImports: getImportPartContent(ctx, structDefine, false, appendImports),
|
||||
tplVarTableNameCamelCase: tableNameCamelCase,
|
||||
tplVarStructDefine: structDefine,
|
||||
tplVarPackageName: filepath.Base(in.EntityPath),
|
||||
})
|
||||
assignDefaultVar(tplView, in)
|
||||
entityContent, err := tplView.ParseContent(ctx, tplContent)
|
||||
if err != nil {
|
||||
mlog.Fatalf("parsing template content failed: %v", err)
|
||||
}
|
||||
return entityContent
|
||||
}
|
||||
|
@ -38,14 +38,14 @@ func (i *CGenDaoInternalGenItems) SetClear(clear bool) {
|
||||
i.Items[i.index].Clear = clear
|
||||
}
|
||||
|
||||
func (i CGenDaoInternalGenItems) AppendDirPath(storageDirPath string) {
|
||||
func (i *CGenDaoInternalGenItems) AppendDirPath(storageDirPath string) {
|
||||
i.Items[i.index].StorageDirPaths = append(
|
||||
i.Items[i.index].StorageDirPaths,
|
||||
storageDirPath,
|
||||
)
|
||||
}
|
||||
|
||||
func (i CGenDaoInternalGenItems) AppendGeneratedFilePath(generatedFilePath string) {
|
||||
func (i *CGenDaoInternalGenItems) AppendGeneratedFilePath(generatedFilePath string) {
|
||||
i.Items[i.index].GeneratedFilePaths = append(
|
||||
i.Items[i.index].GeneratedFilePaths,
|
||||
generatedFilePath,
|
||||
|
149
server/internal/library/hggen/internal/cmd/gendao/gendao_tag.go
Normal file
149
server/internal/library/hggen/internal/cmd/gendao/gendao_tag.go
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gendao
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
const (
|
||||
CGenDaoConfig = `gfcli.gen.dao`
|
||||
CGenDaoUsage = `gf gen dao [OPTION]`
|
||||
CGenDaoBrief = `automatically generate go files for dao/do/entity`
|
||||
CGenDaoEg = `
|
||||
gf gen dao
|
||||
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
|
||||
gf gen dao -r user_
|
||||
`
|
||||
|
||||
CGenDaoAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "order,products"
|
||||
jsonCase: "CamelLower"
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "./my-app"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
typeMapping:
|
||||
decimal:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
numeric:
|
||||
type: string
|
||||
fieldMapping:
|
||||
table_name.field_name:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
`
|
||||
CGenDaoBriefPath = `directory path for generated files`
|
||||
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
|
||||
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenDaoBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
|
||||
CGenDaoBriefWithTime = `add created time for auto produced go files`
|
||||
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
|
||||
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
|
||||
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
|
||||
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
|
||||
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
|
||||
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
|
||||
CGenDaoBriefModelFile = `custom file name for storing generated model content`
|
||||
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
|
||||
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
|
||||
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
|
||||
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
|
||||
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
|
||||
CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenDaoBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`
|
||||
CGenDaoBriefShardingPattern = `sharding pattern for table name, e.g. "users_?" will be replace tables "users_001,users_002,..." to "users" dao`
|
||||
CGenDaoBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
CGenDaoBriefJsonCase = `
|
||||
generated json tag case for model struct, cases are as follows:
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
CGenDaoBriefTplDaoIndexPath = `template file path for dao index file`
|
||||
CGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`
|
||||
CGenDaoBriefTplDaoDoPathPath = `template file path for dao do file`
|
||||
CGenDaoBriefTplDaoEntityPath = `template file path for dao entity file`
|
||||
|
||||
tplVarTableName = `TplTableName`
|
||||
tplVarTableNameCamelCase = `TplTableNameCamelCase`
|
||||
tplVarTableNameCamelLowerCase = `TplTableNameCamelLowerCase`
|
||||
tplVarTableSharding = `TplTableSharding`
|
||||
tplVarPackageImports = `TplPackageImports`
|
||||
tplVarImportPrefix = `TplImportPrefix`
|
||||
tplVarStructDefine = `TplStructDefine`
|
||||
tplVarColumnDefine = `TplColumnDefine`
|
||||
tplVarColumnNames = `TplColumnNames`
|
||||
tplVarGroupName = `TplGroupName`
|
||||
tplVarDatetimeStr = `TplDatetimeStr`
|
||||
tplVarCreatedAtDatetimeStr = `TplCreatedAtDatetimeStr`
|
||||
tplVarPackageName = `TplPackageName`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenDaoConfig`: CGenDaoConfig,
|
||||
`CGenDaoUsage`: CGenDaoUsage,
|
||||
`CGenDaoBrief`: CGenDaoBrief,
|
||||
`CGenDaoEg`: CGenDaoEg,
|
||||
`CGenDaoAd`: CGenDaoAd,
|
||||
`CGenDaoBriefPath`: CGenDaoBriefPath,
|
||||
`CGenDaoBriefLink`: CGenDaoBriefLink,
|
||||
`CGenDaoBriefTables`: CGenDaoBriefTables,
|
||||
`CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
|
||||
`CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
|
||||
`CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
|
||||
`CGenDaoBriefRemoveFieldPrefix`: CGenDaoBriefRemoveFieldPrefix,
|
||||
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
|
||||
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
|
||||
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
|
||||
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
|
||||
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
|
||||
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
|
||||
`CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
|
||||
`CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
|
||||
`CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
|
||||
`CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
|
||||
`CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
|
||||
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
|
||||
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
|
||||
`CGenDaoBriefClear`: CGenDaoBriefClear,
|
||||
`CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping,
|
||||
`CGenDaoBriefFieldMapping`: CGenDaoBriefFieldMapping,
|
||||
`CGenDaoBriefShardingPattern`: CGenDaoBriefShardingPattern,
|
||||
`CGenDaoBriefGroup`: CGenDaoBriefGroup,
|
||||
`CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
|
||||
`CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath,
|
||||
`CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,
|
||||
`CGenDaoBriefTplDaoDoPathPath`: CGenDaoBriefTplDaoDoPathPath,
|
||||
`CGenDaoBriefTplDaoEntityPath`: CGenDaoBriefTplDaoEntityPath,
|
||||
})
|
||||
}
|
@ -8,12 +8,14 @@ package genenums
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
@ -22,8 +24,8 @@ type (
|
||||
CGenEnums struct{}
|
||||
CGenEnumsInput struct {
|
||||
g.Meta `name:"enums" config:"{CGenEnumsConfig}" brief:"{CGenEnumsBrief}" eg:"{CGenEnumsEg}"`
|
||||
Src string `name:"src" short:"s" dc:"source folder path to be parsed" d:"."`
|
||||
Path string `name:"path" short:"p" dc:"output go file path storing enums content" d:"internal/boot/boot_enums.go"`
|
||||
Src string `name:"src" short:"s" dc:"source folder path to be parsed" d:"api"`
|
||||
Path string `name:"path" short:"p" dc:"output go file path storing enums content" d:"internal/packed/packed_enums.go"`
|
||||
Prefixes []string `name:"prefixes" short:"x" dc:"only exports packages that starts with specified prefixes"`
|
||||
}
|
||||
CGenEnumsOutput struct{}
|
||||
@ -34,8 +36,8 @@ const (
|
||||
CGenEnumsBrief = `parse go files in current project and generate enums go file`
|
||||
CGenEnumsEg = `
|
||||
gf gen enums
|
||||
gf gen enums -p internal/boot/boot_enums.go
|
||||
gf gen enums -p internal/boot/boot_enums.go -s .
|
||||
gf gen enums -p internal/packed/packed_enums.go
|
||||
gf gen enums -p internal/packed/packed_enums.go -s .
|
||||
gf gen enums -x github.com/gogf
|
||||
`
|
||||
)
|
||||
|
@ -9,6 +9,7 @@ package genenums
|
||||
import (
|
||||
"go/constant"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
@ -71,6 +72,10 @@ func (c CGenPb) doTagReplacement(ctx context.Context, content string) (string, e
|
||||
if !lineTagMap.IsEmpty() {
|
||||
tagContent := c.listMapToStructTag(lineTagMap)
|
||||
lineTagMap.Clear()
|
||||
// If already have it, don't add it anymore
|
||||
if gstr.Contains(gstr.StrTill(line, "` //"), tagContent) {
|
||||
continue
|
||||
}
|
||||
line, _ = gregex.ReplaceString("`(.+)`", fmt.Sprintf("`$1 %s`", tagContent), line)
|
||||
}
|
||||
lines[index] = line
|
||||
|
@ -11,11 +11,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
@ -25,8 +27,10 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -35,14 +39,19 @@ type (
|
||||
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
|
||||
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
|
||||
GoPackage string `name:"goPackage" short:"g" brief:"{CGenPbEntityBriefGoPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenPbEntityBriefRemoveFieldPrefix}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"none"`
|
||||
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
|
||||
|
||||
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenPbEntityBriefTypeMapping}" orphan:"true"`
|
||||
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenPbEntityBriefFieldMapping}" orphan:"true"`
|
||||
}
|
||||
CGenPbEntityOutput struct{}
|
||||
|
||||
@ -52,6 +61,13 @@ type (
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
|
||||
DBTableFieldName = string
|
||||
DBFieldTypeName = string
|
||||
CustomAttributeType struct {
|
||||
Type string `brief:"custom attribute type name"`
|
||||
Import string `brief:"custom import for this type"`
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
@ -88,13 +104,22 @@ CONFIGURATION SUPPORT
|
||||
option go_package = "protobuf/demos";
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
typeMapping:
|
||||
json:
|
||||
type: google.protobuf.Value
|
||||
import: google/protobuf/struct.proto
|
||||
jsonb:
|
||||
type: google.protobuf.Value
|
||||
import: google/protobuf/struct.proto
|
||||
`
|
||||
CGenPbEntityBriefPath = `directory path for generated files storing`
|
||||
CGenPbEntityBriefPackage = `package path for all entity proto files`
|
||||
CGenPbEntityBriefGoPackage = `go package path for all entity proto files`
|
||||
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefTablesEx = `generate all models exclude the specified tables, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefOption = `extra protobuf options`
|
||||
CGenPbEntityBriefGroup = `
|
||||
@ -119,8 +144,95 @@ case for message attribute names, default is "Camel":
|
||||
case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
`
|
||||
|
||||
CGenPbEntityBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenPbEntityBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`
|
||||
)
|
||||
|
||||
var defaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{
|
||||
// gdb.LocalTypeString
|
||||
"string": {
|
||||
Type: "string",
|
||||
},
|
||||
// gdb.LocalTypeTime
|
||||
// "time": {
|
||||
// Type: "google.protobuf.Duration",
|
||||
// Import: "google/protobuf/duration.proto",
|
||||
// },
|
||||
// gdb.LocalTypeDate
|
||||
"date": {
|
||||
Type: "google.protobuf.Timestamp",
|
||||
Import: "google/protobuf/timestamp.proto",
|
||||
},
|
||||
// gdb.LocalTypeDatetime
|
||||
"datetime": {
|
||||
Type: "google.protobuf.Timestamp",
|
||||
Import: "google/protobuf/timestamp.proto",
|
||||
},
|
||||
// gdb.LocalTypeInt
|
||||
"int": {
|
||||
Type: "int32",
|
||||
},
|
||||
// gdb.LocalTypeUint
|
||||
"uint": {
|
||||
Type: "uint32",
|
||||
},
|
||||
// gdb.LocalTypeInt64
|
||||
"int64": {
|
||||
Type: "int64",
|
||||
},
|
||||
// gdb.LocalTypeUint64
|
||||
"uint64": {
|
||||
Type: "uint64",
|
||||
},
|
||||
// gdb.LocalTypeIntSlice
|
||||
"[]int": {
|
||||
Type: "repeated int32",
|
||||
},
|
||||
// gdb.LocalTypeInt64Slice
|
||||
"[]int64": {
|
||||
Type: "repeated int64",
|
||||
},
|
||||
// gdb.LocalTypeUint64Slice
|
||||
"[]uint64": {
|
||||
Type: "repeated uint64",
|
||||
},
|
||||
// gdb.LocalTypeInt64Bytes
|
||||
"int64-bytes": {
|
||||
Type: "repeated int64",
|
||||
},
|
||||
// gdb.LocalTypeUint64Bytes
|
||||
"uint64-bytes": {
|
||||
Type: "repeated uint64",
|
||||
},
|
||||
// gdb.LocalTypeFloat32
|
||||
"float32": {
|
||||
Type: "float",
|
||||
},
|
||||
// gdb.LocalTypeFloat64
|
||||
"float64": {
|
||||
Type: "double",
|
||||
},
|
||||
// gdb.LocalTypeBytes
|
||||
"[]byte": {
|
||||
Type: "bytes",
|
||||
},
|
||||
// gdb.LocalTypeBool
|
||||
"bool": {
|
||||
Type: "bool",
|
||||
},
|
||||
// gdb.LocalTypeJson
|
||||
// "json": {
|
||||
// Type: "google.protobuf.Value",
|
||||
// Import: "google/protobuf/struct.proto",
|
||||
// },
|
||||
// gdb.LocalTypeJsonb
|
||||
// "jsonb": {
|
||||
// Type: "google.protobuf.Value",
|
||||
// Import: "google/protobuf/struct.proto",
|
||||
// },
|
||||
}
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEntityConfig`: CGenPbEntityConfig,
|
||||
@ -129,15 +241,19 @@ func init() {
|
||||
`CGenPbEntityAd`: CGenPbEntityAd,
|
||||
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
|
||||
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
|
||||
`CGenPbEntityBriefGoPackage`: CGenPbEntityBriefGoPackage,
|
||||
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
|
||||
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
|
||||
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
|
||||
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
|
||||
`CGenPbEntityBriefTablesEx`: CGenPbEntityBriefTablesEx,
|
||||
`CGenPbEntityBriefRemoveFieldPrefix`: CGenPbEntityBriefRemoveFieldPrefix,
|
||||
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
|
||||
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
|
||||
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
|
||||
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
|
||||
`CGenPbEntityBriefTypeMapping`: CGenPbEntityBriefTypeMapping,
|
||||
`CGenPbEntityBriefFieldMapping`: CGenPbEntityBriefFieldMapping,
|
||||
})
|
||||
}
|
||||
|
||||
@ -181,6 +297,9 @@ func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput)
|
||||
in.Package = modName + "/" + defaultPackageSuffix
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
|
||||
excludeTables := gset.NewStrSetFrom(gstr.SplitAndTrim(in.TablesEx, ","))
|
||||
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var (
|
||||
@ -210,8 +329,21 @@ func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput)
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
// merge default typeMapping to input typeMapping.
|
||||
if in.TypeMapping == nil {
|
||||
in.TypeMapping = defaultTypeMapping
|
||||
} else {
|
||||
for key, typeMapping := range defaultTypeMapping {
|
||||
if _, ok := in.TypeMapping[key]; !ok {
|
||||
in.TypeMapping[key] = typeMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
if excludeTables.Contains(tableName) {
|
||||
continue
|
||||
}
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
@ -234,20 +366,29 @@ func generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInp
|
||||
// Change the `newTableName` if `Prefix` is given.
|
||||
newTableName := in.Prefix + in.NewTableName
|
||||
var (
|
||||
imports string
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = filepath.FromSlash(gfile.Join(in.Path, fileName+".proto"))
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine, appendImports = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = filepath.FromSlash(gfile.Join(in.Path, fileName+".proto"))
|
||||
)
|
||||
if gstr.Contains(entityMessageDefine, "google.protobuf.Timestamp") {
|
||||
imports = `import "google/protobuf/timestamp.proto";`
|
||||
packageImportStr := ""
|
||||
var packageImportsArray = garray.NewStrArray()
|
||||
if len(appendImports) > 0 {
|
||||
for _, appendImport := range appendImports {
|
||||
packageImportStr = fmt.Sprintf(`import "%s";`, appendImport)
|
||||
if packageImportsArray.Search(packageImportStr) == -1 {
|
||||
packageImportsArray.Append(packageImportStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.GoPackage == "" {
|
||||
in.GoPackage = in.Package
|
||||
}
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
|
||||
"{Imports}": imports,
|
||||
"{Imports}": packageImportsArray.Join("\n"),
|
||||
"{PackageName}": gfile.Basename(in.Package),
|
||||
"{GoPackage}": in.Package,
|
||||
"{GoPackage}": in.GoPackage,
|
||||
"{OptionContent}": in.Option,
|
||||
"{EntityMessage}": entityMessageDefine,
|
||||
})
|
||||
@ -259,14 +400,19 @@ func generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInp
|
||||
}
|
||||
|
||||
// generateEntityMessageDefinition generates and returns the message definition for specified table.
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) string {
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) (string, []string) {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
appendImports []string
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
var imports string
|
||||
array[index], imports = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
if imports != "" {
|
||||
appendImports = append(appendImports, imports)
|
||||
}
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
@ -277,48 +423,38 @@ func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
stContent = regexp.MustCompile(`\s+\n`).ReplaceAllString(gstr.Replace(stContent, " #", ""), "\n")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
return buffer.String(), appendImports
|
||||
}
|
||||
|
||||
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) []string {
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) (attrLines []string, appendImport string) {
|
||||
var (
|
||||
localTypeName gdb.LocalType
|
||||
comment string
|
||||
jsonTagStr string
|
||||
err error
|
||||
ctx = gctx.GetInitCtx()
|
||||
localTypeNameStr string
|
||||
localTypeName gdb.LocalType
|
||||
comment string
|
||||
jsonTagStr string
|
||||
err error
|
||||
ctx = gctx.GetInitCtx()
|
||||
)
|
||||
localTypeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
if in.TypeMapping != nil && len(in.TypeMapping) > 0 {
|
||||
localTypeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if localTypeName != "" {
|
||||
if typeMapping, ok := in.TypeMapping[strings.ToLower(string(localTypeName))]; ok {
|
||||
localTypeNameStr = typeMapping.Type
|
||||
appendImport = typeMapping.Import
|
||||
}
|
||||
}
|
||||
}
|
||||
var typeMapping = map[gdb.LocalType]string{
|
||||
gdb.LocalTypeString: "string",
|
||||
gdb.LocalTypeDate: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeDatetime: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeInt: "int32",
|
||||
gdb.LocalTypeUint: "uint32",
|
||||
gdb.LocalTypeInt64: "int64",
|
||||
gdb.LocalTypeUint64: "uint64",
|
||||
gdb.LocalTypeIntSlice: "repeated int32",
|
||||
gdb.LocalTypeInt64Slice: "repeated int64",
|
||||
gdb.LocalTypeUint64Slice: "repeated uint64",
|
||||
gdb.LocalTypeInt64Bytes: "repeated int64",
|
||||
gdb.LocalTypeUint64Bytes: "repeated uint64",
|
||||
gdb.LocalTypeFloat32: "float",
|
||||
gdb.LocalTypeFloat64: "double",
|
||||
gdb.LocalTypeBytes: "bytes",
|
||||
gdb.LocalTypeBool: "bool",
|
||||
gdb.LocalTypeJson: "string",
|
||||
gdb.LocalTypeJsonb: "string",
|
||||
}
|
||||
localTypeNameStr := typeMapping[localTypeName]
|
||||
|
||||
if localTypeNameStr == "" {
|
||||
localTypeNameStr = "string"
|
||||
}
|
||||
@ -351,12 +487,19 @@ func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPb
|
||||
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
|
||||
}
|
||||
|
||||
if in.FieldMapping != nil && len(in.FieldMapping) > 0 {
|
||||
if typeMapping, ok := in.FieldMapping[fmt.Sprintf("%s.%s", in.TableName, newFiledName)]; ok {
|
||||
localTypeNameStr = typeMapping.Type
|
||||
appendImport = typeMapping.Import
|
||||
}
|
||||
}
|
||||
|
||||
return []string{
|
||||
" #" + localTypeNameStr,
|
||||
" #" + formatCase(newFiledName, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}, appendImport
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
|
@ -94,6 +94,20 @@ const (
|
||||
genServiceFileLockSeconds = 10
|
||||
)
|
||||
|
||||
type fileInfo struct {
|
||||
PkgItems []pkgItem
|
||||
FuncItems []funcItem
|
||||
}
|
||||
|
||||
type folderInfo struct {
|
||||
SrcPackageName string
|
||||
SrcImportedPackages *garray.SortedStrArray
|
||||
SrcStructFunctions *gmap.ListMap
|
||||
DstFilePath string
|
||||
|
||||
FileInfos []*fileInfo
|
||||
}
|
||||
|
||||
func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGenServiceOutput, err error) {
|
||||
in.SrcFolder = filepath.ToSlash(in.SrcFolder)
|
||||
in.SrcFolder = gstr.TrimRight(in.SrcFolder, `/`)
|
||||
@ -163,7 +177,12 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
return nil, err
|
||||
}
|
||||
// it will use goroutine to generate service files for each package.
|
||||
var wg = sync.WaitGroup{}
|
||||
var (
|
||||
folderInfos []folderInfo
|
||||
wg = sync.WaitGroup{}
|
||||
allStructItems = make(map[string][]string)
|
||||
)
|
||||
|
||||
for _, srcFolderPath := range srcFolderPaths {
|
||||
if !gfile.IsDir(srcFolderPath) {
|
||||
continue
|
||||
@ -175,7 +194,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
if len(files) == 0 {
|
||||
continue
|
||||
}
|
||||
// Parse single logic package folder.
|
||||
|
||||
var (
|
||||
srcPackageName = gfile.Basename(srcFolderPath)
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
@ -184,14 +203,46 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
c.getDstFileNameCase(srcPackageName, in.DstFileNameCase)+".go",
|
||||
)
|
||||
)
|
||||
generatedDstFilePathSet.Add(dstFilePath)
|
||||
// if it were to use goroutine,
|
||||
// it would cause the order of the generated functions in the file to be disordered.
|
||||
|
||||
folder := folderInfo{
|
||||
SrcPackageName: srcPackageName,
|
||||
SrcImportedPackages: srcImportedPackages,
|
||||
SrcStructFunctions: srcStructFunctions,
|
||||
DstFilePath: dstFilePath,
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
pkgItems, funcItems, err := c.parseItemsInSrc(file)
|
||||
pkgItems, structItems, funcItems, err := c.parseItemsInSrc(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range structItems {
|
||||
allStructItems[k] = v
|
||||
}
|
||||
folder.FileInfos = append(folder.FileInfos, &fileInfo{
|
||||
PkgItems: pkgItems,
|
||||
FuncItems: funcItems,
|
||||
})
|
||||
}
|
||||
|
||||
folderInfos = append(folderInfos, folder)
|
||||
}
|
||||
|
||||
folderInfos = c.calculateStructEmbeddedFuncInfos(folderInfos, allStructItems)
|
||||
|
||||
for _, folder := range folderInfos {
|
||||
// Parse single logic package folder.
|
||||
var (
|
||||
srcPackageName = folder.SrcPackageName
|
||||
srcImportedPackages = folder.SrcImportedPackages
|
||||
srcStructFunctions = folder.SrcStructFunctions
|
||||
dstFilePath = folder.DstFilePath
|
||||
)
|
||||
generatedDstFilePathSet.Add(dstFilePath)
|
||||
// if it were to use goroutine,
|
||||
// it would cause the order of the generated functions in the file to be disordered.
|
||||
for _, file := range folder.FileInfos {
|
||||
pkgItems, funcItems := file.PkgItems, file.FuncItems
|
||||
|
||||
// Calculate imported packages for service generating.
|
||||
err = c.calculateImportedItems(in, pkgItems, funcItems, srcImportedPackages)
|
||||
|
@ -10,8 +10,10 @@ import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gstructs"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
@ -32,7 +34,7 @@ type funcItem struct {
|
||||
// parseItemsInSrc parses the pkgItem and funcItem from the specified file.
|
||||
// It can't skip the private methods.
|
||||
// It can't skip the imported packages of import alias equal to `_`.
|
||||
func (c CGenService) parseItemsInSrc(filePath string) (pkgItems []pkgItem, funcItems []funcItem, err error) {
|
||||
func (c CGenService) parseItemsInSrc(filePath string) (pkgItems []pkgItem, structItems map[string][]string, funcItems []funcItem, err error) {
|
||||
var (
|
||||
fileContent = gfile.GetContents(filePath)
|
||||
fileSet = token.NewFileSet()
|
||||
@ -43,11 +45,107 @@ func (c CGenService) parseItemsInSrc(filePath string) (pkgItems []pkgItem, funcI
|
||||
return
|
||||
}
|
||||
|
||||
structItems = make(map[string][]string)
|
||||
pkg := node.Name.Name
|
||||
pkgAliasMap := make(map[string]string)
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
switch x := n.(type) {
|
||||
case *ast.ImportSpec:
|
||||
// parse the imported packages.
|
||||
pkgItems = append(pkgItems, c.parseImportPackages(x))
|
||||
pkgItem := c.parseImportPackages(x)
|
||||
pkgItems = append(pkgItems, pkgItem)
|
||||
pkgPath := strings.Trim(pkgItem.Path, "\"")
|
||||
pkgPath = strings.ReplaceAll(pkgPath, "\\", "/")
|
||||
tmp := strings.Split(pkgPath, "/")
|
||||
srcPkg := tmp[len(tmp)-1]
|
||||
if srcPkg != pkgItem.Alias {
|
||||
pkgAliasMap[pkgItem.Alias] = srcPkg
|
||||
}
|
||||
case *ast.TypeSpec: // type define
|
||||
switch xType := x.Type.(type) {
|
||||
case *ast.StructType: // define struct
|
||||
// parse the struct declaration.
|
||||
var structName = pkg + "." + x.Name.Name
|
||||
var structEmbeddedStruct []string
|
||||
for _, field := range xType.Fields.List {
|
||||
if len(field.Names) > 0 || field.Tag == nil { // not anonymous field
|
||||
continue
|
||||
}
|
||||
|
||||
tagValue := strings.Trim(field.Tag.Value, "`")
|
||||
tagValue = strings.TrimSpace(tagValue)
|
||||
if len(tagValue) == 0 { // not set tag
|
||||
continue
|
||||
}
|
||||
tags := gstructs.ParseTag(tagValue)
|
||||
|
||||
if v, ok := tags["gen"]; !ok || v != "extend" {
|
||||
continue
|
||||
}
|
||||
|
||||
var embeddedStruct string
|
||||
switch v := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
if embeddedStruct, err = c.astExprToString(v); err != nil {
|
||||
embeddedStruct = ""
|
||||
break
|
||||
}
|
||||
embeddedStruct = pkg + "." + embeddedStruct
|
||||
case *ast.StarExpr:
|
||||
if embeddedStruct, err = c.astExprToString(v.X); err != nil {
|
||||
embeddedStruct = ""
|
||||
break
|
||||
}
|
||||
embeddedStruct = pkg + "." + embeddedStruct
|
||||
case *ast.SelectorExpr:
|
||||
var pkg string
|
||||
if pkg, err = c.astExprToString(v.X); err != nil {
|
||||
embeddedStruct = ""
|
||||
break
|
||||
}
|
||||
if v, ok := pkgAliasMap[pkg]; ok {
|
||||
pkg = v
|
||||
}
|
||||
if embeddedStruct, err = c.astExprToString(v.Sel); err != nil {
|
||||
embeddedStruct = ""
|
||||
break
|
||||
}
|
||||
embeddedStruct = pkg + "." + embeddedStruct
|
||||
}
|
||||
|
||||
if embeddedStruct == "" {
|
||||
continue
|
||||
}
|
||||
structEmbeddedStruct = append(structEmbeddedStruct, embeddedStruct)
|
||||
|
||||
}
|
||||
if len(structEmbeddedStruct) > 0 {
|
||||
structItems[structName] = structEmbeddedStruct
|
||||
}
|
||||
case *ast.Ident: // define ident
|
||||
var (
|
||||
structName = pkg + "." + x.Name.Name
|
||||
typeName = pkg + "." + xType.Name
|
||||
)
|
||||
structItems[structName] = []string{typeName}
|
||||
case *ast.SelectorExpr: // define selector
|
||||
var (
|
||||
structName = pkg + "." + x.Name.Name
|
||||
selecotrPkg string
|
||||
typeName string
|
||||
)
|
||||
if selecotrPkg, err = c.astExprToString(xType.X); err != nil {
|
||||
break
|
||||
}
|
||||
if v, ok := pkgAliasMap[selecotrPkg]; ok {
|
||||
selecotrPkg = v
|
||||
}
|
||||
if typeName, err = c.astExprToString(xType.Sel); err != nil {
|
||||
break
|
||||
}
|
||||
typeName = selecotrPkg + "." + typeName
|
||||
structItems[structName] = []string{typeName}
|
||||
}
|
||||
|
||||
case *ast.FuncDecl:
|
||||
// parse the function items.
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
)
|
||||
|
||||
@ -150,3 +151,78 @@ func (c CGenService) tidyResult(resultSlice []map[string]string) (resultStr stri
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenService) getStructFuncItems(structName string, allStructItems map[string][]string, funcItemsWithoutEmbed map[string][]*funcItem) (funcItems []*funcItem) {
|
||||
funcItemNameSet := map[string]struct{}{}
|
||||
|
||||
if items, ok := funcItemsWithoutEmbed[structName]; ok {
|
||||
funcItems = append(funcItems, items...)
|
||||
for _, item := range items {
|
||||
funcItemNameSet[item.MethodName] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
embeddedStructNames, ok := allStructItems[structName]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, embeddedStructName := range embeddedStructNames {
|
||||
items := c.getStructFuncItems(embeddedStructName, allStructItems, funcItemsWithoutEmbed)
|
||||
|
||||
for _, item := range items {
|
||||
if _, ok := funcItemNameSet[item.MethodName]; ok {
|
||||
continue
|
||||
}
|
||||
funcItemNameSet[item.MethodName] = struct{}{}
|
||||
funcItems = append(funcItems, item)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenService) calculateStructEmbeddedFuncInfos(folderInfos []folderInfo, allStructItems map[string][]string) (newFolerInfos []folderInfo) {
|
||||
funcItemsWithoutEmbed := make(map[string][]*funcItem)
|
||||
funcItemMap := make(map[string]*([]funcItem))
|
||||
funcItemsWithoutEmbedMap := make(map[string]*funcItem)
|
||||
|
||||
newFolerInfos = append(newFolerInfos, folderInfos...)
|
||||
|
||||
for _, folder := range newFolerInfos {
|
||||
for k := range folder.FileInfos {
|
||||
fi := folder.FileInfos[k]
|
||||
for k := range fi.FuncItems {
|
||||
item := &fi.FuncItems[k]
|
||||
receiver := folder.SrcPackageName + "." + strings.ReplaceAll(item.Receiver, "*", "")
|
||||
funcItemMap[receiver] = &fi.FuncItems
|
||||
funcItemsWithoutEmbed[receiver] = append(funcItemsWithoutEmbed[receiver], item)
|
||||
funcItemsWithoutEmbedMap[fmt.Sprintf("%s:%s", receiver, item.MethodName)] = item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for receiver, structItems := range allStructItems {
|
||||
receiverName := strings.ReplaceAll(receiver, "*", "")
|
||||
for _, structName := range structItems {
|
||||
// Get the list of methods for the corresponding structName.
|
||||
for _, funcItem := range c.getStructFuncItems(structName, allStructItems, funcItemsWithoutEmbed) {
|
||||
if _, ok := funcItemsWithoutEmbedMap[fmt.Sprintf("%s:%s", receiverName, funcItem.MethodName)]; ok {
|
||||
continue
|
||||
}
|
||||
if funcItemsPtr, ok := funcItemMap[receiverName]; ok {
|
||||
newFuncItem := *funcItem
|
||||
newFuncItem.Receiver = getReceiverName(receiver)
|
||||
(*funcItemsPtr) = append((*funcItemsPtr), newFuncItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getReceiverName(receiver string) string {
|
||||
ss := strings.Split(receiver, ".")
|
||||
return ss[len(ss)-1]
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/consts"
|
||||
)
|
||||
|
||||
|
@ -45,7 +45,7 @@ import (
|
||||
|
||||
"{ImportPath}"
|
||||
)
|
||||
|
||||
{MethodComment}
|
||||
func (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
@ -66,7 +66,7 @@ import (
|
||||
`
|
||||
|
||||
const TemplateGenCtrlControllerMethodFuncMerge = `
|
||||
|
||||
{MethodComment}
|
||||
func (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func (i *implementer) {ImplementerName}() {Module}.I{ImplementerName} {
|
||||
|
||||
`
|
||||
|
||||
const TemplateGenCtrlSdkImplementerFunc = `
|
||||
const TemplateGenCtrlSdkImplementerFunc = `{MethodComment}
|
||||
func (i *implementer{ImplementerName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
|
||||
err = i.Request(ctx, req, &res)
|
||||
return
|
||||
|
@ -8,38 +8,57 @@ package consts
|
||||
|
||||
const TemplateGenDaoIndexContent = `
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package {TplPackageName}
|
||||
package {{.TplPackageName}}
|
||||
|
||||
import (
|
||||
"{TplImportPrefix}/internal"
|
||||
"{{.TplImportPrefix}}/internal"
|
||||
)
|
||||
|
||||
// internal{TplTableNameCamelCase}Dao is internal type for wrapping internal DAO implements.
|
||||
type internal{TplTableNameCamelCase}Dao = *internal.{TplTableNameCamelCase}Dao
|
||||
|
||||
// {TplTableNameCamelLowerCase}Dao is the data access object for table {TplTableName}.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type {TplTableNameCamelLowerCase}Dao struct {
|
||||
internal{TplTableNameCamelCase}Dao
|
||||
// {{.TplTableNameCamelLowerCase}}Dao is the data access object for the table {{.TplTableName}}.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type {{.TplTableNameCamelLowerCase}}Dao struct {
|
||||
*internal.{{.TplTableNameCamelCase}}Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// {TplTableNameCamelCase} is globally public accessible object for table {TplTableName} operations.
|
||||
{TplTableNameCamelCase} = {TplTableNameCamelLowerCase}Dao{
|
||||
internal.New{TplTableNameCamelCase}Dao(),
|
||||
// {{.TplTableNameCamelCase}} is a globally accessible object for table {{.TplTableName}} operations.
|
||||
{{.TplTableNameCamelCase}} = {{.TplTableNameCamelLowerCase}}Dao{
|
||||
{{- if .TplTableSharding -}}
|
||||
internal.New{{.TplTableNameCamelCase}}Dao(userShardingHandler),
|
||||
{{- else -}}
|
||||
internal.New{{.TplTableNameCamelCase}}Dao(),
|
||||
{{- end -}}
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
||||
{{if .TplTableSharding -}}
|
||||
// userShardingHandler is the handler for sharding operations.
|
||||
// You can fill this sharding handler with your custom implementation.
|
||||
func userShardingHandler(m *gdb.Model) *gdb.Model {
|
||||
m = m.Sharding(gdb.ShardingConfig{
|
||||
Table: gdb.ShardingTableConfig{
|
||||
Enable: true,
|
||||
Prefix: "",
|
||||
// Replace Rule field with your custom sharding rule.
|
||||
// Or you can use "&gdb.DefaultShardingRule{}" for default sharding rule.
|
||||
Rule: nil,
|
||||
},
|
||||
Schema: gdb.ShardingSchemaConfig{},
|
||||
})
|
||||
return m
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
|
||||
`
|
||||
|
||||
const TemplateGenDaoInternalContent = `
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
@ -51,64 +70,70 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// {TplTableNameCamelCase}Dao is the data access object for table {TplTableName}.
|
||||
type {TplTableNameCamelCase}Dao struct {
|
||||
// {{.TplTableNameCamelCase}}Dao is the data access object for the table {{.TplTableName}}.
|
||||
type {{.TplTableNameCamelCase}}Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns {TplTableNameCamelCase}Columns // columns contains all the column names of Table for convenient usage.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns {{.TplTableNameCamelCase}}Columns // columns contains all the column names of Table for convenient usage.
|
||||
handlers []gdb.ModelHandler // handlers for customized model modification.
|
||||
}
|
||||
|
||||
// {TplTableNameCamelCase}Columns defines and stores column names for table {TplTableName}.
|
||||
type {TplTableNameCamelCase}Columns struct {
|
||||
{TplColumnDefine}
|
||||
// {{.TplTableNameCamelCase}}Columns defines and stores column names for the table {{.TplTableName}}.
|
||||
type {{.TplTableNameCamelCase}}Columns struct {
|
||||
{{.TplColumnDefine}}
|
||||
}
|
||||
|
||||
// {TplTableNameCamelLowerCase}Columns holds the columns for table {TplTableName}.
|
||||
var {TplTableNameCamelLowerCase}Columns = {TplTableNameCamelCase}Columns{
|
||||
{TplColumnNames}
|
||||
// {{.TplTableNameCamelLowerCase}}Columns holds the columns for the table {{.TplTableName}}.
|
||||
var {{.TplTableNameCamelLowerCase}}Columns = {{.TplTableNameCamelCase}}Columns{
|
||||
{{.TplColumnNames}}
|
||||
}
|
||||
|
||||
// New{TplTableNameCamelCase}Dao creates and returns a new DAO object for table data access.
|
||||
func New{TplTableNameCamelCase}Dao() *{TplTableNameCamelCase}Dao {
|
||||
return &{TplTableNameCamelCase}Dao{
|
||||
group: "{TplGroupName}",
|
||||
table: "{TplTableName}",
|
||||
columns: {TplTableNameCamelLowerCase}Columns,
|
||||
// New{{.TplTableNameCamelCase}}Dao creates and returns a new DAO object for table data access.
|
||||
func New{{.TplTableNameCamelCase}}Dao(handlers ...gdb.ModelHandler) *{{.TplTableNameCamelCase}}Dao {
|
||||
return &{{.TplTableNameCamelCase}}Dao{
|
||||
group: "{{.TplGroupName}}",
|
||||
table: "{{.TplTableName}}",
|
||||
columns: {{.TplTableNameCamelLowerCase}}Columns,
|
||||
handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *{TplTableNameCamelCase}Dao) DB() gdb.DB {
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Table() string {
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Columns() {TplTableNameCamelCase}Columns {
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) Columns() {{.TplTableNameCamelCase}}Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Group() string {
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
model := dao.DB().Model(dao.table)
|
||||
for _, handler := range dao.handlers {
|
||||
model = handler(model)
|
||||
}
|
||||
return model.Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It rolls back the transaction and returns the error if function f returns a non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
func (dao *{{.TplTableNameCamelCase}}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
`
|
||||
|
@ -8,13 +8,13 @@ package consts
|
||||
|
||||
const TemplateGenDaoDoContent = `
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
|
||||
// =================================================================================
|
||||
|
||||
package {TplPackageName}
|
||||
package {{.TplPackageName}}
|
||||
|
||||
{TplPackageImports}
|
||||
{{.TplPackageImports}}
|
||||
|
||||
// {TplTableNameCamelCase} is the golang structure of table {TplTableName} for DAO operations like Where/Data.
|
||||
{TplStructDefine}
|
||||
// {{.TplTableNameCamelCase}} is the golang structure of table {{.TplTableName}} for DAO operations like Where/Data.
|
||||
{{.TplStructDefine}}
|
||||
`
|
||||
|
@ -8,13 +8,13 @@ package consts
|
||||
|
||||
const TemplateGenDaoEntityContent = `
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
|
||||
// =================================================================================
|
||||
|
||||
package {TplPackageName}
|
||||
package {{.TplPackageName}}
|
||||
|
||||
{TplPackageImports}
|
||||
{{.TplPackageImports}}
|
||||
|
||||
// {TplTableNameCamelCase} is the golang structure for table {TplTableName}.
|
||||
{TplStructDefine}
|
||||
// {{.TplTableNameCamelCase}} is the golang structure for table {{.TplTableName}}.
|
||||
{{.TplStructDefine}}
|
||||
`
|
||||
|
@ -162,8 +162,14 @@ func (s serviceInstall) getGoPathBin() string {
|
||||
func (s serviceInstall) getAvailablePaths() []serviceInstallAvailablePath {
|
||||
var (
|
||||
folderPaths []serviceInstallAvailablePath
|
||||
binaryFileName = "gf" + gfile.Ext(gfile.SelfPath())
|
||||
binaryFileName = "gf"
|
||||
)
|
||||
|
||||
// Windows binary file name suffix.
|
||||
if runtime.GOOS == "windows" {
|
||||
binaryFileName += ".exe"
|
||||
}
|
||||
|
||||
// $GOPATH/bin
|
||||
if goPathBin := s.getGoPathBin(); goPathBin != "" {
|
||||
folderPaths = s.checkAndAppendToAvailablePath(
|
||||
|
@ -7,13 +7,13 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/schollz/progressbar/v3"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
@ -34,26 +34,16 @@ func HTTPDownloadFileWithPercent(url string, localSaveFilePath string) error {
|
||||
}
|
||||
defer headResp.Body.Close()
|
||||
|
||||
size, err := strconv.Atoi(headResp.Header.Get("Content-Length"))
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "retrieve Content-Length failed")
|
||||
}
|
||||
doneCh := make(chan int64)
|
||||
|
||||
go doPrintDownloadPercent(doneCh, localSaveFilePath, int64(size))
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wroteBytesCount, err := io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
bar := progressbar.NewOptions(int(resp.ContentLength), progressbar.OptionShowBytes(true), progressbar.OptionShowCount())
|
||||
writer := io.MultiWriter(out, bar)
|
||||
_, err = io.Copy(writer, resp.Body)
|
||||
|
||||
doneCh <- wroteBytesCount
|
||||
elapsed := time.Since(start)
|
||||
if elapsed > time.Minute {
|
||||
mlog.Printf(`download completed in %.0fm`, float64(elapsed)/float64(time.Minute))
|
||||
@ -63,45 +53,3 @@ func HTTPDownloadFileWithPercent(url string, localSaveFilePath string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func doPrintDownloadPercent(doneCh chan int64, localSaveFilePath string, total int64) {
|
||||
var (
|
||||
stop = false
|
||||
lastPercentFmt string
|
||||
)
|
||||
file, err := os.Open(localSaveFilePath)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-doneCh:
|
||||
stop = true
|
||||
|
||||
default:
|
||||
fi, err := file.Stat()
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
size = 1
|
||||
}
|
||||
var (
|
||||
percent = float64(size) / float64(total) * 100
|
||||
percentFmt = fmt.Sprintf(`%.0f`, percent) + "%"
|
||||
)
|
||||
if lastPercentFmt != percentFmt {
|
||||
lastPercentFmt = percentFmt
|
||||
mlog.Print(percentFmt)
|
||||
}
|
||||
}
|
||||
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
|
@ -403,7 +403,7 @@ func (l *gCurd) loadView(ctx context.Context, in *CurdPreviewInput) (err error)
|
||||
"importWebApi": in.options.ImportWebApi, // 导入webApi
|
||||
"apiPrefix": in.options.ApiPrefix, // api前缀
|
||||
"componentPrefix": componentPrefix, // vue子组件前缀
|
||||
"in": in.In, // 在模版中使用`in`参数,如:插件目录名称
|
||||
"in": in.In, // 在模版中使用`in`参数,如:插件目录名称
|
||||
})
|
||||
|
||||
in.view = view
|
||||
@ -453,7 +453,7 @@ func (l *gCurd) DoBuild(ctx context.Context, in *CurdBuildInput) (err error) {
|
||||
|
||||
// 导入失败,将sql文件删除
|
||||
if err = ImportSql(ctx, vi.Path); err != nil {
|
||||
_ = gfile.Remove(vi.Path)
|
||||
_ = gfile.RemoveAll(vi.Path)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ var MemberSummary = gdb.HookHandler{
|
||||
}
|
||||
|
||||
var members []*MemberSumma
|
||||
if err = g.Model("admin_member").Ctx(ctx).WhereIn("id", memberIds).Scan(&members); err != nil {
|
||||
if err = g.Model("admin_member").Ctx(ctx).Fields(MemberSumma{}).WhereIn("id", memberIds).Scan(&members); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -158,26 +158,26 @@ func IsZipType(ext string) bool {
|
||||
// 如果文件类型没有加入系统映射类型,默认认为不是合法的文件类型。建议将常用的上传文件类型加入映射关系。
|
||||
// 当然你也可以不做限制,可以上传任意文件。但需要谨慎处理和设置相应的安全措施。
|
||||
// 获取任意扩展名的扩展类型:mime.TypeByExtension(".xls")
|
||||
func GetFileMimeType(ext string) (string, error) {
|
||||
func GetFileMimeType(ext string) string {
|
||||
if mime, ok := imgType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
if mime, ok := docType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
if mime, ok := audioType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
if mime, ok := videoType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
if mime, ok := zipType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
if mime, ok := otherType[ext]; ok {
|
||||
return mime, nil
|
||||
return mime
|
||||
}
|
||||
return "", gerror.Newf("Invalid file type:%v", ext)
|
||||
return "application/octet-stream"
|
||||
}
|
||||
|
||||
// GetFileKind 获取文件上传类型
|
||||
|
@ -103,10 +103,6 @@ func DoUpload(ctx context.Context, typ string, file *ghttp.UploadFile) (result *
|
||||
|
||||
// ValidateFileMeta 验证文件元数据
|
||||
func ValidateFileMeta(typ string, meta *FileMeta) (err error) {
|
||||
if _, err = GetFileMimeType(meta.Ext); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case KindImg:
|
||||
if !IsImgType(meta.Ext) {
|
||||
@ -152,7 +148,7 @@ func ValidateFileMeta(typ string, meta *FileMeta) (err error) {
|
||||
}
|
||||
|
||||
if len(config.FileType) > 0 && !validate.InSlice(strings.Split(config.FileType, `,`), meta.Ext) {
|
||||
err = gerror.New("上传文件类型未经允许")
|
||||
err = gerror.Newf("上传文件类型未经允许:%v", meta.Ext)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -190,10 +186,7 @@ func GetFileMeta(file *ghttp.UploadFile) (meta *FileMeta, err error) {
|
||||
meta.Size = file.Size
|
||||
meta.Ext = Ext(file.Filename)
|
||||
meta.Kind = GetFileKind(meta.Ext)
|
||||
meta.MimeType, err = GetFileMimeType(meta.Ext)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
meta.MimeType = GetFileMimeType(meta.Ext)
|
||||
|
||||
// 兼容naiveUI
|
||||
naiveType := meta.MimeType
|
||||
@ -272,10 +265,7 @@ func CheckMultipart(ctx context.Context, in *CheckMultipartParams) (res *CheckMu
|
||||
meta.Size = in.Size
|
||||
meta.Ext = Ext(in.FileName)
|
||||
meta.Kind = GetFileKind(meta.Ext)
|
||||
meta.MimeType, err = GetFileMimeType(meta.Ext)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
meta.MimeType = GetFileMimeType(meta.Ext)
|
||||
|
||||
// 兼容naiveUI
|
||||
naiveType := "text/plain"
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/library/location"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/entity"
|
||||
@ -80,6 +81,18 @@ func (s *sAdminCash) List(ctx context.Context, in *adminin.CashListInp) (list []
|
||||
mod = mod.Where("member_id", in.MemberId)
|
||||
}
|
||||
|
||||
// 用户筛选
|
||||
if len(in.ComplexMemberId) == 2 && len(in.ComplexMemberId[0]) > 0 {
|
||||
memberIds, err := service.AdminMember().GetComplexMemberIds(ctx, in.ComplexMemberId[0], in.ComplexMemberId[1])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(memberIds) == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
mod = mod.WhereIn(dao.AdminOrder.Columns().MemberId, memberIds)
|
||||
}
|
||||
|
||||
if len(in.CreatedAt) == 2 {
|
||||
mod = mod.WhereBetween("created_at", gtime.New(in.CreatedAt[0]), gtime.New(in.CreatedAt[1]))
|
||||
}
|
||||
@ -93,6 +106,9 @@ func (s *sAdminCash) List(ctx context.Context, in *adminin.CashListInp) (list []
|
||||
mod = mod.Where("member_id", opMemberId)
|
||||
}
|
||||
|
||||
// 申请人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
totalCount, err = mod.Count()
|
||||
if err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
@ -107,19 +123,6 @@ func (s *sAdminCash) List(ctx context.Context, in *adminin.CashListInp) (list []
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range list {
|
||||
var member *entity.AdminMember
|
||||
if err = dao.AdminMember.Ctx(ctx).Fields("real_name", "username").Where("id", v.MemberId).Scan(&member); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return list, totalCount, err
|
||||
}
|
||||
|
||||
if member != nil {
|
||||
v.MemberName = member.RealName
|
||||
v.MemberUser = member.Username
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/hgorm/handler"
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
@ -174,6 +175,18 @@ func (s *sAdminCreditsLog) List(ctx context.Context, in *adminin.CreditsLogListI
|
||||
mod = mod.Where(dao.AdminCreditsLog.Columns().MemberId, in.MemberId)
|
||||
}
|
||||
|
||||
// 用户筛选
|
||||
if len(in.ComplexMemberId) == 2 && len(in.ComplexMemberId[0]) > 0 {
|
||||
memberIds, err := service.AdminMember().GetComplexMemberIds(ctx, in.ComplexMemberId[0], in.ComplexMemberId[1])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(memberIds) == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
mod = mod.WhereIn(dao.AdminOrder.Columns().MemberId, memberIds)
|
||||
}
|
||||
|
||||
// 查询应用id
|
||||
if in.AppId != "" {
|
||||
mod = mod.WhereLike(dao.AdminCreditsLog.Columns().AppId, in.AppId)
|
||||
@ -209,7 +222,10 @@ func (s *sAdminCreditsLog) List(ctx context.Context, in *adminin.CreditsLogListI
|
||||
mod = mod.WhereBetween(dao.AdminCreditsLog.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
||||
}
|
||||
|
||||
totalCount, err = mod.Clone().Count(1)
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
totalCount, err = mod.Clone().Count()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/grand"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
@ -28,6 +29,7 @@ import (
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/convert"
|
||||
"hotgo/utility/tree"
|
||||
"hotgo/utility/validate"
|
||||
"sync"
|
||||
@ -764,6 +766,52 @@ func (s *sAdminMember) Select(ctx context.Context, in *adminin.MemberSelectInp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetLowerIds 获取指定用户的所有下级ID集合
|
||||
func (s *sAdminMember) GetLowerIds(ctx context.Context, memberId int64) (ids []int64, err error) {
|
||||
array, err := dao.AdminMember.Ctx(ctx).
|
||||
Fields("id").
|
||||
WhereLike("tree", "%"+tree.GenLabel("", memberId)+"%").
|
||||
Array()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, v := range array {
|
||||
ids = append(ids, v.Int64())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetComplexMemberIds 组合查找符合条件的用户ID
|
||||
func (s *sAdminMember) GetComplexMemberIds(ctx context.Context, memberIdx, opt string) (ids []int64, err error) {
|
||||
memberId := gconv.Int64(memberIdx)
|
||||
count, err := s.FilterAuthModel(ctx, contexts.GetUserId(ctx)).WherePri(memberId).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
switch opt {
|
||||
case "1": // 仅查自己
|
||||
ids = append(ids, memberId)
|
||||
case "2": // 仅查下级
|
||||
ids, err = s.GetLowerIds(ctx, memberId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default: // 查全部
|
||||
ids, err = s.GetLowerIds(ctx, memberId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids = append(ids, memberId)
|
||||
}
|
||||
ids = convert.UniqueSlice(ids)
|
||||
return
|
||||
}
|
||||
|
||||
// GetIdsByKeyword 根据关键词查找符合条件的用户ID
|
||||
func (s *sAdminMember) GetIdsByKeyword(ctx context.Context, ks string) (res []int64, err error) {
|
||||
ks = gstr.Trim(ks)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/library/hgorm"
|
||||
"hotgo/internal/library/hgorm/handler"
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/library/payment"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
@ -276,11 +277,26 @@ func (s *sAdminOrder) List(ctx context.Context, in *adminin.OrderListInp) (list
|
||||
mod = mod.Where(dao.AdminOrder.Columns().MemberId, in.MemberId)
|
||||
}
|
||||
|
||||
// 下单用户筛选
|
||||
if len(in.ComplexMemberId) == 2 && len(in.ComplexMemberId[0]) > 0 {
|
||||
memberIds, err := service.AdminMember().GetComplexMemberIds(ctx, in.ComplexMemberId[0], in.ComplexMemberId[1])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(memberIds) == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
mod = mod.WhereIn(dao.AdminOrder.Columns().MemberId, memberIds)
|
||||
}
|
||||
|
||||
mod = mod.LeftJoin(hgorm.GenJoinOnRelation(
|
||||
dao.AdminOrder.Table(), dao.AdminOrder.Columns().OrderSn, // 主表表名,关联条件
|
||||
dao.PayLog.Table(), "payLog", dao.PayLog.Columns().OrderSn, // 关联表表名,别名,关联条件
|
||||
)...)
|
||||
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
totalCount, err = mod.Clone().Count(1)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -357,6 +357,18 @@ func (s *sSysLog) List(ctx context.Context, in *sysin.LogListInp) (list []*sysin
|
||||
mod = mod.Where("member_id", in.MemberId)
|
||||
}
|
||||
|
||||
// 操作人筛选
|
||||
if len(in.ComplexMemberId) == 2 && len(in.ComplexMemberId[0]) > 0 {
|
||||
memberIds, err := service.AdminMember().GetComplexMemberIds(ctx, in.ComplexMemberId[0], in.ComplexMemberId[1])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(memberIds) == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
mod = mod.WhereIn("member_id", memberIds)
|
||||
}
|
||||
|
||||
// 访问IP
|
||||
if in.Ip != "" {
|
||||
mod = mod.Where("ip", in.Ip)
|
||||
|
@ -6,6 +6,7 @@
|
||||
package adminin
|
||||
|
||||
import (
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/form"
|
||||
)
|
||||
@ -24,13 +25,13 @@ type CashViewModel struct {
|
||||
type CashListInp struct {
|
||||
form.PageReq
|
||||
form.StatusReq
|
||||
MemberId int64 `json:"memberId"`
|
||||
CreatedAt []int64 `json:"created_at"`
|
||||
MemberId int64 `json:"memberId"`
|
||||
CreatedAt []int64 `json:"created_at"`
|
||||
ComplexMemberId []string `json:"complexMemberId" dc:"申请人"`
|
||||
}
|
||||
|
||||
type CashListModel struct {
|
||||
MemberUser string `json:"memberUser"`
|
||||
MemberName string `json:"memberName"`
|
||||
MemberBySumma *hook.MemberSumma `json:"memberBySumma" dc:"申请人信息"`
|
||||
entity.AdminCash
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/library/location"
|
||||
"hotgo/internal/model/input/form"
|
||||
|
||||
@ -98,15 +99,16 @@ type CreditsLogSaveIntegralModel struct {
|
||||
// CreditsLogListInp 获取资产变动列表
|
||||
type CreditsLogListInp struct {
|
||||
form.PageReq
|
||||
Id int64 `json:"id" dc:"变动ID"`
|
||||
MemberId int64 `json:"memberId" dc:"管理员ID"`
|
||||
AppId string `json:"appId" dc:"应用id"`
|
||||
CreditType string `json:"creditType" dc:"变动类型"`
|
||||
CreditGroup string `json:"creditGroup" dc:"变动的组别"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
Ip string `json:"ip" dc:"操作人IP"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
Id int64 `json:"id" dc:"变动ID"`
|
||||
MemberId int64 `json:"memberId" dc:"管理员ID"`
|
||||
AppId string `json:"appId" dc:"应用id"`
|
||||
CreditType string `json:"creditType" dc:"变动类型"`
|
||||
CreditGroup string `json:"creditGroup" dc:"变动的组别"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
Ip string `json:"ip" dc:"操作人IP"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
ComplexMemberId []string `json:"complexMemberId" dc:"用户"`
|
||||
}
|
||||
|
||||
func (in *CreditsLogListInp) Filter(ctx context.Context) (err error) {
|
||||
@ -114,21 +116,22 @@ func (in *CreditsLogListInp) Filter(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
type CreditsLogListModel struct {
|
||||
Id int64 `json:"id" dc:"变动ID"`
|
||||
MemberId int64 `json:"memberId" dc:"管理员ID"`
|
||||
AppId string `json:"appId" dc:"应用id"`
|
||||
AddonsName string `json:"addonsName" dc:"插件名称"`
|
||||
CreditType string `json:"creditType" dc:"变动类型"`
|
||||
CreditGroup string `json:"creditGroup" dc:"变动的组别"`
|
||||
BeforeNum float64 `json:"beforeNum" dc:"变动前"`
|
||||
Num float64 `json:"num" dc:"变动数据"`
|
||||
AfterNum float64 `json:"afterNum" dc:"变动后"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
Ip string `json:"ip" dc:"操作人IP"`
|
||||
MapId int64 `json:"mapId" dc:"关联ID"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"修改时间"`
|
||||
Id int64 `json:"id" dc:"变动ID"`
|
||||
MemberId int64 `json:"memberId" dc:"管理员ID"`
|
||||
AppId string `json:"appId" dc:"应用id"`
|
||||
AddonsName string `json:"addonsName" dc:"插件名称"`
|
||||
CreditType string `json:"creditType" dc:"变动类型"`
|
||||
CreditGroup string `json:"creditGroup" dc:"变动的组别"`
|
||||
BeforeNum float64 `json:"beforeNum" dc:"变动前"`
|
||||
Num float64 `json:"num" dc:"变动数据"`
|
||||
AfterNum float64 `json:"afterNum" dc:"变动后"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
Ip string `json:"ip" dc:"操作人IP"`
|
||||
MapId int64 `json:"mapId" dc:"关联ID"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"修改时间"`
|
||||
MemberBySumma *hook.MemberSumma `json:"memberBySumma" dc:"用户信息"`
|
||||
}
|
||||
|
||||
// CreditsLogExportModel 导出资产变动
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/library/hgorm/hook"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/payin"
|
||||
@ -114,6 +115,7 @@ type OrderListInp struct {
|
||||
Status int `json:"status" dc:"状态"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
PayLogOutTradeNo string `json:"payLogOutTradeNo" dc:"商户订单号"`
|
||||
ComplexMemberId []string `json:"complexMemberId" dc:"下单用户"`
|
||||
}
|
||||
|
||||
func (in *OrderListInp) Filter(ctx context.Context) (err error) {
|
||||
@ -122,8 +124,9 @@ func (in *OrderListInp) Filter(ctx context.Context) (err error) {
|
||||
|
||||
type OrderListModel struct {
|
||||
entity.AdminOrder
|
||||
OutTradeNo string `json:"payLogOutTradeNo" dc:"商户订单号"`
|
||||
PayType string `json:"payLogPayType" dc:"支付类型"`
|
||||
OutTradeNo string `json:"payLogOutTradeNo" dc:"商户订单号"`
|
||||
PayType string `json:"payLogPayType" dc:"支付类型"`
|
||||
MemberBySumma *hook.MemberSumma `json:"memberBySumma" dc:"下单用户信息"`
|
||||
}
|
||||
|
||||
// OrderExportModel 导出充值订单
|
||||
|
@ -14,16 +14,17 @@ import (
|
||||
type LogListInp struct {
|
||||
form.PageReq
|
||||
form.StatusReq
|
||||
ReqId string `json:"reqId" dc:"对外ID"`
|
||||
Module string `json:"module" dc:"应用端口"`
|
||||
MemberId int `json:"memberId" dc:"用户ID"`
|
||||
TakeUpTime string `json:"takeUpTime" dc:"请求耗时"`
|
||||
Method string `json:"method" dc:"请求方式"`
|
||||
Url string `json:"url" dc:"请求路径"`
|
||||
Ip string `json:"ip" dc:"访问IP"`
|
||||
ErrorCode string `json:"errorCode" dc:"状态码"`
|
||||
CreatedAt []int64 `json:"createdAt" dc:"创建时间"`
|
||||
Keyword string `json:"keyword" dc:"关键词"`
|
||||
ReqId string `json:"reqId" dc:"对外ID"`
|
||||
Module string `json:"module" dc:"应用端口"`
|
||||
MemberId int `json:"memberId" dc:"用户ID"`
|
||||
TakeUpTime string `json:"takeUpTime" dc:"请求耗时"`
|
||||
Method string `json:"method" dc:"请求方式"`
|
||||
Url string `json:"url" dc:"请求路径"`
|
||||
Ip string `json:"ip" dc:"访问IP"`
|
||||
ErrorCode string `json:"errorCode" dc:"状态码"`
|
||||
CreatedAt []int64 `json:"createdAt" dc:"创建时间"`
|
||||
Keyword string `json:"keyword" dc:"关键词"`
|
||||
ComplexMemberId []string `json:"complexMemberId" dc:"操作人筛选"`
|
||||
}
|
||||
|
||||
type LogListModel struct {
|
||||
|
@ -106,6 +106,10 @@ type (
|
||||
GetIdByCode(ctx context.Context, in *adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error)
|
||||
// Select 获取可选的用户选项
|
||||
Select(ctx context.Context, in *adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error)
|
||||
// GetLowerIds 获取指定用户的所有下级ID集合
|
||||
GetLowerIds(ctx context.Context, memberId int64) (ids []int64, err error)
|
||||
// GetComplexMemberIds 组合查找符合条件的用户ID
|
||||
GetComplexMemberIds(ctx context.Context, memberIdx string, opt string) (ids []int64, err error)
|
||||
// GetIdsByKeyword 根据关键词查找符合条件的用户ID
|
||||
GetIdsByKeyword(ctx context.Context, ks string) (res []int64, err error)
|
||||
// VerifySuperId 验证是否为超管
|
||||
|
@ -31,7 +31,8 @@ import (
|
||||
@{ if eq .options.Step.IsAddon true }isc "hotgo/internal/service"@{end}
|
||||
@{ if eq .options.Step.IsTreeTable true }"hotgo/utility/tree"@{end}
|
||||
@{ if eq .options.Step.HasFuncDict true }"hotgo/internal/library/dict"@{end}
|
||||
@{ if eq .options.Step.HasFuncDict true }"hotgo/internal/model"@{end}
|
||||
@{ if and (eq .options.Step.HasFuncDict true) (eq .options.Step.IsAddon false) }"hotgo/internal/model"@{end}
|
||||
@{ if and (eq .options.Step.HasFuncDict true) (eq .options.Step.IsAddon true) }imodel "hotgo/internal/model"@{end}
|
||||
)
|
||||
|
||||
type s@{.servFunName} struct{}
|
||||
@ -238,7 +239,7 @@ func (s *s@{.servFunName}) TreeOption(ctx context.Context) (nodes []tree.Node, e
|
||||
|
||||
@{ if eq .options.Step.HasFuncDict true }
|
||||
// Option 获取@{.tableComment}选项
|
||||
func (s *s@{.servFunName}) Option(ctx context.Context) (opts []*model.Option, err error) {
|
||||
func (s *s@{.servFunName}) Option(ctx context.Context) (opts []*@{ if eq .options.Step.IsAddon false }model@{end}@{ if eq .options.Step.IsAddon true }imodel@{end}.Option, err error) {
|
||||
var models []*entity.@{.daoName}
|
||||
if err = s.Model(ctx@{ if eq .options.Step.HasNotFilterAuth true } ,&handler.Option{FilterAuth: false}@{end}).Fields(dao.@{.daoName}.Columns().@{.options.FuncDict.Value.GoName},dao.@{.daoName}.Columns().@{.options.FuncDict.Label.GoName}).
|
||||
@{.listOrder}.Scan(&models); err != nil {
|
||||
@ -246,7 +247,7 @@ func (s *s@{.servFunName}) Option(ctx context.Context) (opts []*model.Option, er
|
||||
return
|
||||
}
|
||||
|
||||
opts = make([]*model.Option, len(models))
|
||||
opts = make([]*@{ if eq .options.Step.IsAddon false }model@{end}@{ if eq .options.Step.IsAddon true }imodel@{end}.Option, len(models))
|
||||
for k, v := range models {
|
||||
opts[k] = dict.GenHashOption(v.@{.options.FuncDict.Value.GoName}, gconv.String(v.@{.options.FuncDict.Label.GoName}))
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ CREATE TABLE IF NOT EXISTS `hg_admin_member` (
|
||||
|
||||
INSERT INTO `hg_admin_member` (`id`, `dept_id`, `role_id`, `real_name`, `username`, `password_hash`, `salt`, `password_reset_token`, `integral`, `balance`, `avatar`, `sex`, `qq`, `email`, `mobile`, `birthday`, `city_id`, `address`, `pid`, `level`, `tree`, `invite_code`, `cash`, `last_active_at`, `remark`, `status`, `created_at`, `updated_at`) VALUES
|
||||
(1, 100, 1, '孟帅', 'admin', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', '88.00', '99289.78', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '133814250', '133814250@qq.com', '15303830571', '2016-04-16', 410172, '莲花街001号', 0, 1, '', '111', '{"name": "孟帅", "account": "15303830571", "payeeCode": "http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8mqal5isvcb58g.jpg"}', '2024-08-27 19:02:49', NULL, 1, '2021-02-12 17:59:45', '2024-08-27 19:02:49'),
|
||||
(3, 100, 2, '测试管理员', 'test', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', '0.00', '4.00', 'http://alioss.qvnidaye.com//images/2021/03/12/image_1615529198_vMK4kwq2.jpg', 1, '', 'c@qq.cc', '15303888888', '2016-04-13', 371100, '大潮街道666号', 1, 2, 'tr_1 ', '222', NULL, '2024-04-24 11:47:48', '', 1, '2022-02-11 17:59:45', '2024-04-24 11:47:48'),
|
||||
(3, 100, 2, '测试管理员', 'test', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', '0.00', '4.00', '', 1, '', 'c@qq.cc', '15303888888', '2016-04-13', 371100, '大潮街道666号', 1, 2, 'tr_1 ', '222', NULL, '2024-04-24 11:47:48', '', 1, '2022-02-11 17:59:45', '2024-04-24 11:47:48'),
|
||||
(8, 102, 200, '阿萌', 'ameng', '382df3b083a27886edb94e669a857c33', 'hfuUEb', '', '11.00', '4.22', '', 2, '', '', '', NULL, 0, '', 1, 2, 'tr_1 ', '333', NULL, '2024-04-16 18:56:00', '', 1, '2023-02-03 17:34:31', '2024-04-16 18:56:00'),
|
||||
(9, 100, 206, '黄敏', 'test_finance', '151f5f6bb8b223fc7b589a32effb6f91', 'FhShzw', '', '0.00', '0.00', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '', '', '', NULL, 0, '', 1, 2, 'tr_1 ', '5jZUI3uWLfcj', NULL, NULL, '', 1, '2023-08-02 11:30:45', '2023-08-02 11:31:09'),
|
||||
(11, 111, 209, '刘芳', 'abai', '5787c7a121190011fac8376b1d3e0396', 'puUFvx', '', '0.00', '0.00', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '', '', '', NULL, 0, '', 8, 3, 'tr_1 tr_8 ', 'SH5akjqInb2p', NULL, '2024-04-16 18:56:02', '', 1, '2023-08-02 14:24:50', '2024-04-16 18:56:02'),
|
||||
@ -1460,8 +1460,8 @@ INSERT INTO `hg_sys_config` (`id`, `group`, `name`, `type`, `key`, `value`, `def
|
||||
(51, 'smtp', '最小发送间隔', 'int', 'smtpMinInterval', '60', '', 150, '同地址', 1, 1, '2021-01-30 13:27:43', '2023-02-04 16:59:13'),
|
||||
(52, 'smtp', 'IP最大发送次数', 'int', 'smtpMaxIpLimit', '10', '', 160, '同IP每天最大允许发送次数', 1, 1, '2021-01-30 13:27:43', '2023-02-04 16:59:13'),
|
||||
(53, 'smtp', '验证码有效期', 'int', 'smtpCodeExpire', '600', '', 170, '单位:秒', 1, 1, '2021-01-30 13:27:43', '2023-02-04 16:59:13'),
|
||||
(54, 'basic', '网站域名', 'string', 'basicDomain', 'https://hotgo.facms.cn', 'https://hotgo.facms.cn', 45, '', 1, 1, '2021-01-30 13:27:43', '2024-04-21 22:58:30'),
|
||||
(55, 'basic', 'websocket地址', 'string', 'basicWsAddr', 'wss://hotgo.facms.cn/socket', 'wss://hotgo.facms.cn/socket', 48, '', 1, 1, '2021-01-30 13:27:43', '2024-04-21 22:58:30'),
|
||||
(54, 'basic', '网站域名', 'string', 'basicDomain', 'http://127.0.0.1:8000', 'http://127.0.0.1:8000', 45, '', 1, 1, '2021-01-30 13:27:43', '2024-04-21 22:58:30'),
|
||||
(55, 'basic', 'websocket地址', 'string', 'basicWsAddr', 'ws://127.0.0.1:8000/socket', 'ws://127.0.0.1:8000/socket', 48, '', 1, 1, '2021-01-30 13:27:43', '2024-04-21 22:58:30'),
|
||||
(56, 'upload', 'COS存储路径', 'string', 'uploadCosPath', 'hotgo/attachment/', 'hotgo/attachment/', 450, 'COS对象存储中的相对路径', 1, 1, '2021-01-30 13:27:43', '2024-02-28 16:56:35'),
|
||||
(57, 'upload', 'COS秘钥ID', 'string', 'uploadCosSecretId', '', '', 460, '子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140', 1, 1, '2021-01-30 13:27:43', '2024-02-28 16:56:35'),
|
||||
(58, 'upload', 'COS秘钥', 'string', 'uploadCosSecretKey', '', '', 470, '', 1, 1, '2021-01-30 13:27:43', '2024-02-28 16:56:35'),
|
||||
|
@ -36,7 +36,7 @@ INSERT INTO `hg_admin_dept` (`id`, `pid`, `name`, `code`, `type`, `leader`, `pho
|
||||
|
||||
INSERT INTO `hg_admin_member` (`id`, `dept_id`, `role_id`, `real_name`, `username`, `password_hash`, `salt`, `password_reset_token`, `integral`, `balance`, `avatar`, `sex`, `qq`, `email`, `mobile`, `birthday`, `city_id`, `address`, `pid`, `level`, `tree`, `invite_code`, `cash`, `last_active_at`, `remark`, `status`, `created_at`, `updated_at`) VALUES
|
||||
(1, 100, 1, '孟帅', 'admin', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', 89.00, 99290.78, 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '133814250', '133814250@qq.com', '15303830571', '2016-04-16', 410172, '莲花街001号', 0, 1, '', '111', '{\"name\": \"孟帅\", \"account\": \"15303830571\", \"payeeCode\": \"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8mqal5isvcb58g.jpg\"}', '2024-04-21 22:58:56', NULL, 1, '2021-02-12 17:59:45', '2024-04-21 22:58:56'),
|
||||
(3, 100, 2, '测试管理员', 'test', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', 0.00, 4.00, 'http://alioss.qvnidaye.com//images/2021/03/12/image_1615529198_vMK4kwq2.jpg', 1, '', 'c@qq.cc', '15303888888', '2016-04-13', 371100, '大潮街道666号', 1, 2, 'tr_1 ', '222', NULL, '2024-04-12 12:44:18', '', 1, '2022-02-11 17:59:45', '2024-04-12 12:44:18'),
|
||||
(3, 100, 2, '测试管理员', 'test', 'a7c588fffeb2c1d99b29879d7fe97c78', '6541561', '', 0.00, 4.00, '', 1, '', 'c@qq.cc', '15303888888', '2016-04-13', 371100, '大潮街道666号', 1, 2, 'tr_1 ', '222', NULL, '2024-04-12 12:44:18', '', 1, '2022-02-11 17:59:45', '2024-04-12 12:44:18'),
|
||||
(8, 102, 200, '阿萌', 'ameng', '382df3b083a27886edb94e669a857c33', 'hfuUEb', '', 11.00, 4.22, '', 2, '', '', '', NULL, 0, '', 1, 2, 'tr_1 ', '333', NULL, '2024-04-16 18:56:00', '', 1, '2023-02-03 17:34:31', '2024-04-16 18:56:00'),
|
||||
(9, 100, 206, '黄敏', 'test_finance', '151f5f6bb8b223fc7b589a32effb6f91', 'FhShzw', '', 0.00, 0.00, 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '', '', '', NULL, 0, '', 1, 2, 'tr_1 ', '5jZUI3uWLfcj', NULL, NULL, '', 1, '2023-08-02 11:30:45', '2023-08-02 11:31:09'),
|
||||
(11, 111, 209, '刘芳', 'abai', '5787c7a121190011fac8376b1d3e0396', 'puUFvx', '', 0.00, 0.00, 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdq8er9nfkchdopav.png', 1, '', '', '', NULL, 0, '', 8, 3, 'tr_1 tr_8 ', 'SH5akjqInb2p', NULL, '2024-04-16 18:56:02', '', 1, '2023-08-02 14:24:50', '2024-04-16 18:56:02'),
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hotgo",
|
||||
"type": "module",
|
||||
"version": "2.15.11",
|
||||
"version": "2.16.10",
|
||||
"author": {
|
||||
"name": "MengShuai",
|
||||
"email": "133814250@qq.com",
|
||||
@ -44,7 +44,7 @@
|
||||
"lodash-es": "^4.17.21",
|
||||
"mint-filter": "^4.0.3",
|
||||
"mitt": "^3.0.1",
|
||||
"naive-ui": "^2.39.0",
|
||||
"naive-ui": "^2.41.0",
|
||||
"pinia": "^2.2.2",
|
||||
"pinyin-pro": "^3.24.2",
|
||||
"print-js": "^1.6.0",
|
||||
|
144
web/src/components/ComplexMemberPicker/index.vue
Normal file
144
web/src/components/ComplexMemberPicker/index.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-bind="$props"
|
||||
:style="{ width: '68%' }"
|
||||
v-model:value="memberId"
|
||||
:options="memberOption"
|
||||
:render-label="renderLabel"
|
||||
:filter="handleReceiverFilter"
|
||||
@update:value="handleChangeMemberId"
|
||||
clearable
|
||||
filterable
|
||||
/>
|
||||
<n-select
|
||||
:consistent-menu-width="false"
|
||||
:style="{ width: '32%', 'min-width': '90px' }"
|
||||
:options="selectOptions"
|
||||
v-model:value="optVal"
|
||||
@update:value="handleUpdateOptions"
|
||||
/>
|
||||
</n-input-group>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, onMounted, ref, watch } from 'vue';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { NText, SelectRenderLabel } from 'naive-ui';
|
||||
import { basicProps } from './props';
|
||||
|
||||
const props = defineProps({
|
||||
...basicProps,
|
||||
});
|
||||
const emit = defineEmits(['update:value']);
|
||||
const userStore = useUserStore();
|
||||
const memberId = ref(null);
|
||||
const optVal = ref('-1');
|
||||
const memberOption = ref([]);
|
||||
const selectOptions = [
|
||||
{
|
||||
label: '查全部',
|
||||
value: '-1',
|
||||
},
|
||||
{
|
||||
label: '查本人',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '查下级',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const renderLabel: SelectRenderLabel = (option: { username: ''; label: '' }) => {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
padding: '4px 0',
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
marginRight: '4px',
|
||||
},
|
||||
},
|
||||
[option.username as string]
|
||||
),
|
||||
h(
|
||||
NText,
|
||||
{ depth: 3, tag: 'div' },
|
||||
{
|
||||
default: () => option.label as string,
|
||||
}
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
function handleReceiverFilter(pattern: string, option: object): boolean {
|
||||
const isPatternInLabel = option.label.includes(pattern);
|
||||
const isPatternInUsername = option.username.includes(pattern);
|
||||
const isValueEqual = option.value.toString() === pattern;
|
||||
return isPatternInLabel || isPatternInUsername || isValueEqual;
|
||||
}
|
||||
|
||||
function handleChangeMemberId(v: string) {
|
||||
memberId.value = v;
|
||||
handleUpdateValue();
|
||||
}
|
||||
|
||||
function handleUpdateOptions(value: string) {
|
||||
optVal.value = value;
|
||||
handleUpdateValue();
|
||||
}
|
||||
|
||||
function handleUpdateValue() {
|
||||
if (memberId.value) {
|
||||
emit('update:value', [memberId.value, optVal.value]);
|
||||
} else {
|
||||
emit('update:value', null);
|
||||
}
|
||||
}
|
||||
|
||||
function resetFields() {
|
||||
memberId.value = null;
|
||||
optVal.value = '-1';
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(v) => {
|
||||
if (!v) {
|
||||
resetFields();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
GetMemberOption().then((res) => {
|
||||
if (res) {
|
||||
memberOption.value = res;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
13
web/src/components/ComplexMemberPicker/props.ts
Normal file
13
web/src/components/ComplexMemberPicker/props.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { NSelect } from 'naive-ui';
|
||||
|
||||
export const basicProps = {
|
||||
...NSelect.props,
|
||||
defaultValue: {
|
||||
type: [Array],
|
||||
default: null,
|
||||
},
|
||||
value: {
|
||||
type: [Array],
|
||||
default: null,
|
||||
},
|
||||
};
|
@ -66,6 +66,13 @@
|
||||
v-bind="getComponentProps(schema)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="schema.component === 'ComplexMemberPicker'">
|
||||
<ComplexMemberPicker
|
||||
:class="{ isFull: schema.isFull !== false && getProps.isFull }"
|
||||
v-model:value="formModel[schema.field]"
|
||||
v-bind="getComponentProps(schema)"
|
||||
/>
|
||||
</template>
|
||||
<!--动态渲染表单组件-->
|
||||
<component
|
||||
v-else
|
||||
@ -147,18 +154,16 @@
|
||||
import { createPlaceholderMessage } from './helper';
|
||||
import { useFormEvents } from './hooks/useFormEvents';
|
||||
import { useFormValues } from './hooks/useFormValues';
|
||||
|
||||
import ComplexMemberPicker from '../../ComplexMemberPicker/index.vue';
|
||||
import { basicProps } from './props';
|
||||
import { DownOutlined, UpOutlined, QuestionCircleOutlined } from '@vicons/antd';
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
import type { GridProps } from 'naive-ui/lib/grid';
|
||||
import type { FormSchema, FormProps, FormActionType } from './types/form';
|
||||
|
||||
import {isArray, isBoolean, isFunction} from '@/utils/is';
|
||||
import { isArray, isBoolean, isFunction } from '@/utils/is';
|
||||
import { deepMerge } from '@/utils';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import {ActionItem} from "@/components/Table";
|
||||
import { ActionItem } from '@/components/Table';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicForm',
|
||||
@ -237,7 +242,7 @@
|
||||
});
|
||||
|
||||
const getBindValue = computed(
|
||||
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable)
|
||||
() => ({ ...attrs, ...props, ...unref(getProps) }) as Recordable
|
||||
);
|
||||
|
||||
const getSchema = computed((): FormSchema[] => {
|
||||
|
@ -25,4 +25,5 @@ export type ComponentType =
|
||||
| 'NIconPicker'
|
||||
| 'NRender'
|
||||
| 'NSlider'
|
||||
| 'NRate';
|
||||
| 'NRate'
|
||||
| 'ComplexMemberPicker';
|
||||
|
@ -34,7 +34,7 @@ export const RedirectRoute: AppRouteRecordRaw = {
|
||||
children: [
|
||||
{
|
||||
path: '/redirect/:path(.*)',
|
||||
name: RedirectName,
|
||||
name: `${RedirectName}Son`,
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
title: RedirectName,
|
||||
|
@ -183,7 +183,6 @@ export const renderPopoverMemberSumma = (member: MemberSumma | null | undefined)
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
size: 'small',
|
||||
text: true,
|
||||
iconPlacement: 'right',
|
||||
|
@ -146,6 +146,10 @@ export function isNullOrUnDef(val: unknown): val is null | undefined {
|
||||
return isUnDef(val) || isNull(val);
|
||||
}
|
||||
|
||||
export function isEmpty(value: any): boolean {
|
||||
return value === undefined || value === null || value === '';
|
||||
}
|
||||
|
||||
// 判断字串符是否以字母开头
|
||||
export function isLetterBegin(str) {
|
||||
return /^[A-z]/.test(str);
|
||||
|
@ -81,7 +81,7 @@ export default () => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
createSocket();
|
||||
}, 2000);
|
||||
}, 1000 * 10);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
|
@ -106,7 +106,7 @@ export const columns = [
|
||||
{
|
||||
title: '文件名称',
|
||||
key: 'name',
|
||||
width: 120,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '文件',
|
||||
@ -157,7 +157,7 @@ export const columns = [
|
||||
{
|
||||
title: '扩展类型',
|
||||
key: 'mimeType',
|
||||
width: 120,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
|
@ -21,7 +21,7 @@
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1280"
|
||||
:scroll-x="scrollX"
|
||||
:resizeHeightOffset="-20000"
|
||||
>
|
||||
<template #tableTitle>
|
||||
@ -77,7 +77,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onMounted, reactive, ref } from 'vue';
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
@ -93,6 +93,7 @@
|
||||
import FileUpload from '@/components/FileChooser/src/Upload.vue';
|
||||
import MultipartUpload from '@/components/Upload/multipartUpload.vue';
|
||||
import { Attachment } from '@/components/FileChooser/src/model';
|
||||
import { adaTableScrollX } from '@/utils/hotgo';
|
||||
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
@ -106,7 +107,7 @@
|
||||
const multipartUploadRef = ref();
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 120,
|
||||
width: 132,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
@ -128,6 +129,10 @@
|
||||
},
|
||||
});
|
||||
|
||||
const scrollX = computed(() => {
|
||||
return adaTableScrollX(columns, actionColumn.width);
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 100,
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { h } from 'vue';
|
||||
import { NAvatar, NAvatarGroup, NTooltip } from 'naive-ui';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
@ -106,7 +104,3 @@ export const columns = [
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export function loadOptions() {
|
||||
dict.loadOptions(['sys_normal_disable']);
|
||||
}
|
||||
|
215
web/src/views/apply/notice/edit.vue
Normal file
215
web/src/views/apply/notice/edit.vue
Normal file
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-drawer v-model:show="showModal" :width="dialogWidth">
|
||||
<n-drawer-content closable>
|
||||
<template #header>
|
||||
{{
|
||||
formValue.id > 0
|
||||
? '编辑' + dict.getLabel('noticeTypeOptions', formValue.type) + ' #' + formValue.id
|
||||
: '发送' + dict.getLabel('noticeTypeOptions', formValue.type)
|
||||
}}
|
||||
</template>
|
||||
<n-scrollbar style="max-height: 87vh" class="pr-5">
|
||||
<n-spin :show="loading" description="请稍候...">
|
||||
<n-alert :show-icon="false" type="info">
|
||||
消息发送成功后如果接收人在线会立即收到一条消息通知,编辑已发送的消息不会再次通知
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="formValue"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
:label-placement="settingStore.isMobile ? 'top' : 'left'"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="消息标题" path="title">
|
||||
<n-input placeholder="请输入消息标题" v-model:value="formValue.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="接收人" path="receiver" v-if="formValue.type === 3">
|
||||
<n-select
|
||||
multiple
|
||||
:options="options"
|
||||
:render-label="renderLabel"
|
||||
:render-tag="renderMultipleSelectTag"
|
||||
v-model:value="formValue.receiver"
|
||||
filterable
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="消息内容" path="content">
|
||||
<template v-if="formValue.type === 1">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 10 }"
|
||||
placeholder="请输入通知内容"
|
||||
v-model:value="formValue.content"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Editor style="height: 320px" v-model:value="formValue.content" />
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="标签" path="tag">
|
||||
<n-select
|
||||
clearable
|
||||
placeholder="可以不填"
|
||||
:render-tag="renderTag"
|
||||
v-model:value="formValue.tag"
|
||||
:options="dict.getOptionUnRef('noticeTagOptions')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formValue.sort" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formValue.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备注" path="remark">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="请输入备注,没有可以不填"
|
||||
v-model:value="formValue.remark"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</n-scrollbar>
|
||||
<template #footer>
|
||||
<n-space>
|
||||
<n-button @click="closeForm"> 取消 </n-button>
|
||||
<n-button type="primary" :loading="formBtnLoading" @click="confirmForm">
|
||||
立即发送
|
||||
</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-drawer-content>
|
||||
</n-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { personOption, renderLabel, renderMultipleSelectTag } from '@/enums/systemMessageEnum';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { MaxSort, EditLetter, EditNotice, EditNotify } from '@/api/apply/notice';
|
||||
import { renderTag } from '@/utils';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import { State, newState, rules } from './model';
|
||||
|
||||
const emit = defineEmits(['reloadTable']);
|
||||
const message = useMessage();
|
||||
const settingStore = useProjectSettingStore();
|
||||
const dict = useDictStore();
|
||||
const loading = ref(false);
|
||||
const showModal = ref(false);
|
||||
const formValue = ref<State>(newState(null));
|
||||
const formRef = ref<any>({});
|
||||
const formBtnLoading = ref(false);
|
||||
const options = ref<personOption[]>();
|
||||
const dialogWidth = ref(adaModalWidth(840));
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
switch (formValue.value.type) {
|
||||
case 1:
|
||||
EditNotify(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
EditNotice(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
EditLetter(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
message.error('公告类型不支持');
|
||||
}
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function confirmComplete() {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
closeForm();
|
||||
emit('reloadTable');
|
||||
});
|
||||
}
|
||||
|
||||
function getMemberOption() {
|
||||
GetMemberOption().then((res) => {
|
||||
options.value = res;
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭抽屉
|
||||
function closeForm() {
|
||||
showModal.value = false;
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// 打开抽屉
|
||||
function openModal(state: State, type: number) {
|
||||
showModal.value = true;
|
||||
dialogWidth.value = adaModalWidth(840);
|
||||
getMemberOption();
|
||||
|
||||
// 新增
|
||||
if (!state || state.id < 1) {
|
||||
formValue.value = newState(state);
|
||||
formValue.value.type = type;
|
||||
|
||||
loading.value = true;
|
||||
MaxSort()
|
||||
.then((res) => {
|
||||
formValue.value.sort = res.sort;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 编辑
|
||||
formValue.value = newState(state);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
@ -26,7 +26,7 @@
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1280"
|
||||
:scroll-x="scrollX"
|
||||
:resizeHeightOffset="-20000"
|
||||
>
|
||||
<template #tableTitle>
|
||||
@ -88,109 +88,8 @@
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
:block-scroll="false"
|
||||
:mask-closable="false"
|
||||
preset="dialog"
|
||||
:title="
|
||||
formParams.id > 0
|
||||
? '编辑' + dict.getLabel('noticeTypeOptions', formParams.type) + ' #' + formParams.id
|
||||
: '发送' + dict.getLabel('noticeTypeOptions', formParams.type)
|
||||
"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-alert :show-icon="false" type="info">
|
||||
消息发送成功后如果接收人在线会立即收到一条消息通知,编辑已发送的消息不会再次通知
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="消息标题" path="title">
|
||||
<n-input placeholder="请输入消息标题" v-model:value="formParams.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="接收人" path="receiver" v-if="formParams.type === 3">
|
||||
<n-select
|
||||
multiple
|
||||
:options="options"
|
||||
:render-label="renderLabel"
|
||||
:render-tag="renderMultipleSelectTag"
|
||||
v-model:value="formParams.receiver"
|
||||
filterable
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="消息内容" path="content">
|
||||
<template v-if="formParams.type === 1">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 30 }"
|
||||
placeholder="请输入通知内容"
|
||||
v-model:value="formParams.content"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Editor style="height: 450px" v-model:value="formParams.content" />
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="标签" path="tag">
|
||||
<n-select
|
||||
clearable
|
||||
placeholder="可以不填"
|
||||
:render-tag="renderTag"
|
||||
v-model:value="formParams.tag"
|
||||
:options="dict.getOptionUnRef('noticeTagOptions')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formParams.sort" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备注" path="remark">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="请输入备注,没有可以不填"
|
||||
v-model:value="formParams.remark"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">立即发送</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
<Edit ref="editRef" @reload-table="reloadTable" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -198,117 +97,25 @@
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import {
|
||||
Delete,
|
||||
EditNotify,
|
||||
EditLetter,
|
||||
EditNotice,
|
||||
List,
|
||||
MaxSort,
|
||||
Status,
|
||||
} from '@/api/apply/notice';
|
||||
import { columns, loadOptions } from './columns';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { Delete, List, Status } from '@/api/apply/notice';
|
||||
import { BellOutlined, DeleteOutlined, NotificationOutlined, SendOutlined } from '@vicons/antd';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
import { personOption, renderLabel, renderMultipleSelectTag } from '@/enums/systemMessageEnum';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import { renderTag } from '@/utils';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { adaTableScrollX } from '@/utils/hotgo';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入消息标题',
|
||||
},
|
||||
};
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'type',
|
||||
component: 'NSelect',
|
||||
label: '消息类型',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择消息类型',
|
||||
options: dict.getOption('noticeTypeOptions'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'title',
|
||||
component: 'NInput',
|
||||
label: '消息标题',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息标题',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入消息标题', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
component: 'NInput',
|
||||
label: '消息内容',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息内容关键词',
|
||||
showButton: false,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: dict.getOption('sys_normal_disable'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
import { columns } from './columns';
|
||||
import { schemas, loadOptions } from './model';
|
||||
import Edit from './edit.vue';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const message = useMessage();
|
||||
const dict = useDictStore();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const editRef = ref();
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const options = ref<personOption[]>();
|
||||
const dialogWidth = computed(() => {
|
||||
return adaModalWidth();
|
||||
});
|
||||
|
||||
const resetFormParams = {
|
||||
id: 0,
|
||||
title: '',
|
||||
type: 1,
|
||||
tag: 0,
|
||||
content: '',
|
||||
receiver: null,
|
||||
remark: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
};
|
||||
let formParams = ref<any>(cloneDeep(resetFormParams));
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 200,
|
||||
@ -351,6 +158,10 @@
|
||||
},
|
||||
});
|
||||
|
||||
const scrollX = computed(() => {
|
||||
return adaTableScrollX(columns, actionColumn.width);
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
@ -358,12 +169,7 @@
|
||||
});
|
||||
|
||||
function addTable(type) {
|
||||
showModal.value = true;
|
||||
formParams.value = cloneDeep(resetFormParams);
|
||||
formParams.value.type = type;
|
||||
MaxSort().then((res) => {
|
||||
formParams.value.sort = res.sort;
|
||||
});
|
||||
editRef.value.openModal(null, type);
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
@ -379,52 +185,8 @@
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
switch (formParams.value.type) {
|
||||
case 1:
|
||||
EditNotify(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
EditNotice(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
EditLetter(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
message.error('公告类型不支持');
|
||||
}
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
showModal.value = true;
|
||||
formParams.value = cloneDeep(record);
|
||||
editRef.value.openModal(record, record.type);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
@ -474,13 +236,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function getMemberOption() {
|
||||
options.value = await GetMemberOption();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
loadOptions();
|
||||
await getMemberOption();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
113
web/src/views/apply/notice/model.ts
Normal file
113
web/src/views/apply/notice/model.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
|
||||
export class State {
|
||||
id: number;
|
||||
title: string;
|
||||
type: number;
|
||||
tag: number = 1;
|
||||
content: string;
|
||||
receiver: number[];
|
||||
remark: string;
|
||||
sort: number;
|
||||
status: number = 1;
|
||||
createdBy: number;
|
||||
updatedBy: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
readCount: number;
|
||||
receiverGroup: Receiver[];
|
||||
|
||||
constructor(state?: Partial<State>) {
|
||||
if (state) {
|
||||
Object.assign(this, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Receiver {
|
||||
name: string;
|
||||
src: string;
|
||||
}
|
||||
|
||||
export function newState(state: State | Record<string, any> | null): State {
|
||||
if (state !== null) {
|
||||
if (state instanceof State) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return new State(state);
|
||||
}
|
||||
return new State();
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
export const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入消息标题',
|
||||
},
|
||||
};
|
||||
|
||||
// 表格搜索表单
|
||||
export const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'type',
|
||||
component: 'NSelect',
|
||||
label: '消息类型',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择消息类型',
|
||||
options: dict.getOption('noticeTypeOptions'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'title',
|
||||
component: 'NInput',
|
||||
label: '消息标题',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息标题',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入消息标题', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
component: 'NInput',
|
||||
label: '消息内容',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息内容关键词',
|
||||
showButton: false,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: dict.getOption('sys_normal_disable'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// 加载字典数据选项
|
||||
export function loadOptions() {
|
||||
dict.loadOptions(['sys_normal_disable']);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag } from 'naive-ui';
|
||||
import { renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
const msgMap = {
|
||||
1: '处理中',
|
||||
@ -29,20 +30,12 @@ export const columns = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
key: 'memberUser',
|
||||
render(row) {
|
||||
return row.memberUser;
|
||||
},
|
||||
title: '申请人',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'memberName',
|
||||
render(row) {
|
||||
return row.memberName;
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '提现金额',
|
||||
|
@ -118,7 +118,7 @@
|
||||
</n-carousel>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="提现状态" path="status">
|
||||
<n-form-item label="变更提现状态" path="status">
|
||||
<n-radio-group v-model:value="paymentParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
@ -187,16 +187,15 @@
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '申请人',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择申请人',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入管理员ID', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'ip',
|
||||
|
@ -2,18 +2,18 @@ import { ref } from 'vue';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { renderOptionTag, renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
const dict = useDictStore();
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '选择用户',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择用户',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
@ -21,10 +21,10 @@ export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'creditGroup',
|
||||
component: 'NSelect',
|
||||
label: '组别',
|
||||
label: '变动组别',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择变动的组别',
|
||||
placeholder: '请选择变动组别',
|
||||
options: dict.getOption('creditGroup'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
@ -86,9 +86,12 @@ export const columns = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '管理员ID',
|
||||
title: '用户',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '变动类型',
|
||||
@ -99,7 +102,7 @@ export const columns = [
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '组别',
|
||||
title: '变动组别',
|
||||
key: 'creditGroup',
|
||||
render(row) {
|
||||
return renderOptionTag('creditGroup', row.creditGroup);
|
||||
|
@ -58,7 +58,6 @@
|
||||
}
|
||||
|
||||
const emit = defineEmits(['reloadTable', 'updateShowModal']);
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showModal: false,
|
||||
formParams: () => {
|
||||
|
@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { MemberSumma, renderOptionTag, renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
export interface State {
|
||||
id: number;
|
||||
@ -20,6 +20,7 @@ export interface State {
|
||||
refundReason: string;
|
||||
rejectRefundReason: string;
|
||||
payLogPayType: string;
|
||||
memberBySumma?: null | MemberSumma;
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
@ -51,12 +52,12 @@ export const rules = {};
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '下单用户',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择下单用户',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
@ -99,25 +100,18 @@ export const schemas = ref<FormSchema[]>([
|
||||
]);
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '订单ID',
|
||||
key: 'id',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '管理员ID',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '业务订单号',
|
||||
key: 'orderSn',
|
||||
width: 260,
|
||||
width: 220,
|
||||
},
|
||||
{
|
||||
title: '商户订单号',
|
||||
key: 'payLogOutTradeNo',
|
||||
width: 260,
|
||||
title: '下单用户',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
render(row: State) {
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
@ -143,6 +137,11 @@ export const columns = [
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '商户订单号',
|
||||
key: 'payLogOutTradeNo',
|
||||
width: 220,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag, NEllipsis, NSpace } from 'naive-ui';
|
||||
import { timestampToTime } from '@/utils/dateUtil';
|
||||
import { renderHtmlTooltip } from '@/utils';
|
||||
import Column from './components/Column.vue';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
@ -14,49 +12,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 180,
|
||||
render(row) {
|
||||
const operator =
|
||||
row.memberId === 0 ? row.memberName : row.memberName + '(' + row.memberId + ')';
|
||||
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '180px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
h('div', {
|
||||
innerHTML: '<div><p>' + operator + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>IP:' + row.ip + '</p></div>',
|
||||
}),
|
||||
row.cityLabel != ''
|
||||
? h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'primary',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.cityLabel,
|
||||
}
|
||||
)
|
||||
: null,
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'visitor',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -64,43 +23,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 260,
|
||||
render(row) {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '260px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.method,
|
||||
}
|
||||
),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>接口:' + row.url + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>名称:' + row.tags + ' / ' + row.summary + '</p></div>',
|
||||
}),
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'request',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -108,39 +34,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 260,
|
||||
render(row) {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '260px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
renderHtmlTooltip(
|
||||
'<div style="width: 240px"><p>状态码:' +
|
||||
row.errorMsg +
|
||||
'(' +
|
||||
row.errorCode +
|
||||
')' +
|
||||
'</p></div>'
|
||||
),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>处理耗时:' + row.takeUpTime + 'ms</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>响应时间:' + timestampToTime(row.timestamp) + '</p></div>',
|
||||
}),
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'response',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
|
77
web/src/views/log/log/components/Column.vue
Normal file
77
web/src/views/log/log/components/Column.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<template v-if="column === 'visitor'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row mb-1">
|
||||
<div class="text">
|
||||
{{
|
||||
state.memberId === 0
|
||||
? state.memberName
|
||||
: state.memberName + '(' + state.memberId + ')'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div>访问IP:</div>
|
||||
<div class="text">{{ state.ip }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text">
|
||||
{{ state.cityLabel !== '' ? state.cityLabel : '局域网' }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column === 'request'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row">
|
||||
<div class="text mr-1 mb-1">
|
||||
<n-button :type="state.method === 'GET' ? 'tertiary' : 'primary'" size="tiny">
|
||||
{{ state.method }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="text">{{ state.url }}</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">{{ state.tags }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ state.summary }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column === 'response'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row">
|
||||
<div class="text mr-1 mb-1">
|
||||
<n-button v-if="state.errorCode === 0" type="tertiary" size="tiny">
|
||||
{{ state.errorMsg }}
|
||||
</n-button>
|
||||
<n-button v-else type="error" size="tiny">
|
||||
{{ state.errorCode }} → {{ state.errorMsg }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">处理耗时:{{ state.takeUpTime }}ms</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">响应时间:{{ timestampToTime(state.timestamp) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { basicProps } from './props';
|
||||
import { timestampToTime } from '@/utils/dateUtil';
|
||||
|
||||
const props = defineProps(basicProps);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.text {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
12
web/src/views/log/log/components/props.ts
Normal file
12
web/src/views/log/log/components/props.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { State } from '@/views/log/log/model';
|
||||
|
||||
export const basicProps = {
|
||||
state: {
|
||||
type: State,
|
||||
default: null,
|
||||
},
|
||||
column: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
};
|
@ -53,7 +53,6 @@
|
||||
const dialog = useDialog();
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
const router = useRouter();
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
|
@ -48,16 +48,15 @@ export const schemas = ref<FormSchema[]>([
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '操作人',
|
||||
componentProps: {
|
||||
placeholder: '请输入操作人ID',
|
||||
placeholder: '请选择操作人',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'url',
|
||||
|
@ -129,18 +129,12 @@
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写API路径地址,可同时作用于server端接口鉴权和web端细粒度权限。一次添加多个权限用,分割
|
||||
请填写API路径地址,可同时作用于server端接口鉴权和web端细粒度权限
|
||||
</n-tooltip>
|
||||
分配权限
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<!-- <n-gi>-->
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- <template #feedback>分配权限存在多个时,权限名称只绑定到第一个权限</template>-->
|
||||
<!-- </n-form-item>-->
|
||||
<!-- </n-gi>-->
|
||||
</n-grid>
|
||||
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
|
@ -8,7 +8,6 @@
|
||||
ref="formRef"
|
||||
label-placement="top"
|
||||
>
|
||||
<n-divider title-placement="left">基础设置</n-divider>
|
||||
<n-form-item label="默认驱动" path="uploadDrive">
|
||||
<n-select
|
||||
placeholder="默认驱动"
|
||||
@ -16,46 +15,16 @@
|
||||
v-model:value="formValue.uploadDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-tabs type="card" size="small" v-model:value="tabName">
|
||||
<n-tab-pane name="local">
|
||||
<template #tab> 本地存储</template>
|
||||
<n-divider title-placement="left">本地存储</n-divider>
|
||||
<n-tab-pane name="local" tab="本地存储">
|
||||
<n-form-item label="本地存储路径" path="uploadLocalPath">
|
||||
<n-input v-model:value="formValue.uploadLocalPath" placeholder="" />
|
||||
<template #feedback>填对外访问的相对路径</template>
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="oss">
|
||||
<template #tab> 阿里云OSS存储</template>
|
||||
<n-divider title-placement="left">阿里云OSS存储</n-divider>
|
||||
<n-tab-pane name="oss" tab="阿里云OSS">
|
||||
<n-form-item label="AccessKey ID" path="uploadOssSecretId">
|
||||
<n-input
|
||||
type="password"
|
||||
@ -102,9 +71,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="cos">
|
||||
<template #tab> 腾讯云COS存储</template>
|
||||
<n-divider title-placement="left">腾讯云COS存储</n-divider>
|
||||
<n-tab-pane name="cos" tab="腾讯云COS">
|
||||
<n-form-item label="APPID" path="uploadCosSecretId">
|
||||
<n-input v-model:value="formValue.uploadCosSecretId" />
|
||||
<template #feedback>
|
||||
@ -138,9 +105,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="qiniu">
|
||||
<template #tab> 七牛云对象存储</template>
|
||||
<n-divider title-placement="left">七牛云对象存储</n-divider>
|
||||
<n-tab-pane name="qiniu" tab="七牛云对象存储">
|
||||
<n-form-item label="AccessKey" path="uploadQiNiuAccessKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@ -183,9 +148,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="ucloud">
|
||||
<template #tab> ucloud对象存储</template>
|
||||
<n-divider title-placement="left">ucloud对象存储</n-divider>
|
||||
<n-tab-pane name="ucloud" tab="UC对象存储">
|
||||
<n-form-item label="公钥" path="uploadUCloudPublicKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@ -237,9 +200,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="minio">
|
||||
<template #tab> minio对象存储</template>
|
||||
<n-divider title-placement="left">minio对象存储</n-divider>
|
||||
<n-tab-pane name="minio" tab="MinIO">
|
||||
<n-form-item label="AccessKey ID" path="uploadMinioAccessKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@ -295,6 +256,45 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
<n-grid x-gap="24" :cols="4" class="mt-4">
|
||||
<n-gi>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="3">
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="4">
|
||||
<n-gi>
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="3">
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
|
Loading…
Reference in New Issue
Block a user