feat:附件增加一个文件名称

This commit is contained in:
cjy 2026-02-02 10:09:02 +08:00
parent 25f323ef66
commit 9750b0b505
5 changed files with 1067 additions and 923 deletions

View File

@ -12,23 +12,31 @@ import (
"github.com/google/uuid"
)
// urlsToJSON 将附件 URL 切片序列化为 JSON 字符串存入 DB
func urlsToJSON(urls []string) string {
if len(urls) == 0 {
// attachmentsToJSON 将附件列表url+fileName序列化为 JSON 字符串存入 DB
func attachmentsToJSON(items []*bundle.AttachmentItem) string {
if len(items) == 0 {
return "[]"
}
b, _ := json.Marshal(urls)
list := make([]model.AttachmentItem, 0, len(items))
for _, it := range items {
list = append(list, model.AttachmentItem{URL: it.GetUrl(), FileName: it.GetFileName()})
}
b, _ := json.Marshal(list)
return string(b)
}
// jsonToURLs 将 DB 中的 JSON 字符串反序列化为附件 URL 切片返回给前端
func jsonToURLs(s string) []string {
// jsonToAttachments 将 DB 中的 JSON 反序列化为附件列表(格式:[{"url":"","fileName":""},...]
func jsonToAttachments(s string) []*bundle.AttachmentItem {
if s == "" || s == "[]" {
return nil
}
var urls []string
_ = json.Unmarshal([]byte(s), &urls)
return urls
var list []model.AttachmentItem
_ = json.Unmarshal([]byte(s), &list)
out := make([]*bundle.AttachmentItem, 0, len(list))
for i := range list {
out = append(out, &bundle.AttachmentItem{Url: list[i].URL, FileName: list[i].FileName})
}
return out
}
// validateContractBody 校验合同主体字段create/update 共用)
@ -86,11 +94,11 @@ func validateContractBody(c *bundle.Contract) (string, error) {
if c.QualityAssuranceCurrencyType == 0 {
return "质量保证金货币类型不能为空", errors.New("质量保证金货币类型不能为空")
}
if len(c.ContractAttachmentURLs) > 5 {
return "合同附件URLs不能超过5个", errors.New("合同附件URLs不能超过5个")
if len(c.ContractAttachments) > 5 {
return "合同附件不能超过5个", errors.New("合同附件不能超过5个")
}
if len(c.OtherAttachmentURLs) > 5 {
return "其他附件URLs不能超过5个", errors.New("其他附件URLs不能超过5个")
if len(c.OtherAttachments) > 5 {
return "其他附件不能超过5个", errors.New("其他附件不能超过5个")
}
return "", nil
}
@ -154,7 +162,7 @@ func convertDevelopmentCycles(cycles []*bundle.DevelopmentCycle, contractUUID st
}
result := make([]model.DevelopmentCycle, 0, len(cycles))
for _, dc := range cycles {
if len(dc.AttachmentURLs) > 5 {
if len(dc.Attachments) > 5 {
return nil, "附件URLs不能超过5个", errors.New("附件URLs不能超过5个")
}
// 开发时间最多50个字
@ -174,7 +182,7 @@ func convertDevelopmentCycles(cycles []*bundle.DevelopmentCycle, contractUUID st
ContractUUID: contractUUID,
DevelopmentPeriod: int(dc.DevelopmentPeriod),
DevelopmentTime: dc.DevelopmentTime,
AttachmentURLs: urlsToJSON(dc.AttachmentURLs),
AttachmentURLs: attachmentsToJSON(dc.Attachments),
DeliveryContent: dc.DeliveryContent,
})
}
@ -215,8 +223,8 @@ func UpdateContract(req *bundle.ContractUpdateRequest) (res *bundle.ComResponse,
MaintenanceCurrencyType: int(req.Contract.MaintenanceCurrencyType),
QualityAssuranceFee: req.Contract.QualityAssuranceFee,
QualityAssuranceCurrencyType: int(req.Contract.QualityAssuranceCurrencyType),
ContractAttachmentURLs: urlsToJSON(req.Contract.ContractAttachmentURLs),
OtherAttachmentURLs: urlsToJSON(req.Contract.OtherAttachmentURLs),
ContractAttachmentURLs: attachmentsToJSON(req.Contract.ContractAttachments),
OtherAttachmentURLs: attachmentsToJSON(req.Contract.OtherAttachments),
Operator: req.Contract.Operator,
OperatorID: req.Contract.OperatorID,
OperatorNum: req.Contract.OperatorNum,
@ -291,8 +299,8 @@ func UpdateContract(req *bundle.ContractUpdateRequest) (res *bundle.ComResponse,
MaintenanceCurrencyType: int(req.Contract.MaintenanceCurrencyType),
QualityAssuranceFee: req.Contract.QualityAssuranceFee,
QualityAssuranceCurrencyType: int(req.Contract.QualityAssuranceCurrencyType),
ContractAttachmentURLs: urlsToJSON(req.Contract.ContractAttachmentURLs),
OtherAttachmentURLs: urlsToJSON(req.Contract.OtherAttachmentURLs),
ContractAttachmentURLs: attachmentsToJSON(req.Contract.ContractAttachments),
OtherAttachmentURLs: attachmentsToJSON(req.Contract.OtherAttachments),
Operator: req.Contract.Operator,
OperatorID: req.Contract.OperatorID,
OperatorNum: req.Contract.OperatorNum,
@ -401,8 +409,8 @@ func GetContractList(req *bundle.ContractListRequest) (res *bundle.ContractListR
MaintenanceCycleType: int32(contract.MaintenanceCycleType),
MaintenanceFee: contract.MaintenanceFee,
MaintenanceCurrencyType: int32(contract.MaintenanceCurrencyType),
ContractAttachmentURLs: jsonToURLs(contract.ContractAttachmentURLs),
OtherAttachmentURLs: jsonToURLs(contract.OtherAttachmentURLs),
ContractAttachments: jsonToAttachments(contract.ContractAttachmentURLs),
OtherAttachments: jsonToAttachments(contract.OtherAttachmentURLs),
Operator: contract.Operator,
}
// 格式化操作时间
@ -461,8 +469,8 @@ func GetContractDetail(req *bundle.ContractDetailRequest) (res *bundle.ContractD
MaintenanceCurrencyType: int32(contract.MaintenanceCurrencyType),
QualityAssuranceFee: contract.QualityAssuranceFee,
QualityAssuranceCurrencyType: int32(contract.QualityAssuranceCurrencyType),
ContractAttachmentURLs: jsonToURLs(contract.ContractAttachmentURLs),
OtherAttachmentURLs: jsonToURLs(contract.OtherAttachmentURLs),
ContractAttachments: jsonToAttachments(contract.ContractAttachmentURLs),
OtherAttachments: jsonToAttachments(contract.OtherAttachmentURLs),
Operator: contract.Operator,
}
@ -495,7 +503,7 @@ func GetContractDetail(req *bundle.ContractDetailRequest) (res *bundle.ContractD
ContractUUID: dc.ContractUUID,
DevelopmentPeriod: int32(dc.DevelopmentPeriod),
DevelopmentTime: dc.DevelopmentTime,
AttachmentURLs: jsonToURLs(dc.AttachmentURLs),
Attachments: jsonToAttachments(dc.AttachmentURLs),
DeliveryContent: dc.DeliveryContent,
})
}
@ -532,7 +540,7 @@ func GetDevelopmentCyclesByContractUUID(req *bundle.GetDevelopmentCyclesByContra
ContractUUID: dc.ContractUUID,
DevelopmentPeriod: int32(dc.DevelopmentPeriod),
DevelopmentTime: dc.DevelopmentTime,
AttachmentURLs: jsonToURLs(dc.AttachmentURLs),
Attachments: jsonToAttachments(dc.AttachmentURLs),
DeliveryContent: dc.DeliveryContent,
})
}

View File

@ -21,6 +21,12 @@ const (
MaintenanceCycleTypeMonth = 4 // 月
)
// AttachmentItem 单个附件DB 中附件字段存的是该结构体数组的 JSON
type AttachmentItem struct {
URL string `json:"url"`
FileName string `json:"fileName"`
}
// 合同表
type Contract struct {
ContractUUID string `gorm:"column:contract_uuid;comment:合同UUID" json:"contractUUID"`
@ -47,8 +53,10 @@ type Contract struct {
QualityAssuranceFee float64 `json:"qualityAssuranceFee" gorm:"column:quality_assurance_fee;type:decimal(18,4);comment:质量保证金额"`
QualityAssuranceCurrencyType int `json:"qualityAssuranceCurrencyType" gorm:"column:quality_assurance_currency_type;type:int;comment:质量保证金货币类型"`
ContractAttachmentURLs string `gorm:"column:contract_attachment_urls;type:json;comment:合同附件URLs" json:"contractAttachmentURLs"`
OtherAttachmentURLs string `gorm:"column:other_attachment_urls;type:json;comment:其他附件URLs" json:"otherAttachmentURLs"`
// 合同附件JSON 数组,每项为 {"url":"","fileName":""}
ContractAttachmentURLs string `gorm:"column:contract_attachment_urls;type:json;comment:合同附件(含url+fileName)" json:"contractAttachmentURLs"`
// 其他附件JSON 数组,每项为 {"url":"","fileName":""}
OtherAttachmentURLs string `gorm:"column:other_attachment_urls;type:json;comment:其他附件(含url+fileName)" json:"otherAttachmentURLs"`
Operator string `gorm:"column:operator;comment:操作人;index:idx_operator" json:"operator"`
OperatorID string `gorm:"column:operator_id;type:varchar(50);NOT NULL;default:'';comment:操作人ID" json:"operatorID"`
@ -92,7 +100,8 @@ type DevelopmentCycle struct {
ContractUUID string `gorm:"column:contract_uuid;comment:合同UUID" json:"contractUUID"`
DevelopmentPeriod int `json:"developmentPeriod" gorm:"column:development_period;type:int;comment:开发第几期"`
DevelopmentTime string `gorm:"column:development_time;type:text;comment:开发时间" json:"developmentTime"`
AttachmentURLs string `gorm:"column:attachment_urls;type:json;comment:附件URLs" json:"attachmentURLs"`
// 附件JSON 数组,每项为 {"url":"","fileName":""}
AttachmentURLs string `gorm:"column:attachment_urls;type:json;comment:附件(含url+fileName)" json:"attachmentURLs"`
DeliveryContent string `gorm:"column:delivery_content;type:text;comment:交付内容" json:"deliveryContent"`
CreatedAt time.Time `gorm:"column:created_at;comment:创建时间" json:"createdAt"`
UpdatedAt time.Time `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"`

View File

@ -1960,6 +1960,12 @@ message GetPaymentCyclesByContractUUIDResponse {
string msg = 2 [json_name = "msg"]; //
}
// URL
message AttachmentItem {
string url = 1 [json_name = "url"]; //
string fileName = 2 [json_name = "fileName"]; //
}
//
message ContractInfo {
string contractUUID = 1 [json_name = "contractUUID"]; // UUID
@ -1978,8 +1984,8 @@ message ContractInfo {
int32 maintenanceCycleType = 14 [json_name = "maintenanceCycleType"]; //
double maintenanceFee = 15 [json_name = "maintenanceFee"]; //
int32 maintenanceCurrencyType = 16 [json_name = "maintenanceCurrencyType"]; //
repeated string contractAttachmentURLs = 17 [json_name = "contractAttachmentURLs"]; // URLs
repeated string otherAttachmentURLs = 18 [json_name = "otherAttachmentURLs"]; // URLs
repeated AttachmentItem contractAttachments = 17 [json_name = "contractAttachments"]; // url+fileName
repeated AttachmentItem otherAttachments = 18 [json_name = "otherAttachments"]; // url+fileName
string operator = 19 [json_name = "operator"]; //
string operatorTime = 22 [json_name = "operatorTime"]; //
}
@ -2002,8 +2008,8 @@ message Contract {
int32 maintenanceCurrencyType = 14 [json_name = "maintenanceCurrencyType"]; //
double qualityAssuranceFee = 15 [json_name = "qualityAssuranceFee"]; //
int32 qualityAssuranceCurrencyType = 16 [json_name = "qualityAssuranceCurrencyType"]; //
repeated string contractAttachmentURLs = 17 [json_name = "contractAttachmentURLs"]; // URLs
repeated string otherAttachmentURLs = 18 [json_name = "otherAttachmentURLs"]; // URLs
repeated AttachmentItem contractAttachments = 17 [json_name = "contractAttachments"]; // url+fileName
repeated AttachmentItem otherAttachments = 18 [json_name = "otherAttachments"]; // url+fileName
string operator = 19 [json_name = "operator"]; //
string operatorID = 20 [json_name = "operatorID"]; // ID
string operatorNum = 21 [json_name = "operatorNum"]; //
@ -2028,6 +2034,6 @@ message DevelopmentCycle {
string contractUUID = 2 [json_name = "contractUUID"]; // UUID
int32 developmentPeriod = 3 [json_name = "developmentPeriod"]; //
string developmentTime = 4 [json_name = "developmentTime"]; //
repeated string attachmentURLs = 5 [json_name = "attachmentURLs"]; // URLs
repeated AttachmentItem attachments = 5 [json_name = "attachments"]; // url+fileName
string deliveryContent = 6 [json_name = "deliveryContent"]; //
}

File diff suppressed because it is too large Load Diff

View File

@ -914,10 +914,41 @@ func (this *GetPaymentCyclesByContractUUIDResponse) Validate() error {
}
return nil
}
func (this *AttachmentItem) Validate() error {
return nil
}
func (this *ContractInfo) Validate() error {
for _, item := range this.ContractAttachments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("ContractAttachments", err)
}
}
}
for _, item := range this.OtherAttachments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("OtherAttachments", err)
}
}
}
return nil
}
func (this *Contract) Validate() error {
for _, item := range this.ContractAttachments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("ContractAttachments", err)
}
}
}
for _, item := range this.OtherAttachments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("OtherAttachments", err)
}
}
}
for _, item := range this.PaymentCycles {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
@ -938,5 +969,12 @@ func (this *ContractPaymentCycle) Validate() error {
return nil
}
func (this *DevelopmentCycle) Validate() error {
for _, item := range this.Attachments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Attachments", err)
}
}
}
return nil
}