已完成用户APP首期功能开发

交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
czl231
2026-09-13 00:57:32 +08:00
parent a0a4bb1218
commit 3ef33b531d
793 changed files with 40959 additions and 1204 deletions

View File

@@ -0,0 +1,127 @@
// 功能描述本人供气订单详情、合同与不可变状态记录版本1.0.0。
package user
import (
"errors"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
common "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// GetGasOrder 先验证订单归属,再读取关联事实;不输出员工手机号和内部操作备注。
func GetGasOrder(ctx *gin.Context) {
account, ok := common.UserAccount(ctx)
if !ok {
return
}
var order models.GasorderBasic
if err := impl.DBService.Where("identity = ? AND user_account_id = ? AND status <> ?", ctx.Param("identity"), account.ID, common.StatusArchived).First(&order).Error; err != nil {
gasDetailError(ctx, err)
return
}
var items []models.GasorderItem
if err := impl.DBService.Where("gasorder_basic_id = ?", order.ID).Order("created_at, identity").Find(&items).Error; err != nil {
gasDetailError(ctx, err)
return
}
lines := make([]gin.H, 0, len(items))
for _, item := range items {
lines = append(lines, gin.H{"identity": item.Identity, "name": item.ProductTypeName, "quantity": 1, "sale_amount": item.UnitPrice, "product_code": item.ProductCode})
}
var histories []models.GasorderStatus
if err := impl.DBService.Where("gasorder_basic_id = ? AND status <> ?", order.ID, common.StatusArchived).Order("occurred_at, identity").Find(&histories).Error; err != nil {
gasDetailError(ctx, err)
return
}
timeline := make([]gin.H, 0, len(histories))
for _, h := range histories {
timeline = append(timeline, gin.H{"identity": h.Identity, "status_code": h.ToStatus, "status_name": gasOrderStatusName(h.ToStatus), "occurred_at": h.OccurredAt})
}
var station models.GasBasic
if order.GasBasicID != 0 {
if err := impl.DBService.Where("id = ? AND status = ?", order.GasBasicID, common.StatusEnable).Find(&station).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
var contract models.GasorderContract
if order.GasorderContractID != 0 {
if err := impl.DBService.Where("id = ? AND user_account_id = ? AND gas_basic_id = ? AND status <> ?", order.GasorderContractID, account.ID, order.GasBasicID, common.StatusArchived).Find(&contract).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
var staff models.StaffAccount
if order.StaffAccountID != 0 {
if err := impl.DBService.Where("id = ? AND status = ?", order.StaffAccountID, common.StatusEnable).Find(&staff).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
// 支付状态是独立事实,只选择本订单、本付款人的成功支付,不能从履约状态推断已付款。
var pays []models.PaymentOrder
if err := impl.DBService.Where("business_type = ? AND business_identity = ? AND user_identity = ? AND payment_status = ?", "gasorder", order.Identity, account.Identity, 23).Order("paid_at desc, identity").Find(&pays).Error; err != nil {
gasDetailError(ctx, err)
return
}
payments := make([]gin.H, 0, len(pays))
for _, p := range pays {
payments = append(payments, gin.H{"identity": p.Identity, "channel": p.Channel, "amount": p.Amount, "paid_at": p.PaidAt})
}
infra.Response.Success(ctx, gin.H{
"identity": order.Identity, "order_no": order.OrderNo, "status_code": order.OrderStatus, "status_name": gasOrderStatusName(order.OrderStatus), "allowed_actions": gasOrderActions(order.OrderStatus),
"items": lines, "address": order.Address, "contact_name": order.ContactName, "contact_phone": order.ContactPhone,
"product_amount": order.ProductAmount, "delivery_fee": order.DeliveryFee, "discount_amount": order.DiscountAmount, "payable_amount": order.PayableAmount,
"created_at": order.CreatedAt, "remark": order.Remark, "timeline": timeline, "payments": payments,
"station_name": station.Name, "delivery_staff_name": staff.Name, "contract_identity": contract.Identity, "contract_no": contract.ContractNo,
})
}
// GetGasContract 只展示本人的合同正文附件地址不作为公共URL透传。
func GetGasContract(ctx *gin.Context) {
account, ok := common.UserAccount(ctx)
if !ok {
return
}
var contract models.GasorderContract
if err := impl.DBService.Where("identity = ? AND user_account_id = ? AND status <> ?", ctx.Param("identity"), account.ID, common.StatusArchived).First(&contract).Error; err != nil {
gasDetailError(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"identity": contract.Identity, "contract_no": contract.ContractNo, "title": contract.Title, "terms": contract.Terms, "contract_status": contract.ContractStatus, "signed_at": contract.SignedAt, "effective_at": contract.EffectiveAt, "expired_at": contract.ExpiredAt, "has_attachment": contract.FileURI != ""})
}
func gasDetailError(ctx *gin.Context, err error) {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = errcode.ErrRecordNotFound
}
infra.Response.Error(ctx, err)
}
// gasOrderActions 保留原支付和退款规则,待用户确认时新增本人收货动作。
func gasOrderActions(status int) []string {
switch status {
case common.StatusCreated:
return []string{"pay", "cancel"}
case common.StatusAssigned:
return []string{"pay", "refund", "cancel"}
case common.StatusPaid:
return []string{"refund"}
case common.StatusAwaitingConfirmation:
return []string{"confirm_receipt"}
default:
return []string{}
}
}
func gasOrderStatusName(status int) string {
names := map[int]string{16: "待付款", 18: "已分配", 19: "充装中", 20: "待配送", 21: "配送异常", 22: "已取消", 23: "已完成", 33: "配送中", 34: "待签收", 35: "已支付"}
if name, ok := names[status]; ok {
return name
}
return "状态待更新"
}