兼容接入订单租期字段
This commit is contained in:
@@ -296,8 +296,12 @@ func (j *Job) handleRenterConfirmTimeout(ctx context.Context, now time.Time, cfg
|
|||||||
|
|
||||||
func (j *Job) handleReturnOverdue(ctx context.Context, now time.Time, cfg thresholds) (int, error) {
|
func (j *Job) handleReturnOverdue(ctx context.Context, now time.Time, cfg thresholds) (int, error) {
|
||||||
var rows []model.RentalOrder
|
var rows []model.RentalOrder
|
||||||
|
overdueBefore := now.Add(-time.Duration(cfg.ReturnOverdueGraceMinutes) * time.Minute)
|
||||||
err := j.db.WithContext(ctx).
|
err := j.db.WithContext(ctx).
|
||||||
Where("status = ? AND rent_end_at IS NOT NULL AND rent_end_at <= ?", "renting", now.Add(-time.Duration(cfg.ReturnOverdueGraceMinutes)*time.Minute)).
|
Where(`status = ? AND (
|
||||||
|
(rented_at IS NOT NULL AND TIMESTAMPADD(HOUR, COALESCE(NULLIF(estimated_duration_hours, 0), 24), rented_at) <= ?)
|
||||||
|
OR (rented_at IS NULL AND rent_end_at IS NOT NULL AND rent_end_at <= ?)
|
||||||
|
)`, "renting", overdueBefore, overdueBefore).
|
||||||
Order("id ASC").
|
Order("id ASC").
|
||||||
Limit(100).
|
Limit(100).
|
||||||
Find(&rows).Error
|
Find(&rows).Error
|
||||||
|
|||||||
@@ -7,26 +7,28 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RentalOrder struct {
|
type RentalOrder struct {
|
||||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||||
OrderNo string `gorm:"size:64;not null;uniqueIndex" json:"order_no"`
|
OrderNo string `gorm:"size:64;not null;uniqueIndex" json:"order_no"`
|
||||||
ListingID uint64 `gorm:"not null;index" json:"listing_id"`
|
ListingID uint64 `gorm:"not null;index" json:"listing_id"`
|
||||||
AccountID uint64 `gorm:"not null;index" json:"account_id"`
|
AccountID uint64 `gorm:"not null;index" json:"account_id"`
|
||||||
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
|
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
|
||||||
RenterID uint64 `gorm:"not null;index" json:"renter_id"`
|
RenterID uint64 `gorm:"not null;index" json:"renter_id"`
|
||||||
RentStartAt *time.Time `json:"rent_start_at"`
|
RentedAt *time.Time `json:"rented_at"`
|
||||||
RentEndAt *time.Time `json:"rent_end_at"`
|
EstimatedDurationHours int `gorm:"not null;default:24" json:"estimated_duration_hours"`
|
||||||
RentHours int `gorm:"not null" json:"rent_hours"`
|
RentStartAt *time.Time `json:"rent_start_at"`
|
||||||
RentAmount float64 `gorm:"type:decimal(12,2);not null;default:0" json:"rent_amount"`
|
RentEndAt *time.Time `json:"rent_end_at"`
|
||||||
DepositAmount float64 `gorm:"type:decimal(12,2);not null;default:0" json:"deposit_amount"`
|
RentHours int `gorm:"not null" json:"rent_hours"`
|
||||||
PlatformFee float64 `gorm:"type:decimal(12,2);not null;default:0" json:"platform_fee"`
|
RentAmount float64 `gorm:"type:decimal(12,2);not null;default:0" json:"rent_amount"`
|
||||||
AccountSnapshot datatypes.JSON `json:"account_snapshot"`
|
DepositAmount float64 `gorm:"type:decimal(12,2);not null;default:0" json:"deposit_amount"`
|
||||||
Status string `gorm:"size:32;not null;default:'pending_confirm'" json:"status"`
|
PlatformFee float64 `gorm:"type:decimal(12,2);not null;default:0" json:"platform_fee"`
|
||||||
HandoffStatus string `gorm:"size:32;not null;default:'none'" json:"handoff_status"`
|
AccountSnapshot datatypes.JSON `json:"account_snapshot"`
|
||||||
SettlementStatus string `gorm:"size:32;not null;default:'unsettled'" json:"settlement_status"`
|
Status string `gorm:"size:32;not null;default:'pending_confirm'" json:"status"`
|
||||||
OwnerSettledAt *time.Time `json:"owner_settled_at"`
|
HandoffStatus string `gorm:"size:32;not null;default:'none'" json:"handoff_status"`
|
||||||
SettledAt *time.Time `json:"settled_at"`
|
SettlementStatus string `gorm:"size:32;not null;default:'unsettled'" json:"settlement_status"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
OwnerSettledAt *time.Time `json:"owner_settled_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
SettledAt *time.Time `json:"settled_at"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RentalOrder) TableName() string {
|
func (RentalOrder) TableName() string {
|
||||||
|
|||||||
@@ -7,29 +7,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OrderDTO struct {
|
type OrderDTO struct {
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
ListingID uint64 `json:"listing_id"`
|
ListingID uint64 `json:"listing_id"`
|
||||||
AccountID uint64 `json:"account_id"`
|
AccountID uint64 `json:"account_id"`
|
||||||
OwnerID uint64 `json:"owner_id"`
|
OwnerID uint64 `json:"owner_id"`
|
||||||
RenterID uint64 `json:"renter_id"`
|
RenterID uint64 `json:"renter_id"`
|
||||||
OwnerPhone string `json:"owner_phone,omitempty"`
|
OwnerPhone string `json:"owner_phone,omitempty"`
|
||||||
RenterPhone string `json:"renter_phone,omitempty"`
|
RenterPhone string `json:"renter_phone,omitempty"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
ServerRegion string `json:"server_region"`
|
ServerRegion string `json:"server_region"`
|
||||||
LoginPlatform string `json:"login_platform"`
|
LoginPlatform string `json:"login_platform"`
|
||||||
RentStartAt *time.Time `json:"rent_start_at"`
|
RentedAt *time.Time `json:"rented_at"`
|
||||||
RentEndAt *time.Time `json:"rent_end_at"`
|
EstimatedDurationHours int `json:"estimated_duration_hours"`
|
||||||
RentAmount float64 `json:"rent_amount"`
|
RentStartAt *time.Time `json:"rent_start_at"`
|
||||||
DepositAmount float64 `json:"deposit_amount"`
|
RentEndAt *time.Time `json:"rent_end_at"`
|
||||||
PlatformFee float64 `json:"platform_fee"`
|
RentAmount float64 `json:"rent_amount"`
|
||||||
AccountSnapshot datatypes.JSON `json:"account_snapshot"`
|
DepositAmount float64 `json:"deposit_amount"`
|
||||||
Status string `json:"status"`
|
PlatformFee float64 `json:"platform_fee"`
|
||||||
HandoffStatus string `json:"handoff_status"`
|
AccountSnapshot datatypes.JSON `json:"account_snapshot"`
|
||||||
SettlementStatus string `json:"settlement_status"`
|
Status string `json:"status"`
|
||||||
Checkout *CheckoutDTO `json:"checkout,omitempty"`
|
HandoffStatus string `json:"handoff_status"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
SettlementStatus string `json:"settlement_status"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
Checkout *CheckoutDTO `json:"checkout,omitempty"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateRequest struct {
|
type CreateRequest struct {
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ func listingOrderPrice(listing model.RentalListing) float64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orderDurationHours(order model.RentalOrder) int {
|
||||||
|
if order.EstimatedDurationHours > 0 {
|
||||||
|
return order.EstimatedDurationHours
|
||||||
|
}
|
||||||
|
if order.RentHours > 0 {
|
||||||
|
return order.RentHours
|
||||||
|
}
|
||||||
|
return internalOrderHours
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, error) {
|
func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, error) {
|
||||||
var createdID uint64
|
var createdID uint64
|
||||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||||
@@ -71,19 +81,20 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro
|
|||||||
}
|
}
|
||||||
rentHours := internalOrderHours
|
rentHours := internalOrderHours
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
OrderNo: orderNo,
|
OrderNo: orderNo,
|
||||||
ListingID: listing.ID,
|
ListingID: listing.ID,
|
||||||
AccountID: listing.AccountID,
|
AccountID: listing.AccountID,
|
||||||
OwnerID: listing.OwnerID,
|
OwnerID: listing.OwnerID,
|
||||||
RenterID: renterID,
|
RenterID: renterID,
|
||||||
RentHours: rentHours,
|
EstimatedDurationHours: rentHours,
|
||||||
RentAmount: listingOrderPrice(listing),
|
RentHours: rentHours,
|
||||||
DepositAmount: listing.DepositAmount,
|
RentAmount: listingOrderPrice(listing),
|
||||||
PlatformFee: 0,
|
DepositAmount: listing.DepositAmount,
|
||||||
AccountSnapshot: snapshot,
|
PlatformFee: 0,
|
||||||
Status: "pending_payment",
|
AccountSnapshot: snapshot,
|
||||||
HandoffStatus: "none",
|
Status: "pending_payment",
|
||||||
SettlementStatus: "unsettled",
|
HandoffStatus: "none",
|
||||||
|
SettlementStatus: "unsettled",
|
||||||
}
|
}
|
||||||
if err := tx.Create(&order).Error; err != nil {
|
if err := tx.Create(&order).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -357,8 +368,11 @@ func (r *Repository) ConfirmReceive(userID uint64, orderID uint64) error {
|
|||||||
}
|
}
|
||||||
order.Status = "renting"
|
order.Status = "renting"
|
||||||
order.HandoffStatus = "received"
|
order.HandoffStatus = "received"
|
||||||
|
durationHours := orderDurationHours(order)
|
||||||
|
order.EstimatedDurationHours = durationHours
|
||||||
order.RentStartAt = &now
|
order.RentStartAt = &now
|
||||||
rentEnd := now.Add(time.Duration(order.RentHours) * time.Hour)
|
order.RentedAt = &now
|
||||||
|
rentEnd := now.Add(time.Duration(durationHours) * time.Hour)
|
||||||
order.RentEndAt = &rentEnd
|
order.RentEndAt = &rentEnd
|
||||||
orderID := order.ID
|
orderID := order.ID
|
||||||
if err := notification.Append(tx, notification.Entry{
|
if err := notification.Append(tx, notification.Entry{
|
||||||
@@ -1053,29 +1067,41 @@ type orderRow struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (row orderRow) toDTO() OrderDTO {
|
func (row orderRow) toDTO() OrderDTO {
|
||||||
|
rentedAt := row.RentedAt
|
||||||
|
if rentedAt == nil {
|
||||||
|
rentedAt = row.RentStartAt
|
||||||
|
}
|
||||||
|
durationHours := orderDurationHours(row.RentalOrder)
|
||||||
|
rentEndAt := row.RentEndAt
|
||||||
|
if rentEndAt == nil && rentedAt != nil && durationHours > 0 {
|
||||||
|
calculatedEnd := rentedAt.Add(time.Duration(durationHours) * time.Hour)
|
||||||
|
rentEndAt = &calculatedEnd
|
||||||
|
}
|
||||||
return OrderDTO{
|
return OrderDTO{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
OrderNo: row.OrderNo,
|
OrderNo: row.OrderNo,
|
||||||
ListingID: row.ListingID,
|
ListingID: row.ListingID,
|
||||||
AccountID: row.AccountID,
|
AccountID: row.AccountID,
|
||||||
OwnerID: row.OwnerID,
|
OwnerID: row.OwnerID,
|
||||||
RenterID: row.RenterID,
|
RenterID: row.RenterID,
|
||||||
OwnerPhone: row.OwnerPhone,
|
OwnerPhone: row.OwnerPhone,
|
||||||
RenterPhone: row.RenterPhone,
|
RenterPhone: row.RenterPhone,
|
||||||
Title: row.Title,
|
Title: row.Title,
|
||||||
ServerRegion: row.ServerRegion,
|
ServerRegion: row.ServerRegion,
|
||||||
LoginPlatform: row.LoginPlatform,
|
LoginPlatform: row.LoginPlatform,
|
||||||
RentStartAt: row.RentStartAt,
|
RentedAt: rentedAt,
|
||||||
RentEndAt: row.RentEndAt,
|
EstimatedDurationHours: durationHours,
|
||||||
RentAmount: row.RentAmount,
|
RentStartAt: row.RentStartAt,
|
||||||
DepositAmount: row.DepositAmount,
|
RentEndAt: rentEndAt,
|
||||||
PlatformFee: row.PlatformFee,
|
RentAmount: row.RentAmount,
|
||||||
AccountSnapshot: row.AccountSnapshot,
|
DepositAmount: row.DepositAmount,
|
||||||
Status: row.Status,
|
PlatformFee: row.PlatformFee,
|
||||||
HandoffStatus: row.HandoffStatus,
|
AccountSnapshot: row.AccountSnapshot,
|
||||||
SettlementStatus: row.SettlementStatus,
|
Status: row.Status,
|
||||||
CreatedAt: row.CreatedAt,
|
HandoffStatus: row.HandoffStatus,
|
||||||
UpdatedAt: row.UpdatedAt,
|
SettlementStatus: row.SettlementStatus,
|
||||||
|
CreatedAt: row.CreatedAt,
|
||||||
|
UpdatedAt: row.UpdatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ CREATE TABLE rental_orders (
|
|||||||
account_id BIGINT UNSIGNED NOT NULL,
|
account_id BIGINT UNSIGNED NOT NULL,
|
||||||
owner_id BIGINT UNSIGNED NOT NULL,
|
owner_id BIGINT UNSIGNED NOT NULL,
|
||||||
renter_id BIGINT UNSIGNED NOT NULL,
|
renter_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
rented_at DATETIME NULL,
|
||||||
|
estimated_duration_hours INT NOT NULL DEFAULT 24,
|
||||||
rent_start_at DATETIME NULL,
|
rent_start_at DATETIME NULL,
|
||||||
rent_end_at DATETIME NULL,
|
rent_end_at DATETIME NULL,
|
||||||
rent_hours INT NOT NULL,
|
rent_hours INT NOT NULL,
|
||||||
@@ -95,7 +97,8 @@ CREATE TABLE rental_orders (
|
|||||||
UNIQUE KEY uk_rental_orders_order_no (order_no),
|
UNIQUE KEY uk_rental_orders_order_no (order_no),
|
||||||
KEY idx_rental_orders_renter_status (renter_id, status),
|
KEY idx_rental_orders_renter_status (renter_id, status),
|
||||||
KEY idx_rental_orders_owner_status (owner_id, status),
|
KEY idx_rental_orders_owner_status (owner_id, status),
|
||||||
KEY idx_rental_orders_listing_id (listing_id)
|
KEY idx_rental_orders_listing_id (listing_id),
|
||||||
|
KEY idx_rental_orders_rented_at (status, rented_at)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE handoff_records (
|
CREATE TABLE handoff_records (
|
||||||
|
|||||||
@@ -41,6 +41,67 @@ SET price = CASE
|
|||||||
END
|
END
|
||||||
WHERE price <= 0;
|
WHERE price <= 0;
|
||||||
|
|
||||||
|
SET @order_rented_at_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'rental_orders'
|
||||||
|
AND column_name = 'rented_at'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @add_order_rented_at_sql := IF(
|
||||||
|
@order_rented_at_exists = 0,
|
||||||
|
'ALTER TABLE rental_orders ADD COLUMN rented_at DATETIME NULL AFTER renter_id',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE add_order_rented_at_stmt FROM @add_order_rented_at_sql;
|
||||||
|
EXECUTE add_order_rented_at_stmt;
|
||||||
|
DEALLOCATE PREPARE add_order_rented_at_stmt;
|
||||||
|
|
||||||
|
SET @order_estimated_duration_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'rental_orders'
|
||||||
|
AND column_name = 'estimated_duration_hours'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @add_order_estimated_duration_sql := IF(
|
||||||
|
@order_estimated_duration_exists = 0,
|
||||||
|
'ALTER TABLE rental_orders ADD COLUMN estimated_duration_hours INT NOT NULL DEFAULT 24 AFTER rented_at',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE add_order_estimated_duration_stmt FROM @add_order_estimated_duration_sql;
|
||||||
|
EXECUTE add_order_estimated_duration_stmt;
|
||||||
|
DEALLOCATE PREPARE add_order_estimated_duration_stmt;
|
||||||
|
|
||||||
|
UPDATE rental_orders
|
||||||
|
SET
|
||||||
|
rented_at = COALESCE(rented_at, rent_start_at),
|
||||||
|
estimated_duration_hours = CASE
|
||||||
|
WHEN estimated_duration_hours > 0 THEN estimated_duration_hours
|
||||||
|
WHEN rent_hours > 0 THEN rent_hours
|
||||||
|
ELSE 24
|
||||||
|
END
|
||||||
|
WHERE rented_at IS NULL OR estimated_duration_hours <= 0;
|
||||||
|
|
||||||
|
SET @order_rented_at_index_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'rental_orders'
|
||||||
|
AND index_name = 'idx_rental_orders_rented_at'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @add_order_rented_at_index_sql := IF(
|
||||||
|
@order_rented_at_index_exists = 0,
|
||||||
|
'ALTER TABLE rental_orders ADD KEY idx_rental_orders_rented_at (status, rented_at)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE add_order_rented_at_index_stmt FROM @add_order_rented_at_index_sql;
|
||||||
|
EXECUTE add_order_rented_at_index_stmt;
|
||||||
|
DEALLOCATE PREPARE add_order_rented_at_index_stmt;
|
||||||
|
|
||||||
INSERT INTO system_configs (`key`, `value`, description)
|
INSERT INTO system_configs (`key`, `value`, description)
|
||||||
VALUES ('order.pending_payment_timeout_minutes', '15', '订单待支付超时取消分钟数')
|
VALUES ('order.pending_payment_timeout_minutes', '15', '订单待支付超时取消分钟数')
|
||||||
ON DUPLICATE KEY UPDATE `key` = VALUES(`key`);
|
ON DUPLICATE KEY UPDATE `key` = VALUES(`key`);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export interface Order {
|
|||||||
title: string
|
title: string
|
||||||
server_region: string
|
server_region: string
|
||||||
login_platform: string
|
login_platform: string
|
||||||
|
rented_at?: string
|
||||||
|
estimated_duration_hours: number
|
||||||
rent_start_at?: string
|
rent_start_at?: string
|
||||||
rent_end_at?: string
|
rent_end_at?: string
|
||||||
rent_amount: number
|
rent_amount: number
|
||||||
|
|||||||
@@ -282,6 +282,19 @@ function readError(error: unknown, fallback: string) {
|
|||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function orderRentedAt() {
|
||||||
|
return order.value?.rented_at || order.value?.rent_start_at
|
||||||
|
}
|
||||||
|
|
||||||
|
function orderEstimatedEndAt() {
|
||||||
|
if (!order.value) return undefined
|
||||||
|
if (order.value.rent_end_at) return order.value.rent_end_at
|
||||||
|
const rentedAt = orderRentedAt()
|
||||||
|
const durationHours = Number(order.value.estimated_duration_hours || 0)
|
||||||
|
if (!rentedAt || durationHours <= 0) return undefined
|
||||||
|
return new Date(new Date(rentedAt).getTime() + durationHours * 60 * 60 * 1000).toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
function hydrateCounterForm() {
|
function hydrateCounterForm() {
|
||||||
if (!order.value?.checkout) return
|
if (!order.value?.checkout) return
|
||||||
const checkout = order.value.checkout
|
const checkout = order.value.checkout
|
||||||
@@ -327,8 +340,8 @@ function linesToList(value: string) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="order" class="order-panel">
|
<div v-if="order" class="order-panel">
|
||||||
<p>开始:{{ formatDateTime(order.rent_start_at, '未开始') }}</p>
|
<p>开始:{{ formatDateTime(orderRentedAt(), '未开始') }}</p>
|
||||||
<p>预计截止:{{ formatDateTime(order.rent_end_at, '未设置') }}</p>
|
<p>预计截止:{{ formatDateTime(orderEstimatedEndAt(), '未设置') }}</p>
|
||||||
<p v-if="order.status === 'pending_payment'">订单待支付,支付后账号进入交接流程。</p>
|
<p v-if="order.status === 'pending_payment'">订单待支付,支付后账号进入交接流程。</p>
|
||||||
<el-button v-if="order.status === 'pending_payment' && isRenter" type="primary" :loading="paying" @click="handlePay">
|
<el-button v-if="order.status === 'pending_payment' && isRenter" type="primary" :loading="paying" @click="handlePay">
|
||||||
支付订单
|
支付订单
|
||||||
|
|||||||
@@ -63,6 +63,19 @@ function readError(error: unknown, fallback: string) {
|
|||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function orderRentedAt() {
|
||||||
|
return order.value?.rented_at || order.value?.rent_start_at
|
||||||
|
}
|
||||||
|
|
||||||
|
function orderEstimatedEndAt() {
|
||||||
|
if (!order.value) return undefined
|
||||||
|
if (order.value.rent_end_at) return order.value.rent_end_at
|
||||||
|
const rentedAt = orderRentedAt()
|
||||||
|
const durationHours = Number(order.value.estimated_duration_hours || 0)
|
||||||
|
if (!rentedAt || durationHours <= 0) return undefined
|
||||||
|
return new Date(new Date(rentedAt).getTime() + durationHours * 60 * 60 * 1000).toISOString()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -106,8 +119,8 @@ function readError(error: unknown, fallback: string) {
|
|||||||
<h2>用户信息</h2>
|
<h2>用户信息</h2>
|
||||||
<p>租客:{{ order.renter_phone || order.renter_id }}</p>
|
<p>租客:{{ order.renter_phone || order.renter_id }}</p>
|
||||||
<p>号主:{{ order.owner_phone || order.owner_id }}</p>
|
<p>号主:{{ order.owner_phone || order.owner_id }}</p>
|
||||||
<p>开始:{{ formatDateTime(order.rent_start_at, '未开始') }}</p>
|
<p>开始:{{ formatDateTime(orderRentedAt(), '未开始') }}</p>
|
||||||
<p>预计截止:{{ formatDateTime(order.rent_end_at, '未设置') }}</p>
|
<p>预计截止:{{ formatDateTime(orderEstimatedEndAt(), '未设置') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-panel dashboard-panel">
|
<div class="order-panel dashboard-panel">
|
||||||
|
|||||||
Reference in New Issue
Block a user