完善租客等级免押与积分管理
This commit is contained in:
@@ -11,6 +11,9 @@ export interface AdminUserItem {
|
||||
risk_status: RiskStatus
|
||||
credit_score: number
|
||||
deposit_free_quota_cent: number
|
||||
deposit_free_manual_quota_cent: number
|
||||
deposit_free_level_quota_cent: number
|
||||
deposit_free_effective_quota_cent: number
|
||||
deposit_free_used_cent: number
|
||||
deposit_free_remaining_cent: number
|
||||
renter_growth_points: number
|
||||
@@ -34,6 +37,11 @@ export interface AdminWalletAdjustPayload {
|
||||
reference_no?: string
|
||||
}
|
||||
|
||||
export interface AdminGrowthPointsAdjustPayload {
|
||||
target_points: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
export interface AdminUserQuery {
|
||||
keyword?: string
|
||||
status?: '' | UserStatus
|
||||
@@ -74,6 +82,17 @@ export async function setAdminUserDepositFreeQuota(id: number, amountCent: numbe
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adjustAdminUserGrowthPoints(
|
||||
id: number,
|
||||
payload: AdminGrowthPointsAdjustPayload
|
||||
) {
|
||||
const { data } = await apiClient.post<ApiResponse<AdminUserItem>>(
|
||||
`/admin/users/${id}/growth-points`,
|
||||
payload
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function revokeAdminUserRealname(id: number, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<AdminUserItem>>(
|
||||
`/admin/users/${id}/revoke-realname`,
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
export interface RenterGrowthLevelRule {
|
||||
code: 'normal' | 'platinum' | 'diamond' | 'peak'
|
||||
name: string
|
||||
min_points: number
|
||||
discount_bps: number
|
||||
deposit_free_quota_cent: number
|
||||
}
|
||||
|
||||
export interface RenterGrowthConfig {
|
||||
enabled: boolean
|
||||
points_per_yuan: number
|
||||
levels: RenterGrowthLevelRule[]
|
||||
}
|
||||
|
||||
export const defaultRenterGrowthConfig: RenterGrowthConfig = {
|
||||
enabled: true,
|
||||
points_per_yuan: 1,
|
||||
levels: [
|
||||
{
|
||||
code: 'normal',
|
||||
name: '普通',
|
||||
min_points: 0,
|
||||
discount_bps: 10000,
|
||||
deposit_free_quota_cent: 0,
|
||||
},
|
||||
{
|
||||
code: 'platinum',
|
||||
name: '铂金',
|
||||
min_points: 300,
|
||||
discount_bps: 9900,
|
||||
deposit_free_quota_cent: 50000,
|
||||
},
|
||||
{
|
||||
code: 'diamond',
|
||||
name: '钻石',
|
||||
min_points: 1000,
|
||||
discount_bps: 9800,
|
||||
deposit_free_quota_cent: 100000,
|
||||
},
|
||||
{
|
||||
code: 'peak',
|
||||
name: '巅峰',
|
||||
min_points: 5000,
|
||||
discount_bps: 9500,
|
||||
deposit_free_quota_cent: 150000,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export function parseRenterGrowthConfig(raw: string): RenterGrowthConfig {
|
||||
const parsed = parseRawConfig(raw)
|
||||
const incomingLevels = Array.isArray(parsed.levels) ? parsed.levels : []
|
||||
return {
|
||||
enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : true,
|
||||
points_per_yuan: positiveInteger(parsed.points_per_yuan, 1),
|
||||
levels: defaultRenterGrowthConfig.levels.map(defaultLevel => {
|
||||
const incoming = incomingLevels.find(level => level?.code === defaultLevel.code)
|
||||
return {
|
||||
code: defaultLevel.code,
|
||||
name: defaultLevel.name,
|
||||
min_points: nonNegativeInteger(incoming?.min_points, defaultLevel.min_points),
|
||||
discount_bps: positiveInteger(incoming?.discount_bps, defaultLevel.discount_bps),
|
||||
deposit_free_quota_cent: nonNegativeInteger(
|
||||
incoming?.deposit_free_quota_cent,
|
||||
defaultLevel.deposit_free_quota_cent
|
||||
),
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
function parseRawConfig(raw: string): Partial<RenterGrowthConfig> {
|
||||
try {
|
||||
return JSON.parse(raw) as Partial<RenterGrowthConfig>
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export function cloneRenterGrowthConfig(config: RenterGrowthConfig): RenterGrowthConfig {
|
||||
return JSON.parse(JSON.stringify(config)) as RenterGrowthConfig
|
||||
}
|
||||
|
||||
function positiveInteger(value: unknown, fallback: number) {
|
||||
const number = Number(value)
|
||||
return Number.isInteger(number) && number > 0 ? number : fallback
|
||||
}
|
||||
|
||||
function nonNegativeInteger(value: unknown, fallback: number) {
|
||||
const number = Number(value)
|
||||
return Number.isInteger(number) && number >= 0 ? number : fallback
|
||||
}
|
||||
Reference in New Issue
Block a user