343 lines
11 KiB
Go
343 lines
11 KiB
Go
package model
|
|
|
|
import (
|
|
"backend/common"
|
|
"backend/util"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/xuri/excelize/v2"
|
|
)
|
|
|
|
type Language struct {
|
|
Id int `json:"Id" db:"Id"`
|
|
Key string `json:"key" db:"key"`
|
|
EN_US string `json:"en_US" db:"en_US"`
|
|
ZH_CN string `json:"zh_CN" db:"zh_CN"`
|
|
PT_BR string `json:"pt_BR" db:"pt_BR"`
|
|
ES_LATAM string `json:"es_LATAM" db:"es_LATAM"`
|
|
Url string `json:"url"`
|
|
}
|
|
|
|
type LanguageOp struct {
|
|
Id int `json:"Id" db:"Id"`
|
|
LanguageId int `json:"LanguageId" db:"LanguageId"`
|
|
Field string `json:"Field" db:"Field"`
|
|
OldValue string `json:"OldValue" db:"OldValue"`
|
|
NewValue string `json:"NewValue" db:"NewValue"`
|
|
Type string `json:"Type" db:"Type"`
|
|
Update int `json:"Update" db:"Update"`
|
|
}
|
|
|
|
type LanguageMod struct {
|
|
PageSize int `json:"PageSize"`
|
|
CurrentPage int `json:"CurrentPage"`
|
|
StartTime int `json:"StartTime"`
|
|
EndTime int `json:"EndTime"`
|
|
SearchField string `json:"SearchField"`
|
|
SearchValue string `json:"SearchValue"`
|
|
}
|
|
|
|
func (l *LanguageMod) LanguageList(account string) (map[string]interface{}, error) {
|
|
Db := util.MPool.GetGameDB()
|
|
column := ""
|
|
defer Db.Close()
|
|
var languages []*Language
|
|
SearchSQL := ""
|
|
if l.SearchField != "" {
|
|
if l.SearchValue != "" {
|
|
escaped := strings.ReplaceAll(l.SearchValue, "'", "''")
|
|
SearchSQL = " `" + l.SearchField + "` like '%" + escaped + "%' "
|
|
} else {
|
|
SearchSQL = " `" + l.SearchField + "` = '' "
|
|
}
|
|
|
|
}
|
|
AccountConfig := common.GetTranlaterConfig(account)
|
|
if AccountConfig != nil {
|
|
column = AccountConfig.Colunm
|
|
keysArr := strings.Split(AccountConfig.Keys, ",")
|
|
if len(keysArr) > 0 {
|
|
keyConditions := make([]string, len(keysArr))
|
|
for i, key := range keysArr {
|
|
escapedKey := strings.ReplaceAll(strings.TrimSpace(key), "'", "''")
|
|
keyConditions[i] = fmt.Sprintf("`key` like '%%%s%%'", escapedKey)
|
|
}
|
|
if SearchSQL != "" {
|
|
SearchSQL += " AND "
|
|
}
|
|
if AccountConfig.KeysType == "no_include" {
|
|
SearchSQL += " NOT (" + strings.Join(keyConditions, " or ") + ") "
|
|
} else {
|
|
SearchSQL += " (" + strings.Join(keyConditions, " or ") + ") "
|
|
}
|
|
}
|
|
}
|
|
if SearchSQL != "" {
|
|
SearchSQL = " where " + SearchSQL
|
|
}
|
|
sql := fmt.Sprintf("SELECT `Id`, `key`, `en_US`, `zh_CN`, `pt_BR`, `es_LATAM` FROM language %s LIMIT ?, ?", SearchSQL)
|
|
err := Db.Select(&languages, sql, (l.CurrentPage-1)*l.PageSize, l.PageSize)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var languageOp []*LanguageOp
|
|
err = Db.Select(&languageOp, "SELECT `Id`, `LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update` FROM language_op where `Update` >= ? and `Update` <= ? ", l.StartTime, l.EndTime)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var total int
|
|
err = Db.QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM language %s", SearchSQL)).Scan(&total)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := range languages {
|
|
url := util.GetLanguageImageURL(languages[i].Key)
|
|
if url != "" {
|
|
//url = "../../../../public/" + url
|
|
url = "./" + url
|
|
}
|
|
languages[i].Url = url
|
|
}
|
|
return map[string]interface{}{
|
|
"data": languages,
|
|
"op": languageOp,
|
|
"total": total,
|
|
"column": column,
|
|
}, nil
|
|
}
|
|
|
|
func (l *LanguageMod) LanguageListAll() (map[string]interface{}, error) {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
var languages []*Language
|
|
err := Db.Select(&languages, "SELECT `Id`, `key`, `en_US`, `zh_CN`,`pt_BR`, `es_LATAM` FROM language")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var total int
|
|
err = Db.QueryRow("SELECT COUNT(*) FROM language").Scan(&total)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// 导出为 xlsx 文件
|
|
f := excelize.NewFile()
|
|
mainSheet := "client"
|
|
backendSheet := "backend"
|
|
// 创建主表
|
|
if _, err := f.NewSheet(mainSheet); err != nil {
|
|
return nil, err
|
|
}
|
|
// 创建 backend 子表
|
|
if _, err := f.NewSheet(backendSheet); err != nil {
|
|
return nil, err
|
|
}
|
|
SaveTime, _ := util.GetLanguageLastUpdate()
|
|
ExportTime, _ := util.GetLanguageExportLastUpdate()
|
|
if SaveTime <= ExportTime {
|
|
return map[string]interface{}{
|
|
"code": 1,
|
|
"msg": "No changes since last export",
|
|
}, nil
|
|
}
|
|
// 写表头(在主表和 backend 表都写一份)
|
|
headers := []string{"Id", "key", "en_US", "zh_CN", "pt_BR", "es_LATAM"}
|
|
cols := []string{"A", "B", "C", "D", "E", "F"}
|
|
for i, h := range headers {
|
|
if err := f.SetCellValue(mainSheet, cols[i]+"1", h); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, cols[i]+"1", h); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
headers2 := []string{"编号", "键", "英文", "简体中文", "葡萄牙语(巴西)", "西班牙语(拉丁美洲)"}
|
|
for i, h := range headers2 {
|
|
if err := f.SetCellValue(mainSheet, cols[i]+"2", h); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, cols[i]+"2", h); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
// 写数据行:分别维护主表和 backend 表的行号
|
|
mainRowIndex := 3
|
|
backendRowIndex := 3
|
|
for _, lang := range languages {
|
|
if strings.HasPrefix(lang.Key, "backend") {
|
|
row := fmt.Sprintf("%d", backendRowIndex)
|
|
if err := f.SetCellValue(backendSheet, "A"+row, lang.Id); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, "B"+row, lang.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, "C"+row, lang.EN_US); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, "D"+row, lang.ZH_CN); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, "E"+row, lang.PT_BR); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(backendSheet, "F"+row, lang.ES_LATAM); err != nil {
|
|
return nil, err
|
|
}
|
|
backendRowIndex++
|
|
} else {
|
|
row := fmt.Sprintf("%d", mainRowIndex)
|
|
if err := f.SetCellValue(mainSheet, "A"+row, lang.Id); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(mainSheet, "B"+row, lang.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(mainSheet, "C"+row, lang.EN_US); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(mainSheet, "D"+row, lang.ZH_CN); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(mainSheet, "E"+row, lang.PT_BR); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := f.SetCellValue(mainSheet, "F"+row, lang.ES_LATAM); err != nil {
|
|
return nil, err
|
|
}
|
|
mainRowIndex++
|
|
}
|
|
}
|
|
// 在 /data/docs 仓库中添加并提交该文件
|
|
repoDir := "/data/docs"
|
|
cmd := exec.Command("git", "checkout", "main")
|
|
cmd.Dir = repoDir
|
|
if _, err := cmd.CombinedOutput(); err != nil {
|
|
// try to fetch and force-create/reset local main from origin/main
|
|
fetch := exec.Command("git", "fetch", "origin", "main")
|
|
fetch.Dir = repoDir
|
|
if fout, ferr := fetch.CombinedOutput(); ferr != nil {
|
|
return nil, fmt.Errorf("git fetch failed: %v: %s", ferr, string(fout))
|
|
}
|
|
cmd = exec.Command("git", "checkout", "-B", "main", "origin/main")
|
|
cmd.Dir = repoDir
|
|
if out2, err2 := cmd.CombinedOutput(); err2 != nil {
|
|
return nil, fmt.Errorf("git checkout main failed: %v: %s", err2, string(out2))
|
|
}
|
|
}
|
|
cmd = exec.Command("git", "pull")
|
|
cmd.Dir = repoDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return nil, fmt.Errorf("git pull failed: %v: %s", err, string(out))
|
|
}
|
|
// 保存到临时文件
|
|
// 保存到指定目录
|
|
pathDir := "/data/docs/config"
|
|
if err := os.MkdirAll(pathDir, 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
path := filepath.Join(pathDir, "AllLanguage.xlsx")
|
|
if err := f.SaveAs(path); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
relPath, err := filepath.Rel(repoDir, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd = exec.Command("git", "add", relPath)
|
|
cmd.Dir = repoDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return nil, fmt.Errorf("git add failed: %v: %s", err, string(out))
|
|
}
|
|
|
|
commitMsg := fmt.Sprintf("Export AllLanguage.xlsx at %s", time.Now().Format(time.RFC3339))
|
|
cmd = exec.Command("git", "commit", "-m", commitMsg)
|
|
cmd.Dir = repoDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
// 忽略 "nothing to commit" 情形
|
|
if !strings.Contains(string(out), "nothing to commit") {
|
|
return nil, fmt.Errorf("git commit failed: %v: %s", err, string(out))
|
|
}
|
|
}
|
|
cmd = exec.Command("git", "push", "origin", "main")
|
|
cmd.Dir = repoDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return nil, fmt.Errorf("git push failed: %v: %s", err, string(out))
|
|
}
|
|
util.SaveLanguageExportLastUpdate(util.Now())
|
|
// 将文件路径返回到调用方
|
|
return map[string]interface{}{
|
|
// "data": languages,
|
|
"total": total,
|
|
}, nil
|
|
}
|
|
|
|
func (l *LanguageMod) LanguageSave(langList []LanguageOp, admin string) error {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
for _, lang := range langList {
|
|
_, err := Db.Exec("UPDATE language SET `"+lang.Field+"` = ? WHERE Id = ?", lang.NewValue, lang.LanguageId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = Db.Exec("insert into language_op (`LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update`, `Role`) values (?, ?, ?, ?, ?,?,?)", lang.LanguageId, lang.Field, lang.OldValue, lang.NewValue, lang.Type, util.Now(), admin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// 删除 key 包含 "obsolete" 的记录
|
|
if _, err := Db.Exec("DELETE FROM language WHERE `key` LIKE ?", "%obsolete%"); err != nil {
|
|
return err
|
|
}
|
|
util.SaveLanguageLastUpdate(util.Now())
|
|
return nil
|
|
}
|
|
|
|
func (l *LanguageMod) LanguageAdd(langList []Language, admin string) error {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
for _, lang := range langList {
|
|
res, err := Db.Exec("INSERT INTO language (`key`, `en_US`, `zh_CN`, `pt_BR`) VALUES (?, ?, ?, ?)", lang.Key, lang.EN_US, lang.ZH_CN, lang.PT_BR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lastId, err := res.LastInsertId()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lang.Id = int(lastId)
|
|
_, err = Db.Exec("insert into language_op (`LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update`, `Role`) values (?, ?, ?, ?, ?,?,?)", lang.Id, "All", "", lang.EN_US+"|"+lang.ZH_CN+"|"+lang.PT_BR, "Add", util.Now(), admin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
util.SaveLanguageLastUpdate(util.Now())
|
|
return nil
|
|
}
|
|
|
|
func (l *LanguageMod) LanguageDelete(key string, admin string) error {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
var lang Language
|
|
err := Db.Get(&lang, "SELECT `Id`, `key`, `en_US`, `zh_CN`, `pt_BR` FROM language WHERE `key` = ?", key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = Db.Exec("DELETE FROM language WHERE `key` = ?", key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = Db.Exec("insert into language_op (`LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update`, `Role`) values (?, ?, ?, ?, ?,?,?)", lang.Id, "All", lang.EN_US+"|"+lang.ZH_CN+"|"+lang.PT_BR, "", "Delete", util.Now(), admin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
util.SaveLanguageLastUpdate(util.Now())
|
|
return nil
|
|
}
|