chore: 初始开源发布
iotlcm-app:小程序端 + 用户端服务。 - app/:uni-app 小程序前端(基于 unibest,MIT) - 微信 AppID → YOUR_WX_APPID,uni-app AppID → __UNI__YOURAPPID - 内网后端地址 → admin.iotlcm.example.com - 应用标题与 unibest 模板 README 重写(保留上游致谢与 MIT 声明) - server/:GoFrame 用户端服务(基于 XiuAdmin,Apache-2.0) - module xiuadmin → git.5iot.com/iotlcm-public/iotlcm-app(360 文件) - 支付回调地址 → app.iotlcm.example.com,商户名与应用名泛化 - 真实手机号 → 合法 11 位编造号(保留号段前 3 位 + 后 4 位) - 依赖号码尾部的断言同步更新 - 补 server/LICENSE(Apache-2.0) - 移除内部资产:CI 触发器 - 补根 README,LF 行尾 + .gitattributes 已知:TestSysDept_RefreshDeptAncestors 在源仓同一提交上同样失败,属既有缺陷。
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
// package xgen
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package xgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/addons"
|
||||
genconsts "git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgen/gen_consts"
|
||||
gendao "git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgen/gen_dao"
|
||||
genmodel "git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgen/gen_model"
|
||||
genview "git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgen/gen_view"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/request"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/service"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
const gfCliVersion = "v2.9.6"
|
||||
|
||||
func gfCliCommand(args ...string) string {
|
||||
return "go run github.com/gogf/gf/cmd/gf/v2@" + gfCliVersion + " " + strings.Join(args, " ")
|
||||
}
|
||||
|
||||
func GenTypeSelects(ctx context.Context) (output []*genmodel.SelectGenTypeModel, err error) {
|
||||
output = make([]*genmodel.SelectGenTypeModel, 0)
|
||||
for k, v := range genconsts.GenCodesTypeNameMap {
|
||||
item := &genmodel.SelectGenTypeModel{
|
||||
SelectItemModel: genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Name: v,
|
||||
Label: v,
|
||||
Disabled: false,
|
||||
},
|
||||
Templates: make([]*genmodel.SelectGenTemplateModel, 0),
|
||||
}
|
||||
confName, ok := genconsts.GenCodesTypeConfMap[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
confTemplates := make([]*genmodel.GenCodesConfigCrudTemplate, 0)
|
||||
err = g.Cfg().MustGet(ctx, "xgen.application."+confName+".templates").Scan(&confTemplates)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(confTemplates) == 0 && confName != "crud" {
|
||||
err = g.Cfg().MustGet(ctx, "xgen.application.crud.templates").Scan(&confTemplates)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for index, v := range confTemplates {
|
||||
item.Templates = append(item.Templates, &genmodel.SelectGenTemplateModel{
|
||||
SelectItemModel: genmodel.SelectItemModel{
|
||||
Value: index,
|
||||
Label: v.Group,
|
||||
Name: v.Group,
|
||||
Disabled: false,
|
||||
},
|
||||
IsAddon: v.IsAddon,
|
||||
})
|
||||
}
|
||||
sort.Slice(item.Templates, func(i, j int) bool {
|
||||
return item.Templates[i].Value.(int) < item.Templates[j].Value.(int)
|
||||
})
|
||||
|
||||
output = append(output, item)
|
||||
}
|
||||
return
|
||||
}
|
||||
func DbSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
dbs := g.Cfg().MustGet(ctx, "xgen.selectDbs")
|
||||
if len(dbs.Strings()) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range dbs.Strings() {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: v,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func StatusSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for k, v := range genconsts.GenCodesStatusNameMap {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].Value.(string) < output[j].Value.(string)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func LinkModeSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for k, v := range genconsts.GenCodesJoinNameMap {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].Value.(int) < output[j].Value.(int)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func BuildMethodSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for k, v := range genconsts.GenCodesBuildMethNameMap {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].Value.(int) < output[j].Value.(int)
|
||||
})
|
||||
return
|
||||
}
|
||||
func FormModeSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for _, v := range genview.FMs {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: v,
|
||||
Label: genview.FMMap[v],
|
||||
Name: genview.FMMap[v],
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
func FormRoleSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for k, v := range genview.FRMap {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DictModeSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
dictMode, _, err := service.SysDictType().List(ctx, &model.SysDictTypeListParam{
|
||||
PageInfo: request.PageInfo{
|
||||
Page: 1,
|
||||
PageSize: 2000,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range dictMode {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: v.DictType,
|
||||
Label: v.DictName + "(" + v.DictType + ")",
|
||||
Name: v.DictName,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WhereModeSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for _, v := range genview.WMs {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: v,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TableAlignSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for _, v := range genview.TableAligns {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: v,
|
||||
Label: genview.TableAlignMap[v],
|
||||
Name: genview.TableAlignMap[v],
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TreeStyleTypeSelects(ctx context.Context) (output []*genmodel.SelectItemModel, err error) {
|
||||
output = make([]*genmodel.SelectItemModel, 0)
|
||||
for k, v := range genconsts.GenCodesTreeStyleTypeNameMap {
|
||||
output = append(output, &genmodel.SelectItemModel{
|
||||
Value: k,
|
||||
Label: v,
|
||||
Name: v,
|
||||
Disabled: false,
|
||||
})
|
||||
}
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].Value.(int) < output[j].Value.(int)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func GenCodesSelects(ctx context.Context) (output *genmodel.SelectsModel, err error) {
|
||||
output = &genmodel.SelectsModel{}
|
||||
output.GenType, err = GenTypeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.Db, err = DbSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.Status, err = StatusSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.LinkMode, err = LinkModeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.BuildMethod, err = BuildMethodSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.FormMode, err = FormModeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.WhereMode, err = WhereModeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.FormRole, err = FormRoleSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.DictMode, err = DictModeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.Addons, err = addons.ModuleSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.TableAlign, err = TableAlignSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
output.TreeStyleType, err = TreeStyleTypeSelects(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GenCodesTableSelect(ctx context.Context, params *genmodel.GenCodesTableSelectParam) (output []*genmodel.GenCodesTableSelectModel, err error) {
|
||||
if params == nil || params.DbGroup == "" {
|
||||
return
|
||||
}
|
||||
sql := "SELECT TABLE_NAME as value, TABLE_COMMENT as label FROM information_schema.`TABLES` WHERE TABLE_SCHEMA = ?"
|
||||
config := g.DB(params.DbGroup).GetConfig()
|
||||
disableTables := g.Cfg().MustGet(ctx, "xgen.disableTables").Strings()
|
||||
|
||||
lists := make([]*genmodel.GenCodesTableSelectModel, 0)
|
||||
err = g.DB(params.DbGroup).Ctx(ctx).Raw(sql, config.Name).Scan(&lists)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
patternStr := `addon_(\w+)_`
|
||||
repStr := ``
|
||||
for _, v := range lists {
|
||||
if gstr.InArray(disableTables, v.Value) {
|
||||
continue
|
||||
}
|
||||
newValue := v.Value
|
||||
if config.Prefix != "" {
|
||||
newValue = gstr.SubStrFromEx(v.Value, config.Prefix)
|
||||
}
|
||||
// g.Log().Infof(ctx, "server/internal/library/xgen/xgen_curd.go GenCodesTableSelect newValue:%v config.Prefix:%v", newValue, config.Prefix)
|
||||
if newValue == "" {
|
||||
continue
|
||||
}
|
||||
// 插件移除掉插件表前缀
|
||||
bt, err := gregex.Replace(patternStr, []byte(repStr), []byte(newValue))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// g.Log().Infof(ctx, "server/internal/library/xgen/xgen_curd.go GenCodesTableSelect newValue:%v string(bt):%v", newValue, string(bt))
|
||||
|
||||
row := v
|
||||
row.DefTableComment = v.Label
|
||||
row.DaoName = gstr.CaseCamel(newValue)
|
||||
row.DefVarName = gstr.CaseCamel(string(bt))
|
||||
row.DefAlias = gstr.CaseCamelLower(newValue)
|
||||
row.Name = fmt.Sprintf("%s (%s)", v.Value, v.Label)
|
||||
row.Label = row.Name
|
||||
output = append(output, row)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GenCodesColumnSelect(ctx context.Context, params *genmodel.GenCodesColumnSelectParam) (output []*genmodel.GenCodesColumnSelectModel, err error) {
|
||||
sql := "SELECT COLUMN_NAME as value, COLUMN_COMMENT as label FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?"
|
||||
dbConfig := g.DB(params.DbGroup).GetConfig()
|
||||
|
||||
lists := make([]*genmodel.GenCodesColumnSelectModel, 0)
|
||||
err = g.DB(params.DbGroup).Ctx(ctx).Raw(sql, dbConfig.Name, params.TableName).Scan(&lists)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(lists) == 0 {
|
||||
err = gerror.New("表不存在")
|
||||
return
|
||||
}
|
||||
for _, v := range lists {
|
||||
output = append(output, &genmodel.GenCodesColumnSelectModel{
|
||||
Value: v.Value,
|
||||
Label: v.Label,
|
||||
Name: fmt.Sprintf("%s (%s)", v.Value, v.Label),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GenCodesColumnList(ctx context.Context, params *genmodel.GenCodesColumnListParam) (output []*genmodel.GenCodesColumnListModel, err error) {
|
||||
output, err = genview.TableColumnList(ctx, params)
|
||||
return
|
||||
}
|
||||
|
||||
// GetLoadGenerate 获取本地生成配置
|
||||
func GetLoadGenerate(ctx context.Context) (conf *genmodel.GenCodesConfig, err error) {
|
||||
err = g.Cfg().MustGet(ctx, "xgen").Scan(&conf)
|
||||
return
|
||||
}
|
||||
|
||||
func GenCodesPreview(ctx context.Context, params *genmodel.GenCodesPreviewParam) (output *genmodel.GenCodesPreviewModel, err error) {
|
||||
|
||||
genConfig, err := GetLoadGenerate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
daoConfig, err := gendao.GetDaoConfig(ctx, params.DbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch params.GenType {
|
||||
case genconsts.GenCodesTypeCurd, genconsts.GenCodesTypeTree:
|
||||
return genview.Curd.DoPreview(ctx, &genmodel.CurdPreviewParam{
|
||||
In: params,
|
||||
DaoConfig: daoConfig,
|
||||
Config: genConfig,
|
||||
})
|
||||
default:
|
||||
err = gerror.Newf("生成类型暂不支持!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Build 提交生成
|
||||
func GenCodesBuild(ctx context.Context, params *genmodel.GenCodesBuildParam) (output *genmodel.GenCodesBuildModel, err error) {
|
||||
output = &genmodel.GenCodesBuildModel{}
|
||||
genConfig, err := GetLoadGenerate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
daoConfig, err := gendao.GetDaoConfig(ctx, params.DbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch params.GenType {
|
||||
case genconsts.GenCodesTypeCurd, genconsts.GenCodesTypeTree:
|
||||
pin := params
|
||||
|
||||
return output, genview.Curd.DoBuild(ctx, &genmodel.CurdBuildParam{
|
||||
PreviewIn: &genmodel.CurdPreviewParam{
|
||||
In: pin,
|
||||
DaoConfig: daoConfig,
|
||||
Config: genConfig,
|
||||
},
|
||||
BeforeEvent: genmodel.CurdBuildEvent{"runDao": Dao},
|
||||
AfterEvent: genmodel.CurdBuildEvent{"runService": func(ctx context.Context) (err error) {
|
||||
cfg := gendao.GetServiceConfig()
|
||||
|
||||
// 插件模块,切换到插件下运行gen service
|
||||
if genConfig.Application.Crud.Templates[pin.GenTemplate].IsAddon {
|
||||
// 依然使用配置中的参数,只是将生成路径指向插件模块路径
|
||||
cfg.SrcFolder = "addons/" + pin.AddonName + "/logic"
|
||||
cfg.DstFolder = "addons/" + pin.AddonName + "/service"
|
||||
}
|
||||
err = ServiceWithCfg(ctx, cfg)
|
||||
return
|
||||
}},
|
||||
})
|
||||
default:
|
||||
err = gerror.Newf("生成类型暂不支持!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithCfg 生成业务接口
|
||||
func ServiceWithCfg(ctx context.Context, cfg ...*genmodel.GenServiceConfig) (err error) {
|
||||
c := gendao.GetServiceConfig()
|
||||
if len(cfg) > 0 {
|
||||
c = cfg[0]
|
||||
}
|
||||
cmd := gfCliCommand("gen", "service")
|
||||
|
||||
if c.SrcFolder != "" {
|
||||
cmd += ` -s ` + c.SrcFolder
|
||||
}
|
||||
if c.DstFolder != "" {
|
||||
cmd += ` -d ` + c.DstFolder
|
||||
}
|
||||
if c.DstFileNameCase != "" {
|
||||
cmd += ` -f ` + c.DstFileNameCase
|
||||
}
|
||||
if c.WatchFile != "" {
|
||||
cmd += ` -w ` + c.WatchFile
|
||||
}
|
||||
if c.StPattern != "" {
|
||||
cmd += ` -a ` + c.StPattern
|
||||
}
|
||||
// Do not pass "-l" here. GoFrame v2.9.6 can mis-handle relative paths
|
||||
// on Windows and remove the generated service files it just created.
|
||||
if c.Clear {
|
||||
g.Log().Warning(ctx, "gf gen service clear is disabled on Windows to avoid deleting generated files")
|
||||
}
|
||||
if c.ImportPrefix != "" {
|
||||
cmd += ` -i ` + c.ImportPrefix
|
||||
}
|
||||
if c.Packages != nil {
|
||||
cmd += ` -p ` + strings.Join(c.Packages, ",")
|
||||
}
|
||||
r, err := gproc.ShellExec(gctx.New(), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Log().Info(ctx, "生成业务接口 Stdout", r)
|
||||
return
|
||||
}
|
||||
|
||||
// Dao 生成数据库实体
|
||||
func Dao(ctx context.Context) (err error) {
|
||||
cmd := gfCliCommand("gen", "dao")
|
||||
r, err := gproc.ShellExec(gctx.New(), cmd)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "生成数据库实体 Stderr", r)
|
||||
return err
|
||||
}
|
||||
g.Log().Info(ctx, "生成数据库实体 Stdout", r)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user