1.新增短信模版相关接口;
This commit is contained in:
parent
5a618d8c95
commit
fd3414f7c7
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@ const (
|
|||
ShowCount = 100 // 前端展示手机号数量
|
||||
)
|
||||
|
||||
// SmsTask 短信下行记录
|
||||
type SmsTask struct {
|
||||
models.Model
|
||||
|
||||
|
@ -27,6 +28,7 @@ type SmsTask struct {
|
|||
ScheduleTime *time.Time `gorm:"schedule_time"` // 计划发送时间(定时时间)
|
||||
}
|
||||
|
||||
// SmsTaskBatch 短信批量任务记录
|
||||
type SmsTaskBatch struct {
|
||||
models.Model
|
||||
|
||||
|
@ -45,6 +47,7 @@ type SmsTaskBatch struct {
|
|||
ScheduleTime *time.Time `gorm:"schedule_time"` // 计划发送时间(定时时间)
|
||||
}
|
||||
|
||||
// SmsSendRecord 短信发送明细
|
||||
type SmsSendRecord struct {
|
||||
models.Model
|
||||
|
||||
|
@ -70,6 +73,7 @@ type SensitiveWord struct {
|
|||
IsEnabled bool `json:"is_enabled" gorm:"default:1;column:is_enabled;comment:是否启用"`
|
||||
}
|
||||
|
||||
// SmsUplinkLog 短信上行记录
|
||||
type SmsUplinkLog struct {
|
||||
models.Model
|
||||
|
||||
|
@ -78,6 +82,7 @@ type SmsUplinkLog struct {
|
|||
BatchID string `gorm:"column:batch_id;type:varchar(64);not null" json:"batch_id"` // 下行短信批次 ID
|
||||
}
|
||||
|
||||
// SmsSignatureRealname 签名实名制
|
||||
type SmsSignatureRealname struct {
|
||||
models.Model
|
||||
|
||||
|
@ -100,12 +105,21 @@ type SmsSignatureRealname struct {
|
|||
IsActive int `json:"is_active"` // 是否有效(0 无效;1 有效)
|
||||
}
|
||||
|
||||
// SmsContactCategory 通讯录分类
|
||||
type SmsContactCategory struct {
|
||||
models.Model
|
||||
Name string `json:"name" gorm:"type:varchar(100);not null"`
|
||||
ParentID uint64 `json:"parent_id" gorm:"default:0"`
|
||||
Children []SmsContactCategory `json:"children,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
// SmsContact 通讯录
|
||||
type SmsContact struct {
|
||||
models.Model
|
||||
|
||||
CooperativeNumber string `gorm:"column:cooperative_number"` // 合作商编号
|
||||
CooperativeName string `gorm:"column:cooperative_name"` // 合作商名称
|
||||
CategoryID uint64 `json:"category_id" gorm:"default:0"`
|
||||
CooperativeNumber string `json:"cooperative_number"` // 合作商编号
|
||||
CooperativeName string `json:"cooperative_name"` // 合作商名称
|
||||
Name string `json:"name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Gender string `json:"gender"`
|
||||
|
@ -115,6 +129,75 @@ type SmsContact struct {
|
|||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// SmsPhraseCategory 短语分类
|
||||
type SmsPhraseCategory struct {
|
||||
models.Model
|
||||
Name string `json:"name" gorm:"type:varchar(100);not null"`
|
||||
ParentID uint64 `json:"parent_id" gorm:"default:0"`
|
||||
Children []SmsPhraseCategory `json:"children,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
// SmsPhrase 通讯录-常用短语
|
||||
type SmsPhrase struct {
|
||||
models.Model
|
||||
|
||||
Content string `json:"content" gorm:"type:varchar(255);not null"`
|
||||
CategoryID uint `json:"category_id" gorm:"default:0"`
|
||||
}
|
||||
|
||||
// SmsCommonNumber 常用号码列表
|
||||
type SmsCommonNumber struct {
|
||||
models.Model
|
||||
|
||||
Name string `json:"name"`
|
||||
PhoneNumbers string `json:"phone_numbers"` // 如:"12345678901,13322223333"
|
||||
PhoneCount int `json:"phone_count" gorm:"-"` // 号码数量(从 phone_numbers 计算)
|
||||
}
|
||||
|
||||
// SmsBlackList 黑名单列表
|
||||
type SmsBlackList struct {
|
||||
models.Model
|
||||
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// SmsTemplate 短信模版表
|
||||
type SmsTemplate struct {
|
||||
models.Model
|
||||
|
||||
CooperativeNumber string `gorm:"column:cooperative_number"` // 合作商编号
|
||||
CooperativeName string `gorm:"column:cooperative_name"` // 合作商名称
|
||||
Content string `json:"content"` // 模版内容(必填)
|
||||
ExpireAt *time.Time `json:"expire_at"` // 到期时间(有效期)
|
||||
Remark string `json:"remark"` // 备注
|
||||
Status int `json:"status"` // 状态:0=审核中 1=正常 2=拒绝 3=过期
|
||||
}
|
||||
|
||||
type ContactInput struct {
|
||||
CategoryID []uint64 `json:"category_id" binding:"required"`
|
||||
ID uint64 `json:"id"` // 联系人ID
|
||||
Name string `json:"name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Gender string `json:"gender"`
|
||||
BirthdayStr string `json:"birthday"` // 先用 string 接收
|
||||
Company string `json:"company"`
|
||||
Address string `json:"address"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type EditContactInput struct {
|
||||
CategoryID uint64 `json:"category_id" binding:"required"`
|
||||
ID uint64 `json:"id"` // 联系人ID
|
||||
Name string `json:"name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Gender string `json:"gender"`
|
||||
BirthdayStr string `json:"birthday"` // 先用 string 接收
|
||||
Company string `json:"company"`
|
||||
Address string `json:"address"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type MassImportPhoneResp struct {
|
||||
List []string `json:"list"` // 加密后的数据
|
||||
ImportSerialNumber string `json:"import_serial_number"` // 导入excel返回的编号
|
||||
|
@ -272,12 +355,40 @@ type SignatureRealnameQueryResp struct {
|
|||
TotalPage int64 `json:"total_page"`
|
||||
}
|
||||
|
||||
type AddContactCategoryReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
ParentID uint `json:"parent_id"` // 默认 0 表示顶级
|
||||
}
|
||||
|
||||
type EditContactCategoryReq struct {
|
||||
ID uint `json:"id" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
// DeleteContactCategoryRequest 删除通讯录分类请求
|
||||
type DeleteContactCategoryRequest struct {
|
||||
IDs []uint `json:"ids" binding:"required"` // 要删除的分类ID列表
|
||||
}
|
||||
|
||||
// ListContactCategoryRequest 查询通讯录分类树的请求
|
||||
type ListContactCategoryRequest struct {
|
||||
CategoryID uint64 `json:"category_id"` // 为空表示查询整个树
|
||||
}
|
||||
|
||||
type SmsContactCategoryTree struct {
|
||||
ID uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ParentID uint64 `json:"parent_id"`
|
||||
Children []SmsContactCategoryTree `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// ContactQuery 请求结构体
|
||||
type ContactQuery struct {
|
||||
Name string `form:"name"` // 模糊搜索
|
||||
PhoneNumber string `form:"phone_number"` // 模糊搜索
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"page_size"`
|
||||
CategoryID []uint64 `json:"category_id" binding:"required"`
|
||||
Name string `form:"name"` // 模糊搜索
|
||||
PhoneNumber string `form:"phone_number"` // 模糊搜索
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"page_size"`
|
||||
}
|
||||
|
||||
// ContactQueryResp 响应结构体
|
||||
|
@ -292,3 +403,205 @@ type ContactQueryResp struct {
|
|||
type ContactDeleteRequest struct {
|
||||
ContactIDs []uint `json:"contact_ids" binding:"required"` // 要删除的记录ID列表
|
||||
}
|
||||
|
||||
// ExportContactsRequest 导出联系人请求参数
|
||||
type ExportContactsRequest struct {
|
||||
IDs []uint `json:"ids"` // 联系人ID列表(优先)
|
||||
All bool `json:"all"` // 是否导出全部
|
||||
}
|
||||
|
||||
type ExportContactsResp struct {
|
||||
ExportUrl string `json:"export_url"` // 下载链接
|
||||
}
|
||||
|
||||
type AddPhraseCategoryReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
ParentID uint `json:"parent_id"` // 默认 0 表示顶级
|
||||
}
|
||||
|
||||
type EditPhraseCategoryReq struct {
|
||||
ID uint `json:"id" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
// DeletePhraseCategoryRequest 删除短语分类请求
|
||||
type DeletePhraseCategoryRequest struct {
|
||||
IDs []uint `json:"ids" binding:"required"` // 要删除的分类ID列表
|
||||
}
|
||||
|
||||
// SmsPhraseQuery 查询参数
|
||||
type SmsPhraseQuery struct {
|
||||
Content string `form:"content" binding:"required"` // 模糊搜索内容
|
||||
CategoryID uint `form:"category_id"` // 所属分类ID
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"page_size"`
|
||||
}
|
||||
|
||||
type SmsPhraseListResp struct {
|
||||
List []SmsPhrase `json:"list"` // 短语列表
|
||||
Total int64 `json:"total"` // 总条数
|
||||
Page int `json:"page"` // 当前页
|
||||
PageSize int `json:"page_size"` // 每页大小
|
||||
TotalPage int64 `json:"total_page"` // 总页数
|
||||
}
|
||||
|
||||
// SmsPhraseAddOrEdit 新增或编辑参数
|
||||
type SmsPhraseAddOrEdit struct {
|
||||
ID uint `json:"id"` // 编辑时用
|
||||
Content string `json:"content" binding:"required"`
|
||||
CategoryID uint `json:"category_id" binding:"required"`
|
||||
}
|
||||
|
||||
// SmsPhraseBatchDeleteReq 批量删除
|
||||
type SmsPhraseBatchDeleteReq struct {
|
||||
IDs []uint `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
// ListPhraseCategoryRequest 查询短语分类树的请求
|
||||
type ListPhraseCategoryRequest struct {
|
||||
CategoryID uint64 `json:"category_id"` // 为空表示查询整个树
|
||||
}
|
||||
|
||||
type SmsPhraseCategoryTree struct {
|
||||
ID uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ParentID uint64 `json:"parent_id"`
|
||||
Children []SmsPhraseCategoryTree `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// SmsCommonNumberQuery 查询
|
||||
type SmsCommonNumberQuery struct {
|
||||
Name string `json:"name"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
}
|
||||
|
||||
// SmsCommonNumberAddReq 添加常用号码请求结构体
|
||||
type SmsCommonNumberAddReq struct {
|
||||
Name string `json:"name" binding:"required"` // 名称
|
||||
PhoneList []string `json:"phone_list" binding:"required"` // 号码列表
|
||||
}
|
||||
|
||||
// SmsCommonNumberAppendReq 追加常用号码请求结构体
|
||||
type SmsCommonNumberAppendReq struct {
|
||||
ID int64 `json:"id" binding:"required"` // 记录ID
|
||||
PhoneList []string `json:"phone_list" binding:"required"` // 需要追加的号码列表
|
||||
}
|
||||
|
||||
// SmsCommonNumberDetailReq 常用号码详情
|
||||
type SmsCommonNumberDetailReq struct {
|
||||
ID int64 `json:"id" binding:"required"` // 记录ID
|
||||
}
|
||||
|
||||
// SmsCommonNumberDeleteReq 删除
|
||||
type SmsCommonNumberDeleteReq struct {
|
||||
Ids []uint64 `json:"ids"`
|
||||
}
|
||||
|
||||
// SmsCommonNumberExportReq 导出
|
||||
type SmsCommonNumberExportReq struct {
|
||||
All bool `json:"all"` // 是否导出全部
|
||||
Ids []uint64 `json:"ids"`
|
||||
}
|
||||
|
||||
type SmsCommonNumberExportResp struct {
|
||||
ExportUrl string `json:"export_url"` // 下载链接
|
||||
}
|
||||
|
||||
type SmsCommonNumberListResp struct {
|
||||
List []SmsCommonNumber `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
TotalPage int64 `json:"totalPage"`
|
||||
}
|
||||
|
||||
type BlacklistAddReq struct {
|
||||
PhoneList []string `json:"phone_list" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// ExportBlacklistRequest 导出黑名单请求
|
||||
type ExportBlacklistRequest struct {
|
||||
All bool `json:"all"` // 是否导出全部
|
||||
Ids []string `json:"ids"` // 指定导出的手机号ID
|
||||
}
|
||||
|
||||
// ExportBlacklistResp 导出响应
|
||||
type ExportBlacklistResp struct {
|
||||
ExportUrl string `json:"export_url"`
|
||||
}
|
||||
|
||||
type BlacklistQuery struct {
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type BlacklistListResp struct {
|
||||
List []SmsBlackList `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
TotalPage int64 `json:"total_page"`
|
||||
}
|
||||
|
||||
// SmsBlacklistBatchDeleteReq 批量删除黑名单请求
|
||||
type SmsBlacklistBatchDeleteReq struct {
|
||||
IDs []uint `json:"ids"` // 黑名单记录ID
|
||||
}
|
||||
|
||||
// SmsTemplateQuery 短信模版查询参数
|
||||
type SmsTemplateQuery struct {
|
||||
Content string `json:"content"` // 模版内容模糊查询
|
||||
Status int `json:"status"` // 模版状态(0=待审核,1=正常,2=审核拒绝,3=已过期)
|
||||
CreateStart time.Time `json:"create_start"` // 创建时间起
|
||||
CreateEnd time.Time `json:"create_end"` // 创建时间止
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// SmsTemplateListResp 返回模版列表结构
|
||||
type SmsTemplateListResp struct {
|
||||
List []SmsTemplate `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
TotalPage int64 `json:"total_page"`
|
||||
}
|
||||
|
||||
// SmsTemplateExportReq 短信模版导出请求
|
||||
type SmsTemplateExportReq struct {
|
||||
Ids []uint `json:"ids"` // 选择的模版 ID 列表
|
||||
All bool `json:"all"` // 是否导出全部
|
||||
}
|
||||
|
||||
// ExportTemplateResp 导出结果
|
||||
type ExportTemplateResp struct {
|
||||
ExportUrl string `json:"export_url"` // 下载地址
|
||||
}
|
||||
|
||||
type ApproveTemplateRequest struct {
|
||||
ID uint `json:"id"`
|
||||
Status int `json:"status"` // 1 正常, 2 审核不通过
|
||||
}
|
||||
|
||||
// SmsTemplateUpdateRequest 修改短信模版请求
|
||||
type SmsTemplateUpdateRequest struct {
|
||||
ID uint `json:"id" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
ExpireAt *time.Time `json:"expire_at"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// DeleteIdsRequest 批量删除模版时使用
|
||||
type DeleteIdsRequest struct {
|
||||
IDs []uint `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
// SmsTemplateCreateRequest 创建短信模版请求
|
||||
type SmsTemplateCreateRequest struct {
|
||||
Content string `json:"content" binding:"required"` // 模版内容
|
||||
ExpireAt *time.Time `json:"expire_at"` // 到期时间
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
|
|
|
@ -39,9 +39,43 @@ func registerSmsManageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMidd
|
|||
sms.POST("/signature_realname/update", api.UpdateSignatureRealname) // 编辑实名签名
|
||||
sms.POST("/signature_realname/delete", api.DeleteSignatureRealname) // 批量删除签名实名记录
|
||||
|
||||
sms.POST("/contacts/list", api.ListContacts) // 查询通讯录列表
|
||||
sms.POST("/contacts/add", api.AddContact) // 新增联系人
|
||||
sms.POST("/contacts/edit", api.EditContact) // 编辑联系人
|
||||
sms.POST("/contacts/batch_delete", api.BulkDeleteContacts) // 批量删除联系人
|
||||
sms.POST("/contacts_category/add", api.AddContactsCategory) // 新增通讯录分类节点
|
||||
sms.POST("/contacts_category/edit", api.EditContactsCategory) // 编辑通讯录分类节点
|
||||
sms.POST("/contacts_category/delete", api.DeleteContactsCategories) // 删除通讯录分类
|
||||
sms.POST("/contacts_category/list", api.ListContactsCategories) // 查询通讯录分类列表(树形结构)
|
||||
sms.POST("/contacts/list", api.ListContacts) // 查询通讯录列表
|
||||
sms.POST("/contacts/add", api.AddContact) // 新增联系人
|
||||
sms.POST("/contacts/edit", api.EditContact) // 编辑联系人
|
||||
sms.POST("/contacts/batch_delete", api.BulkDeleteContacts) // 批量删除联系人
|
||||
sms.POST("/contacts/import", api.BulkImportContacts) // 批量导入通讯录
|
||||
sms.POST("/contacts/export", api.BulkExportContacts) // 批量导出通讯录
|
||||
|
||||
sms.POST("/phrase_category/add", api.AddPhraseCategory) // 新增短语分类节点
|
||||
sms.POST("/phrase_category/edit", api.EditPhraseCategory) // 编辑短语分类节点
|
||||
sms.POST("/phrase_category/delete", api.DeletePhraseCategories) // 删除常用短语分类
|
||||
sms.POST("/phrase_category/list", api.ListPhraseCategories) // 查询常用短语分类列表(树形结构)
|
||||
sms.POST("/phrase/add", api.AddPhrase) // 新增常用短语
|
||||
sms.POST("/phrase/edit", api.EditPhrase) // 编辑常用短语
|
||||
sms.POST("/phrase/delete", api.DeletePhrases) // 批量删除短语
|
||||
sms.POST("/phrase/list", api.ListPhrases) // 查询常用短语列表
|
||||
|
||||
sms.POST("/common_number/list", api.ListCommonNumbers) // 常用号码列表
|
||||
sms.POST("/common_number/add", api.AddCommonNumber) // 添加常用号码
|
||||
sms.POST("/common_number/append", api.AppendCommonNumber) // 追加号码
|
||||
sms.POST("/common_number/detail", api.CommonNumberDetail) // 常用号码详情
|
||||
sms.POST("/common_number/delete", api.DeleteCommonNumbers) // 批量删除常用号码
|
||||
sms.POST("/common_number/export", api.ExportCommonNumber) // 导出常用号码
|
||||
|
||||
sms.POST("/black_list/add", api.AddBlacklistNumber) // 添加黑名单
|
||||
sms.POST("/black_list/list", api.ListBlacklist) // 黑名单列表
|
||||
sms.POST("/black_list/export", api.ExportBlacklist) // 导出黑名单号码
|
||||
sms.POST("/black_list/delete", api.DeleteBlacklist) // 批量删除黑名单
|
||||
|
||||
sms.POST("/template/create", api.CreateSmsTemplate) // 新增短信模版
|
||||
sms.POST("/template/delete", api.DeleteSmsTemplates) // 批量删除短信模版
|
||||
sms.POST("/template/update", api.UpdateSmsTemplate) // 修改短信模版
|
||||
sms.POST("/template/approve", api.ApproveSmsTemplate) // 审核短信模版
|
||||
sms.POST("/template/list", api.ListSmsTemplates) // 获取短信模版列表
|
||||
sms.POST("/template/export", api.ExportSmsTemplate) // 导出短信模版
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package bus_service
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
|
@ -11,7 +12,11 @@ import (
|
|||
"go-admin/common/redisx"
|
||||
"golang.org/x/net/context"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -811,6 +816,9 @@ func (s *SmsService) ListContacts(req bus_models.ContactQuery, db *gorm.DB) (bus
|
|||
|
||||
query := db.Model(&bus_models.SmsContact{})
|
||||
|
||||
if len(req.CategoryID) != 0 {
|
||||
query = query.Where("category_id IN ?", req.CategoryID)
|
||||
}
|
||||
if req.Name != "" {
|
||||
query = query.Where("name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
|
@ -862,7 +870,7 @@ func (s *SmsService) AddContact(contact bus_models.SmsContact, db *gorm.DB) erro
|
|||
}
|
||||
|
||||
// EditContact 编辑联系人
|
||||
func (s *SmsService) EditContact(id string, contact bus_models.SmsContact, db *gorm.DB) error {
|
||||
func (s *SmsService) EditContact(id uint64, contact bus_models.SmsContact, db *gorm.DB) error {
|
||||
var existingContact bus_models.SmsContact
|
||||
if err := db.Where("id = ?", id).First(&existingContact).Error; err != nil {
|
||||
return err
|
||||
|
@ -886,3 +894,847 @@ func (s *SmsService) EditContact(id string, contact bus_models.SmsContact, db *g
|
|||
func (s *SmsService) BulkDeleteContacts(req bus_models.ContactDeleteRequest, db *gorm.DB) error {
|
||||
return db.Where("id IN (?)", req.ContactIDs).Delete(&bus_models.SmsContact{}).Error
|
||||
}
|
||||
|
||||
// ImportContactsFromExcel 从Excel导入联系人(含格式校验)
|
||||
func (s *SmsService) ImportContactsFromExcel(r io.Reader, db *gorm.DB, coopNum, coopName string, categoryId uint64) error {
|
||||
excelFile, err := excelize.OpenReader(r)
|
||||
if err != nil {
|
||||
return errors.New("解析Excel失败")
|
||||
}
|
||||
|
||||
rows, err := excelFile.GetRows("Sheet1")
|
||||
if err != nil || len(rows) < 2 {
|
||||
return errors.New("excel格式错误或无有效数据")
|
||||
}
|
||||
|
||||
var contacts []bus_models.SmsContact
|
||||
for i, row := range rows {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(row) < 7 {
|
||||
// 如果一行少于7个字段,补充缺失字段为空字符串或默认值
|
||||
for len(row) < 7 {
|
||||
row = append(row, "")
|
||||
}
|
||||
}
|
||||
|
||||
phone := strings.TrimSpace(row[3])
|
||||
if !isValidPhoneNumber(phone) {
|
||||
return fmt.Errorf("第 %d 行手机号码格式不正确: %s", i+1, phone)
|
||||
}
|
||||
|
||||
birthday, err := parseExcelDate(row[4])
|
||||
if err != nil {
|
||||
return fmt.Errorf("第 %d 行生日格式不正确,应为YYYY-MM-DD: %s", i+1, row[4])
|
||||
}
|
||||
|
||||
contacts = append(contacts, bus_models.SmsContact{
|
||||
CategoryID: categoryId,
|
||||
CooperativeNumber: coopNum,
|
||||
CooperativeName: coopName,
|
||||
Name: strings.TrimSpace(row[0]),
|
||||
Company: strings.TrimSpace(row[1]),
|
||||
Gender: strings.TrimSpace(row[2]),
|
||||
PhoneNumber: phone,
|
||||
Birthday: birthday,
|
||||
Address: strings.TrimSpace(row[5]),
|
||||
Remark: strings.TrimSpace(row[6]),
|
||||
})
|
||||
}
|
||||
|
||||
if len(contacts) == 0 {
|
||||
return errors.New("无有效联系人记录")
|
||||
}
|
||||
|
||||
err = db.Create(&contacts).Error
|
||||
if err != nil {
|
||||
return errors.New("导入失败:" + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidPhoneNumber(phone string) bool {
|
||||
match, _ := regexp.MatchString(`^1\d{10}$`, phone)
|
||||
return match
|
||||
}
|
||||
|
||||
func parseExcelDate(dateStr string) (*time.Time, error) {
|
||||
if dateStr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
layouts := []string{"2006-01-02", "2006/01/02"}
|
||||
for _, layout := range layouts {
|
||||
if t, err := time.Parse(layout, dateStr); err == nil {
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("日期格式不正确")
|
||||
}
|
||||
|
||||
func (s *SmsService) ExportContactsToExcel(db *gorm.DB, req bus_models.ExportContactsRequest) (string, error) {
|
||||
var contacts []bus_models.SmsContact
|
||||
query := db.Order("id desc")
|
||||
|
||||
if !req.All {
|
||||
if len(req.IDs) == 0 {
|
||||
return "", fmt.Errorf("未传入ID且未选择导出全部")
|
||||
}
|
||||
query = query.Where("id IN ?", req.IDs)
|
||||
}
|
||||
|
||||
if err := query.Find(&contacts).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(contacts) == 0 {
|
||||
return "", fmt.Errorf("没有可导出的联系人")
|
||||
}
|
||||
|
||||
file := excelize.NewFile()
|
||||
sheet := "Sheet1"
|
||||
headers := []string{"姓名", "公司", "性别", "手机号码", "生日", "地址", "备注"}
|
||||
|
||||
// 表头
|
||||
for i, h := range headers {
|
||||
col := string('A' + i)
|
||||
file.SetCellValue(sheet, col+"1", h)
|
||||
}
|
||||
|
||||
// 内容
|
||||
for i, c := range contacts {
|
||||
row := i + 2
|
||||
file.SetCellValue(sheet, "A"+strconv.Itoa(row), c.Name)
|
||||
file.SetCellValue(sheet, "B"+strconv.Itoa(row), c.Company)
|
||||
file.SetCellValue(sheet, "C"+strconv.Itoa(row), c.Gender)
|
||||
file.SetCellValue(sheet, "D"+strconv.Itoa(row), c.PhoneNumber)
|
||||
if c.Birthday != nil {
|
||||
file.SetCellValue(sheet, "E"+strconv.Itoa(row), c.Birthday.Format("2006-01-02"))
|
||||
}
|
||||
file.SetCellValue(sheet, "F"+strconv.Itoa(row), c.Address)
|
||||
file.SetCellValue(sheet, "G"+strconv.Itoa(row), c.Remark)
|
||||
}
|
||||
|
||||
style, _ := file.NewStyle(&excelize.Style{
|
||||
Alignment: &excelize.Alignment{
|
||||
Horizontal: "center",
|
||||
Vertical: "center",
|
||||
},
|
||||
})
|
||||
file.SetColWidth(sheet, "A", "G", 20)
|
||||
file.SetCellStyle(sheet, "A1", fmt.Sprintf("G%d", len(contacts)+1), style)
|
||||
|
||||
// 保存文件
|
||||
fileName := time.Now().Format("20060102150405") + "_导出通讯录.xlsx"
|
||||
filePath := ExportFile + fileName
|
||||
fileUrl := MiGuExportUrl + fileName
|
||||
|
||||
if err := file.SaveAs(filePath); err != nil {
|
||||
logger.Errorf("导出通讯录失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) AddPhraseCategory(req bus_models.AddPhraseCategoryReq, db *gorm.DB) error {
|
||||
return db.Create(&bus_models.SmsPhraseCategory{
|
||||
Name: req.Name,
|
||||
ParentID: uint64(req.ParentID),
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) EditPhraseCategory(req bus_models.EditPhraseCategoryReq, db *gorm.DB) error {
|
||||
return db.Model(&bus_models.SmsPhraseCategory{}).
|
||||
Where("id = ?", req.ID).
|
||||
Update("name", req.Name).
|
||||
Error
|
||||
}
|
||||
|
||||
func (s *SmsService) DeletePhraseCategories(ids []uint, db *gorm.DB) error {
|
||||
if len(ids) == 0 {
|
||||
return errors.New("未指定需要删除的分类")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := db.Model(&bus_models.SmsPhraseCategory{}).Count(&total).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 递归找出所有要删除的 ID(含子分类)
|
||||
var allIDs []uint
|
||||
var walk func(uint)
|
||||
walk = func(parentID uint) {
|
||||
var children []bus_models.SmsPhraseCategory
|
||||
db.Where("parent_id = ?", parentID).Find(&children)
|
||||
for _, child := range children {
|
||||
allIDs = append(allIDs, uint(child.ID))
|
||||
walk(uint(child.ID))
|
||||
}
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
allIDs = append(allIDs, id)
|
||||
walk(id)
|
||||
}
|
||||
|
||||
// 保证删除后至少保留一个分类节点
|
||||
if len(allIDs) >= int(total) {
|
||||
return errors.New("无法删除所有分类节点,至少保留一个")
|
||||
}
|
||||
|
||||
// 删除短语
|
||||
if err := db.Where("category_id IN ?", allIDs).Delete(&bus_models.SmsPhrase{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除分类
|
||||
return db.Where("id IN ?", allIDs).Delete(&bus_models.SmsPhraseCategory{}).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) ListPhrases(req bus_models.SmsPhraseQuery, db *gorm.DB) (bus_models.SmsPhraseListResp, error) {
|
||||
var list []bus_models.SmsPhrase
|
||||
var total int64
|
||||
|
||||
query := db.Model(&bus_models.SmsPhrase{})
|
||||
|
||||
if req.Content != "" {
|
||||
query = query.Where("content LIKE ?", "%"+req.Content+"%")
|
||||
}
|
||||
if req.CategoryID != 0 {
|
||||
query = query.Where("category_id = ?", req.CategoryID)
|
||||
}
|
||||
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsPhraseListResp{}, err
|
||||
}
|
||||
|
||||
// 处理分页
|
||||
page := req.Page
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
err = query.Order("id desc").
|
||||
Offset((page - 1) * pageSize).
|
||||
Limit(pageSize).
|
||||
Find(&list).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsPhraseListResp{}, err
|
||||
}
|
||||
|
||||
return bus_models.SmsPhraseListResp{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
TotalPage: (total + int64(pageSize) - 1) / int64(pageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AddPhrase 新增
|
||||
func (s *SmsService) AddPhrase(req bus_models.SmsPhraseAddOrEdit, db *gorm.DB) error {
|
||||
phrase := bus_models.SmsPhrase{
|
||||
Content: req.Content,
|
||||
CategoryID: req.CategoryID,
|
||||
}
|
||||
return db.Create(&phrase).Error
|
||||
}
|
||||
|
||||
// EditPhrase 编辑
|
||||
func (s *SmsService) EditPhrase(req bus_models.SmsPhraseAddOrEdit, db *gorm.DB) error {
|
||||
return db.Model(&bus_models.SmsPhrase{}).
|
||||
Where("id = ?", req.ID).
|
||||
Updates(map[string]interface{}{
|
||||
"content": req.Content,
|
||||
"category_id": req.CategoryID,
|
||||
}).Error
|
||||
}
|
||||
|
||||
// DeletePhrases 批量删除
|
||||
func (s *SmsService) DeletePhrases(ids []uint, db *gorm.DB) error {
|
||||
return db.Where("id IN (?)", ids).Delete(&bus_models.SmsPhrase{}).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) GetPhraseCategoryTree(db *gorm.DB, parentID uint64) ([]bus_models.SmsPhraseCategoryTree, error) {
|
||||
var categories []bus_models.SmsPhraseCategory
|
||||
if err := db.Find(&categories).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建 map[id]category
|
||||
idMap := make(map[uint64]*bus_models.SmsPhraseCategoryTree)
|
||||
for _, cat := range categories {
|
||||
node := &bus_models.SmsPhraseCategoryTree{
|
||||
ID: cat.ID,
|
||||
Name: cat.Name,
|
||||
ParentID: cat.ParentID,
|
||||
}
|
||||
idMap[cat.ID] = node
|
||||
}
|
||||
|
||||
// 构建树结构
|
||||
for _, node := range idMap {
|
||||
if parent, ok := idMap[node.ParentID]; ok {
|
||||
parent.Children = append(parent.Children, *node)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回指定节点下的树
|
||||
if parentID != 0 {
|
||||
if root, ok := idMap[parentID]; ok {
|
||||
return []bus_models.SmsPhraseCategoryTree{*root}, nil
|
||||
}
|
||||
return []bus_models.SmsPhraseCategoryTree{}, nil // 指定节点不存在
|
||||
}
|
||||
|
||||
// 否则返回整棵树
|
||||
var roots []bus_models.SmsPhraseCategoryTree
|
||||
for _, node := range idMap {
|
||||
if node.ParentID == 0 {
|
||||
roots = append(roots, *node)
|
||||
}
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) AddContactsCategory(req bus_models.AddContactCategoryReq, db *gorm.DB) error {
|
||||
return db.Create(&bus_models.SmsContactCategory{
|
||||
Name: req.Name,
|
||||
ParentID: uint64(req.ParentID),
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) EditContactsCategory(req bus_models.EditContactCategoryReq, db *gorm.DB) error {
|
||||
return db.Model(&bus_models.SmsContactCategory{}).
|
||||
Where("id = ?", req.ID).
|
||||
Update("name", req.Name).
|
||||
Error
|
||||
}
|
||||
|
||||
func (s *SmsService) DeleteContactsCategories(ids []uint, db *gorm.DB) error {
|
||||
if len(ids) == 0 {
|
||||
return errors.New("未指定需要删除的分类")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := db.Model(&bus_models.SmsContactCategory{}).Count(&total).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 递归找出所有要删除的 ID(含子分类)
|
||||
var allIDs []uint
|
||||
var walk func(uint)
|
||||
walk = func(parentID uint) {
|
||||
var children []bus_models.SmsContactCategory
|
||||
db.Where("parent_id = ?", parentID).Find(&children)
|
||||
for _, child := range children {
|
||||
allIDs = append(allIDs, uint(child.ID))
|
||||
walk(uint(child.ID))
|
||||
}
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
allIDs = append(allIDs, id)
|
||||
walk(id)
|
||||
}
|
||||
|
||||
// 保证删除后至少保留一个分类节点
|
||||
if len(allIDs) >= int(total) {
|
||||
return errors.New("无法删除所有分类节点,至少保留一个")
|
||||
}
|
||||
|
||||
// 删除短语
|
||||
if err := db.Where("category_id IN ?", allIDs).Delete(&bus_models.SmsContact{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除分类
|
||||
return db.Where("id IN ?", allIDs).Delete(&bus_models.SmsContactCategory{}).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) GetContactsCategoryTree(db *gorm.DB, parentID uint64) ([]bus_models.SmsContactCategoryTree, error) {
|
||||
var categories []bus_models.SmsContactCategory
|
||||
if err := db.Find(&categories).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建 map[id]category
|
||||
idMap := make(map[uint64]*bus_models.SmsContactCategoryTree)
|
||||
for _, cat := range categories {
|
||||
node := &bus_models.SmsContactCategoryTree{
|
||||
ID: cat.ID,
|
||||
Name: cat.Name,
|
||||
ParentID: cat.ParentID,
|
||||
}
|
||||
idMap[cat.ID] = node
|
||||
}
|
||||
|
||||
// 构建树结构
|
||||
for _, node := range idMap {
|
||||
if parent, ok := idMap[node.ParentID]; ok {
|
||||
parent.Children = append(parent.Children, *node)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回指定节点下的树
|
||||
if parentID != 0 {
|
||||
if root, ok := idMap[parentID]; ok {
|
||||
return []bus_models.SmsContactCategoryTree{*root}, nil
|
||||
}
|
||||
return []bus_models.SmsContactCategoryTree{}, nil // 指定节点不存在
|
||||
}
|
||||
|
||||
// 否则返回整棵树
|
||||
var roots []bus_models.SmsContactCategoryTree
|
||||
for _, node := range idMap {
|
||||
if node.ParentID == 0 {
|
||||
roots = append(roots, *node)
|
||||
}
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) ListCommonNumbers(req bus_models.SmsCommonNumberQuery, db *gorm.DB) (bus_models.SmsCommonNumberListResp, error) {
|
||||
var dbList []bus_models.SmsCommonNumber
|
||||
var total int64
|
||||
|
||||
query := db.Model(&bus_models.SmsCommonNumber{})
|
||||
if req.Name != "" {
|
||||
query = query.Where("name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsCommonNumberListResp{}, err
|
||||
}
|
||||
|
||||
// 处理分页
|
||||
page := req.Page
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
err = query.Order("id desc").
|
||||
Offset((page - 1) * pageSize).
|
||||
Limit(pageSize).
|
||||
Find(&dbList).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsCommonNumberListResp{}, err
|
||||
}
|
||||
|
||||
// 转换为返回结构体
|
||||
var respList []bus_models.SmsCommonNumber
|
||||
for _, item := range dbList {
|
||||
respList = append(respList, bus_models.SmsCommonNumber{
|
||||
Name: item.Name,
|
||||
PhoneNumbers: item.PhoneNumbers,
|
||||
PhoneCount: len(strings.Split(item.PhoneNumbers, ",")),
|
||||
})
|
||||
}
|
||||
|
||||
totalPage := (total + int64(page) - 1) / int64(pageSize)
|
||||
if totalPage < 1 {
|
||||
totalPage = 1
|
||||
}
|
||||
|
||||
return bus_models.SmsCommonNumberListResp{
|
||||
List: respList,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
TotalPage: totalPage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) AddCommonNumber(req bus_models.SmsCommonNumberAddReq, db *gorm.DB) error {
|
||||
if req.Name == "" {
|
||||
return errors.New("名称不能为空")
|
||||
}
|
||||
return db.Create(&bus_models.SmsCommonNumber{
|
||||
Name: req.Name,
|
||||
PhoneNumbers: strings.Join(req.PhoneList, ","),
|
||||
}).Error
|
||||
}
|
||||
|
||||
// AppendCommonNumber 向已有常用号码记录中追加号码(自动去重)
|
||||
// 逻辑:获取原始号码列表 + 新号码列表 => 合并去重 => 更新保存
|
||||
func (s *SmsService) AppendCommonNumber(req bus_models.SmsCommonNumberAppendReq, db *gorm.DB) error {
|
||||
var record bus_models.SmsCommonNumber
|
||||
err := db.Where("id = ?", req.ID).First(&record).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 拆分原始号码
|
||||
originalNumbers := strings.Split(record.PhoneNumbers, ",")
|
||||
numberSet := make(map[string]struct{})
|
||||
|
||||
// 原号码去重填入 map
|
||||
for _, num := range originalNumbers {
|
||||
num = strings.TrimSpace(num)
|
||||
if num != "" {
|
||||
numberSet[num] = struct{}{}
|
||||
}
|
||||
}
|
||||
// 新号码去重合并
|
||||
for _, num := range req.PhoneList {
|
||||
num = strings.TrimSpace(num)
|
||||
if num != "" {
|
||||
numberSet[num] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
var deduplicated []string
|
||||
for num := range numberSet {
|
||||
deduplicated = append(deduplicated, num)
|
||||
}
|
||||
sort.Strings(deduplicated) // 方便前端对比、稳定输出顺序
|
||||
|
||||
record.PhoneNumbers = strings.Join(deduplicated, ",")
|
||||
return db.Save(&record).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) GetCommonNumberDetail(id int64, db *gorm.DB) (bus_models.SmsCommonNumber, error) {
|
||||
var record bus_models.SmsCommonNumber
|
||||
err := db.First(&record, id).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
func (s *SmsService) DeleteCommonNumbers(ids []uint64, db *gorm.DB) error {
|
||||
return db.Where("id IN (?)", ids).Delete(&bus_models.SmsCommonNumber{}).Error
|
||||
}
|
||||
|
||||
// ExportCommonNumbers 导出多个常用号码名称下的所有号码到一个文件
|
||||
func (s *SmsService) ExportCommonNumbers(req bus_models.SmsCommonNumberExportReq, db *gorm.DB) (string, error) {
|
||||
var records []bus_models.SmsCommonNumber
|
||||
|
||||
query := db.Model(&bus_models.SmsCommonNumber{}).Order("id desc")
|
||||
if !req.All {
|
||||
if len(req.Ids) == 0 {
|
||||
return "", fmt.Errorf("未传入号码且未选择导出全部")
|
||||
}
|
||||
query = query.Where("id IN ?", req.Ids)
|
||||
}
|
||||
|
||||
err := query.Find(&records).Error
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return "", errors.New("未找到对应的常用号码数据")
|
||||
}
|
||||
|
||||
// 创建文件
|
||||
fileName := time.Now().Format("20060102150405") + "_常用号码.xlsx"
|
||||
filePath := ExportFile + fileName
|
||||
fileUrl := MiGuExportUrl + fileName
|
||||
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer := csv.NewWriter(file)
|
||||
defer writer.Flush()
|
||||
|
||||
// 写数据
|
||||
for _, record := range records {
|
||||
numbers := strings.Split(record.PhoneNumbers, ",")
|
||||
for _, number := range numbers {
|
||||
trimmed := strings.TrimSpace(number)
|
||||
if trimmed != "" {
|
||||
writer.Write([]string{trimmed})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) AddBlacklistNumber(req bus_models.BlacklistAddReq, db *gorm.DB) error {
|
||||
if len(req.PhoneList) == 0 {
|
||||
return fmt.Errorf("手机号列表不能为空")
|
||||
}
|
||||
|
||||
var records []bus_models.SmsBlackList
|
||||
for _, phone := range req.PhoneList {
|
||||
records = append(records, bus_models.SmsBlackList{
|
||||
PhoneNumber: phone,
|
||||
Remark: req.Remark,
|
||||
})
|
||||
}
|
||||
|
||||
return db.Create(&records).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) ListBlacklist(req bus_models.BlacklistQuery, db *gorm.DB) (bus_models.BlacklistListResp, error) {
|
||||
var list []bus_models.SmsBlackList
|
||||
var total int64
|
||||
|
||||
query := db.Model(&bus_models.SmsBlackList{})
|
||||
if req.PhoneNumber != "" {
|
||||
query = query.Where("phone_number LIKE ?", "%"+req.PhoneNumber+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return bus_models.BlacklistListResp{}, err
|
||||
}
|
||||
|
||||
page := req.Page
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
err = query.Order("id desc").
|
||||
Offset((page - 1) * pageSize).
|
||||
Limit(pageSize).
|
||||
Find(&list).Error
|
||||
if err != nil {
|
||||
return bus_models.BlacklistListResp{}, err
|
||||
}
|
||||
|
||||
totalPage := (total + int64(pageSize) - 1) / int64(pageSize)
|
||||
if totalPage < 1 {
|
||||
totalPage = 1
|
||||
}
|
||||
|
||||
return bus_models.BlacklistListResp{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
TotalPage: totalPage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) ExportBlacklistToExcel(db *gorm.DB, req bus_models.ExportBlacklistRequest) (string, error) {
|
||||
var blacklists []bus_models.SmsBlackList
|
||||
query := db.Model(&bus_models.SmsBlackList{}).Order("id desc")
|
||||
|
||||
if !req.All {
|
||||
if len(req.Ids) == 0 {
|
||||
return "", fmt.Errorf("未传入号码且未选择导出全部")
|
||||
}
|
||||
query = query.Where("id IN ?", req.Ids)
|
||||
}
|
||||
|
||||
if err := query.Find(&blacklists).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(blacklists) == 0 {
|
||||
return "", fmt.Errorf("没有可导出的黑名单记录")
|
||||
}
|
||||
|
||||
file := excelize.NewFile()
|
||||
sheet := "Sheet1"
|
||||
headers := []string{"手机号", "备注", "创建时间"}
|
||||
|
||||
for i, h := range headers {
|
||||
col := string('A' + i)
|
||||
file.SetCellValue(sheet, col+"1", h)
|
||||
}
|
||||
|
||||
for i, b := range blacklists {
|
||||
row := strconv.Itoa(i + 2)
|
||||
file.SetCellValue(sheet, "A"+row, b.PhoneNumber)
|
||||
file.SetCellValue(sheet, "B"+row, b.Remark)
|
||||
file.SetCellValue(sheet, "C"+row, b.CreatedAt.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
style, _ := file.NewStyle(&excelize.Style{
|
||||
Alignment: &excelize.Alignment{
|
||||
Horizontal: "center",
|
||||
Vertical: "center",
|
||||
},
|
||||
})
|
||||
file.SetColWidth(sheet, "A", "C", 20)
|
||||
file.SetCellStyle(sheet, "A1", fmt.Sprintf("C%d", len(blacklists)+1), style)
|
||||
|
||||
fileName := time.Now().Format("20060102150405") + "_导出黑名单.xlsx"
|
||||
filePath := ExportFile + fileName
|
||||
fileUrl := MiGuExportUrl + fileName
|
||||
|
||||
if err := file.SaveAs(filePath); err != nil {
|
||||
logger.Errorf("导出黑名单失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
||||
// DeleteBlacklist 批量删除黑名单记录
|
||||
func (s *SmsService) DeleteBlacklist(ids []uint, db *gorm.DB) error {
|
||||
return db.Where("id IN ?", ids).Delete(&bus_models.SmsBlackList{}).Error
|
||||
}
|
||||
|
||||
// CreateSmsTemplate 创建短信模版
|
||||
func (s *SmsService) CreateSmsTemplate(data *bus_models.SmsTemplate, db *gorm.DB) error {
|
||||
return db.Create(data).Error
|
||||
}
|
||||
|
||||
// DeleteSmsTemplates 批量删除短信模版
|
||||
func (s *SmsService) DeleteSmsTemplates(ids []uint, db *gorm.DB) error {
|
||||
return db.Delete(&bus_models.SmsTemplate{}, ids).Error
|
||||
}
|
||||
|
||||
// UpdateSmsTemplate 更新短信模版
|
||||
func (s *SmsService) UpdateSmsTemplate(req *bus_models.SmsTemplateUpdateRequest, db *gorm.DB) error {
|
||||
var tmpl bus_models.SmsTemplate
|
||||
|
||||
// 查找原始数据
|
||||
if err := db.First(&tmpl, req.ID).Error; err != nil {
|
||||
return fmt.Errorf("未找到指定的短信模版")
|
||||
}
|
||||
|
||||
// 更新模版内容
|
||||
tmpl.Content = req.Content
|
||||
|
||||
// 更新到期时间(如果传入了新的时间)
|
||||
if !req.ExpireAt.IsZero() {
|
||||
tmpl.ExpireAt = req.ExpireAt
|
||||
}
|
||||
|
||||
// 更新更新时间
|
||||
tmpl.UpdatedAt = time.Now()
|
||||
|
||||
// 保存更新后的模版
|
||||
return db.Save(&tmpl).Error
|
||||
}
|
||||
|
||||
// ApproveSmsTemplate 审核短信模版
|
||||
func (s *SmsService) ApproveSmsTemplate(id uint, status int, db *gorm.DB) error {
|
||||
return db.Model(&bus_models.SmsTemplate{}).
|
||||
Where("id = ?", id).
|
||||
Update("status", status).Error
|
||||
}
|
||||
|
||||
func (s *SmsService) ListSmsTemplates(req bus_models.SmsTemplateQuery, db *gorm.DB) (bus_models.SmsTemplateListResp, error) {
|
||||
var list []bus_models.SmsTemplate
|
||||
var total int64
|
||||
|
||||
query := db.Model(&bus_models.SmsTemplate{})
|
||||
|
||||
if req.Content != "" {
|
||||
query = query.Where("content LIKE ?", "%"+req.Content+"%")
|
||||
}
|
||||
if req.Status != 0 {
|
||||
query = query.Where("status = ?", req.Status)
|
||||
}
|
||||
if !req.CreateStart.IsZero() && !req.CreateEnd.IsZero() {
|
||||
query = query.Where("created_at BETWEEN ? AND ?", req.CreateStart, req.CreateEnd)
|
||||
}
|
||||
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsTemplateListResp{}, err
|
||||
}
|
||||
|
||||
page := req.Page
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
err = query.Order("id desc").
|
||||
Offset((page - 1) * pageSize).
|
||||
Limit(pageSize).
|
||||
Find(&list).Error
|
||||
if err != nil {
|
||||
return bus_models.SmsTemplateListResp{}, err
|
||||
}
|
||||
|
||||
totalPage := (total + int64(pageSize) - 1) / int64(pageSize)
|
||||
if totalPage < 1 {
|
||||
totalPage = 1
|
||||
}
|
||||
|
||||
return bus_models.SmsTemplateListResp{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
TotalPage: totalPage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SmsService) ExportSmsTemplates(req bus_models.SmsTemplateExportReq, db *gorm.DB) (string, error) {
|
||||
var templates []bus_models.SmsTemplate
|
||||
|
||||
query := db.Model(&bus_models.SmsTemplate{}).Order("id desc")
|
||||
if !req.All {
|
||||
if len(req.Ids) == 0 {
|
||||
return "", fmt.Errorf("未传入模版且未选择导出全部")
|
||||
}
|
||||
query = query.Where("id IN ?", req.Ids)
|
||||
}
|
||||
|
||||
err := query.Find(&templates).Error
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(templates) == 0 {
|
||||
return "", errors.New("未找到对应的短信模版数据")
|
||||
}
|
||||
|
||||
// 生成文件
|
||||
fileName := time.Now().Format("20060102150405") + "_短信模版导出.csv"
|
||||
filePath := ExportFile + fileName
|
||||
fileUrl := MiGuExportUrl + fileName
|
||||
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer := csv.NewWriter(file)
|
||||
defer writer.Flush()
|
||||
|
||||
// 写表头
|
||||
writer.Write([]string{"模版ID", "模版内容", "备注", "状态", "创建时间"})
|
||||
|
||||
// 写内容
|
||||
for _, tmpl := range templates {
|
||||
status := map[int]string{
|
||||
0: "待审核",
|
||||
1: "正常",
|
||||
2: "审核拒绝",
|
||||
3: "已过期",
|
||||
}[tmpl.Status]
|
||||
|
||||
writer.Write([]string{
|
||||
strconv.Itoa(int(tmpl.ID)),
|
||||
tmpl.Content,
|
||||
tmpl.Remark,
|
||||
status,
|
||||
tmpl.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
9
tools/utils/utils.go
Normal file
9
tools/utils/utils.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package utils
|
||||
|
||||
import "regexp"
|
||||
|
||||
func IsValidPhone(phone string) bool {
|
||||
// 简单验证:以1开头,后面10位数字
|
||||
reg := regexp.MustCompile(`^1[0-9]{10}$`)
|
||||
return reg.MatchString(phone)
|
||||
}
|
Loading…
Reference in New Issue
Block a user