新增商品编号搜索
This commit is contained in:
@@ -30,6 +30,7 @@ func (GameAccount) TableName() string {
|
||||
|
||||
type RentalListing struct {
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
ListingNo string `gorm:"column:listing_no;size:20;not null;uniqueIndex" json:"listing_no"`
|
||||
AccountID uint64 `gorm:"not null;index" json:"account_id"`
|
||||
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
|
||||
Price float64 `gorm:"type:decimal(12,2);not null;default:0" json:"price"`
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
type ListingDTO struct {
|
||||
ID uint64 `json:"id"`
|
||||
ListingNo string `json:"listing_no"`
|
||||
AccountID uint64 `json:"account_id"`
|
||||
OwnerID uint64 `json:"owner_id"`
|
||||
OwnerPhone string `json:"owner_phone,omitempty"`
|
||||
@@ -187,6 +188,7 @@ type ExternalUploadMeta struct {
|
||||
type ExternalUploadResult struct {
|
||||
Index int `json:"index"`
|
||||
ListingID uint64 `json:"listing_id,omitempty"`
|
||||
ListingNo string `json:"listing_no,omitempty"`
|
||||
AccountID uint64 `json:"account_id,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
ReviewStatus string `json:"review_status,omitempty"`
|
||||
@@ -195,6 +197,7 @@ type ExternalUploadResult struct {
|
||||
|
||||
type ExternalUploadResponse struct {
|
||||
ListingID uint64 `json:"listing_id,omitempty"`
|
||||
ListingNo string `json:"listing_no,omitempty"`
|
||||
AccountID uint64 `json:"account_id,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
ReviewStatus string `json:"review_status,omitempty"`
|
||||
|
||||
@@ -50,6 +50,10 @@ func initialPublishState(reviewRequired bool) (string, string, *time.Time) {
|
||||
func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bool) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
listingNo, err := r.nextListingNo(tx, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
screenshots, err := marshalScreenshots(req.ScreenshotURLS)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -78,6 +82,7 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bo
|
||||
price := normalizedListingPrice(req)
|
||||
depositAmount := roundMoney(req.DepositAmount)
|
||||
listing := model.RentalListing{
|
||||
ListingNo: listingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: ownerID,
|
||||
Price: price,
|
||||
@@ -106,6 +111,10 @@ type externalUploadCreate struct {
|
||||
func (r *Repository) CreateFromExternalUpload(upload externalUploadCreate, req CreateRequest) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
listingNo, err := r.nextListingNo(tx, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
admin, err := r.findActiveUploadAdmin(tx, upload.UploaderName)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -139,6 +148,7 @@ func (r *Repository) CreateFromExternalUpload(upload externalUploadCreate, req C
|
||||
return err
|
||||
}
|
||||
listing := model.RentalListing{
|
||||
ListingNo: listingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: owner.ID,
|
||||
Price: normalizedListingPrice(req),
|
||||
@@ -1009,6 +1019,9 @@ func publicZoneCounts(items []ListingDTO) map[string]int64 {
|
||||
|
||||
func publicSearchText(item ListingDTO) string {
|
||||
parts := []string{
|
||||
item.ListingNo,
|
||||
strconv.FormatUint(item.ID, 10),
|
||||
strconv.FormatUint(item.AccountID, 10),
|
||||
item.Title,
|
||||
item.Description,
|
||||
item.RankLevel,
|
||||
@@ -1303,6 +1316,39 @@ func (r *Repository) findForReviewUpdate(tx *gorm.DB, listingID uint64) (*model.
|
||||
return &listing, &account, nil
|
||||
}
|
||||
|
||||
func (r *Repository) nextListingNo(tx *gorm.DB, now time.Time) (string, error) {
|
||||
bizDate := now.Format("20060102")
|
||||
if tx.Dialector.Name() == "mysql" {
|
||||
if err := tx.Exec(`
|
||||
INSERT INTO listing_no_sequences (biz_date, next_seq)
|
||||
VALUES (?, LAST_INSERT_ID(1))
|
||||
ON DUPLICATE KEY UPDATE next_seq = LAST_INSERT_ID(next_seq + 1)
|
||||
`, bizDate).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
var seq int
|
||||
if err := tx.Raw("SELECT LAST_INSERT_ID()").Scan(&seq).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s%04d", bizDate, seq), nil
|
||||
}
|
||||
|
||||
var maxNo string
|
||||
if err := tx.Table("rental_listings").
|
||||
Select("COALESCE(MAX(listing_no), '')").
|
||||
Where("listing_no LIKE ?", bizDate+"%").
|
||||
Scan(&maxNo).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
seq := 1
|
||||
if len(maxNo) > len(bizDate) {
|
||||
if parsed, err := strconv.Atoi(maxNo[len(bizDate):]); err == nil {
|
||||
seq = parsed + 1
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s%04d", bizDate, seq), nil
|
||||
}
|
||||
|
||||
type listingRow struct {
|
||||
model.RentalListing
|
||||
Title string
|
||||
@@ -1394,6 +1440,7 @@ func (row listingRow) toDTO() ListingDTO {
|
||||
reviewStatus, reviewReason := normalizedReviewState(row.Status, row.ReviewStatus, row.ReviewReason)
|
||||
return ListingDTO{
|
||||
ID: row.ID,
|
||||
ListingNo: row.ListingNo,
|
||||
AccountID: row.AccountID,
|
||||
OwnerID: row.OwnerID,
|
||||
OwnerPhone: row.OwnerPhone,
|
||||
@@ -1427,6 +1474,7 @@ func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
|
||||
reviewStatus, reviewReason := normalizedReviewState(listing.Status, listing.ReviewStatus, listing.ReviewReason)
|
||||
return &ListingDTO{
|
||||
ID: listing.ID,
|
||||
ListingNo: listing.ListingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: listing.OwnerID,
|
||||
Title: account.Title,
|
||||
|
||||
@@ -150,6 +150,7 @@ func (s *Service) ImportExternalUpload(req ExternalUploadRequest, meta ExternalU
|
||||
result := ExternalUploadResult{
|
||||
Index: index,
|
||||
ListingID: dto.ID,
|
||||
ListingNo: dto.ListingNo,
|
||||
AccountID: dto.AccountID,
|
||||
Status: dto.Status,
|
||||
ReviewStatus: dto.ReviewStatus,
|
||||
@@ -157,6 +158,7 @@ func (s *Service) ImportExternalUpload(req ExternalUploadRequest, meta ExternalU
|
||||
results = append(results, result)
|
||||
if len(items) == 1 {
|
||||
resp.ListingID = dto.ID
|
||||
resp.ListingNo = dto.ListingNo
|
||||
resp.AccountID = dto.AccountID
|
||||
resp.Status = dto.Status
|
||||
resp.ReviewStatus = dto.ReviewStatus
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
-- 商品编号:用于前台展示、搜索和客服定位
|
||||
ALTER TABLE rental_listings
|
||||
ADD COLUMN listing_no VARCHAR(20) NULL COMMENT '商品编号,格式yyyyMMddNNNN' AFTER id;
|
||||
|
||||
UPDATE rental_listings AS l
|
||||
JOIN (
|
||||
SELECT
|
||||
id,
|
||||
CONCAT(
|
||||
DATE_FORMAT(created_at, '%Y%m%d'),
|
||||
LPAD(ROW_NUMBER() OVER (PARTITION BY DATE(created_at) ORDER BY id), 4, '0')
|
||||
) AS generated_listing_no
|
||||
FROM rental_listings
|
||||
) AS seq ON seq.id = l.id
|
||||
SET l.listing_no = seq.generated_listing_no
|
||||
WHERE l.listing_no IS NULL OR l.listing_no = '';
|
||||
|
||||
ALTER TABLE rental_listings
|
||||
MODIFY COLUMN listing_no VARCHAR(20) NOT NULL COMMENT '商品编号,格式yyyyMMddNNNN',
|
||||
ADD UNIQUE KEY uk_rental_listings_listing_no (listing_no);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS listing_no_sequences (
|
||||
biz_date CHAR(8) PRIMARY KEY COMMENT '业务日期yyyyMMdd',
|
||||
next_seq INT NOT NULL DEFAULT 0 COMMENT '当日已分配最大序号',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='商品编号日序列表';
|
||||
|
||||
INSERT INTO listing_no_sequences (biz_date, next_seq)
|
||||
SELECT DATE_FORMAT(created_at, '%Y%m%d') AS biz_date, COUNT(*) AS next_seq
|
||||
FROM rental_listings
|
||||
GROUP BY DATE_FORMAT(created_at, '%Y%m%d')
|
||||
ON DUPLICATE KEY UPDATE next_seq = GREATEST(next_seq, VALUES(next_seq));
|
||||
Reference in New Issue
Block a user