package controller import ( "backend/alibaba" "backend/model" "backend/util" "fmt" "os/exec" "strings" "time" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" ) func Copywriting(c *gin.Context) { request := struct { Step int `json:"step"` }{} if err := c.BindJSON(&request); err != nil { failed(c, "参数绑定失败: "+err.Error()) return } switch request.Step { case 0: success(c, map[string]interface{}{ "step": 1, "label": "下载文案文件", "tips": []string{}, "code": 0, }) case 1: CopywritingStep1(c) case 2: CopywritingStep2(c) case 3: CopywritingStep3(c) default: failed(c, "无效的步骤") } util.AddAdminLog(c, "文案自动化脚本", request) } func CopywritingStep1(c *gin.Context) { err := alibaba.DownloadFile() if err != nil { success(c, map[string]interface{}{ "step": 2, "label": "提交git", "tips": []string{ err.Error(), }, "code": 1, }) return } // 执行脚本的逻辑 success(c, map[string]interface{}{ "step": 2, "label": "提交git", "tips": []string{ "下载文案文件DialogueData.xlsx成功", }, "code": 0, }) } func CopywritingStep2(c *gin.Context) { time.Sleep(time.Second) code := 0 repoDir := `/data/docs` file := `config/DialogueData.xlsx` // git pull if out, err := exec.Command("git", "-C", repoDir, "pull").CombinedOutput(); err != nil { scritp_fail(c, "git pull 失败: "+err.Error()+": "+string(out)) return } // git add if out, err := exec.Command("git", "-C", repoDir, "add", file).CombinedOutput(); err != nil { scritp_fail(c, "git add 失败: "+err.Error()+": "+string(out)) return } // git commit (ignore non-fatal commit output/errors like "nothing to commit") exec.Command("git", "-C", repoDir, "commit", "-m", "Update DialogueData.xlsx").Run() // git push if out, err := exec.Command("git", "-C", repoDir, "push").CombinedOutput(); err != nil { scritp_fail(c, "git push 失败: "+err.Error()+": "+string(out)) return } _ = code // 执行脚本的逻辑 success(c, map[string]interface{}{ "step": 3, "label": "修改翻译表", "tips": []string{}, "code": 0, }) } func CopywritingStep3(c *gin.Context) { file := `/data/docs/config/DialogueData.xlsx` f, err := excelize.OpenFile(file) if err != nil { failed(c, "打开文件失败: "+err.Error()) return } defer f.Close() rows, err := f.GetRows("DialogueData") if err != nil { failed(c, "读取sheet失败: "+err.Error()) return } type Dialogue struct { Id int Key string Dialogue string } dialogueMap := make(map[string]Dialogue) for i, row := range rows { // 跳过标题行(如果有) if i < 2 { continue } var dVal, iVal string if len(row) > 3 { dVal = row[3] // D列,0-based 索引 3 } if len(row) > 8 { iVal = row[8] // I列,0-based 索引 8 } var lVal string if len(row) > 11 { lVal = row[11] // L列,0-based 索引 11 } if lVal != "" { continue } if dVal == "" || iVal == "" { continue } dialogueMap[dVal] = Dialogue{ Key: dVal, Dialogue: iVal, Id: i - 2, // 减去标题行 } } type db_data struct { Id int `db:"Id"` Key string `db:"key"` EnUs string `db:"en_us"` OldValue string } var dbDatas []db_data db := util.MPool.GetGameDB() defer db.Close() if db == nil { scritp_fail(c, "获取数据库连接失败") return } err = db.Select(&dbDatas, "SELECT `Id`, `key`, `en_us` FROM `language`") if err != nil { scritp_fail(c, "查询语言表失败: "+err.Error()) return } updateData := []db_data{} for _, item := range dbDatas { if val, ok := dialogueMap[item.Key]; ok { if val.Dialogue != item.EnUs { item.OldValue = item.EnUs item.EnUs = val.Dialogue updateData = append(updateData, item) } delete(dialogueMap, item.Key) } } for _, item := range updateData { _, err := db.Exec("UPDATE `language` SET `en_us` = ? WHERE `key` = ?", item.EnUs, item.Key) if err != nil { scritp_fail(c, "更新语言表失败: "+err.Error()) return } _, err = db.Exec("insert into language_op (`LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update`, `Role`) values (?, ?, ?, ?, ?,?,?)", item.Id, "en_us", item.OldValue, item.EnUs, "Edit", util.Now(), "scripts") } for _, v := range dialogueMap { result, err := db.Exec("INSERT INTO `language` (`key`, `en_us`) VALUES (?, ?)", v.Key, v.Dialogue) if err != nil { scritp_fail(c, "插入语言表失败: "+err.Error()) return } id, _ := result.LastInsertId() _, err = db.Exec("insert into language_op (`LanguageId`, `Field`, `OldValue`, `NewValue`, `Type`, `Update`, `Role`) values (?, ?, ?, ?, ?,?,?)", id, "All", "", v.Dialogue, "Add", util.Now(), "scripts") } // 将结果放到 gin 上下文,供后续使用 c.Set("DialogueMap", dialogueMap) tips := []string{} if len(updateData) > 0 { tips = append(tips, fmt.Sprintf("更新了 %d 条翻译内容", len(updateData))) for _, v := range updateData { tips = append(tips, fmt.Sprintf("Key: %s", v.Key)) } } if len(dialogueMap) > 0 { tips = append(tips, fmt.Sprintf("新增了 %d 条翻译内容", len(dialogueMap))) for _, v := range dialogueMap { tips = append(tips, fmt.Sprintf("Key: %s", v.Key)) } } // 执行脚本的逻辑 success(c, map[string]interface{}{ "step": -1, "label": "脚本执行成功", "tips": tips, "code": 0, }) } func scritp_fail(c *gin.Context, err string) { success(c, map[string]interface{}{ "step": -1, "label": "", "tips": []string{ err, }, "code": 1, }) } func CopyOnline(c *gin.Context) { request := struct { Step int `json:"step"` }{} if err := c.BindJSON(&request); err != nil { failed(c, "参数绑定失败: "+err.Error()) return } switch request.Step { case 0: success(c, map[string]interface{}{ "step": 1, "label": "复制数据库", "tips": []string{}, "code": 0, }) case 1: CopyOnlineStep1(c) case 2: CopyOnlineStep2(c) case 3: CopyOnlineStep3(c) case 4: CopyOnlineStep4(c) default: failed(c, "无效的步骤") } util.AddAdminLog(c, "文案自动化脚本", request) } func CopyOnlineStep2(c *gin.Context) { // 关闭QA环境服务 time.Sleep(time.Second) servers := util.GetAllServersByAppId(2) // AppId=2 QA环境 for _, server := range servers { if server.Status != 1 { continue } s := &model.Server{AppId: 2, ServerId: server.ServerId} output, err := s.StopServer() if err != nil { // 如果错误信息包含"未启动",则忽略该错误 if !strings.Contains(output, "未启动") { scritp_fail(c, "停止QA环境服务失败: "+err.Error()) return } } } success(c, map[string]interface{}{ "step": 3, "label": "写入数据到QA环境", "tips": []string{}, "code": 0, }) } func CopyOnlineStep1(c *gin.Context) { // mysqldump 复制数据库 nodeInfo := util.GetNodeByName("devops") SshClient, err := util.NewSshClient(nodeInfo) if err != nil { scritp_fail(c, "连接devops节点失败: "+err.Error()) return } defer SshClient.Close() cmd := "ansible-playbook /data/devops/playbook/script_copy_us_step_1.yml -i /data/devops/playbook/hosts" output, err := SshClient.RunCommand(cmd) if err != nil { scritp_fail(c, "执行复制数据库脚本step1失败: "+err.Error()+": "+output) return } time.Sleep(time.Second) success(c, map[string]interface{}{ "step": 2, "label": "关闭QA环境服务", "tips": []string{}, "code": 0, }) } func CopyOnlineStep3(c *gin.Context) { // 写入数据到QA环境 nodeInfo := util.GetNodeByName("devops") SshClient, err := util.NewSshClient(nodeInfo) if err != nil { scritp_fail(c, "连接devops节点失败: "+err.Error()) return } defer SshClient.Close() cmd := "ansible-playbook /data/devops/playbook/script_copy_us_step_2.yml -i /data/devops/playbook/hosts" output, err := SshClient.RunCommand(cmd) if err != nil { scritp_fail(c, "执行复制数据库脚本step1失败: "+err.Error()+": "+output) return } time.Sleep(time.Second) success(c, map[string]interface{}{ "step": 4, "label": "启动QA环境服务", "tips": []string{}, "code": 0, }) } func CopyOnlineStep4(c *gin.Context) { // 启动QA环境服务 servers := util.GetAllServersByAppId(2) // AppId=2 QA环境 for _, server := range servers { if server.Status == 1 { continue } s := &model.Server{AppId: 2, ServerId: server.ServerId} _, err := s.StartServer() if err != nil { scritp_fail(c, "启动QA环境服务失败: "+err.Error()) return } } str := ` # US环境同步自动化脚本完成 所有人 ` alibaba.SendStandardMsg("US环境同步自动化脚本完成", str, "green") time.Sleep(time.Second) success(c, map[string]interface{}{ "step": -1, "label": "脚本执行成功", "tips": []string{}, "code": 0, }) }