完善租客等级免押与积分管理

This commit is contained in:
yml2213
2026-07-26 18:07:10 +08:00
parent 379536e5c5
commit c594b543d1
24 changed files with 1296 additions and 178 deletions
@@ -18,6 +18,7 @@ import {
} from '@/features/listings/api/homeConfig'
import type { OrderAgreements } from '@/features/orders/api/orders'
import { fetchSystemConfigs, type SystemConfig } from '@/features/admin/api/systemConfigs'
import { parseRenterGrowthConfig } from '@/features/admin/api/renterGrowth'
import { formatDateTime } from '@/shared/utils/time'
import { safeParseJSON } from '@/shared/utils/json'
import { formatSystemConfigSelectValue } from '@/shared/utils/systemConfigOptions'
@@ -28,14 +29,12 @@ import SalePriceDialog from '../components/SalePriceDialog.vue'
import HomeAnnouncementsDialog from '../components/HomeAnnouncementsDialog.vue'
import HomeBannersDialog from '../components/HomeBannersDialog.vue'
import AwRecycleDialog from '../components/AwRecycleDialog.vue'
import {
defaultAWRecycleConfig,
type AWRecycleConfig,
} from '@/features/listings/api/homeConfig'
import { defaultAWRecycleConfig, type AWRecycleConfig } from '@/features/listings/api/homeConfig'
import ListingPublishAgreementsDialog from '../components/ListingPublishAgreementsDialog.vue'
import OrderAgreementsDialog from '../components/OrderAgreementsDialog.vue'
import PostRentalNoticeDialog from '../components/PostRentalNoticeDialog.vue'
import GeneralConfigDialog from '../components/GeneralConfigDialog.vue'
import RenterGrowthConfigDialog from '../components/RenterGrowthConfigDialog.vue'
import AutoWelcomeConfig from '../components/AutoWelcomeConfig.vue'
import {
fetchAutoWelcomeMessage,
@@ -80,6 +79,7 @@ const listingPublishAgreementsVisible = ref(false)
const agreementsVisible = ref(false)
const postRentalNoticeVisible = ref(false)
const generalVisible = ref(false)
const renterGrowthVisible = ref(false)
const publishConfig = computed(
() => configs.value.find(item => item.key === 'listing.publish_options') || null
@@ -90,6 +90,9 @@ const salePriceConfig = computed(
const listingPublishCooldownConfig = computed(
() => configs.value.find(item => item.key === 'listing.publish_cooldown_minutes') || null
)
const renterGrowthConfig = computed(
() => configs.value.find(item => item.key === 'renter.growth_level_rules') || null
)
const homeAnnouncementsConfig = computed(
() => configs.value.find(item => item.key === 'mobile.home_announcements') || null
)
@@ -153,7 +156,8 @@ const regularConfigs = computed(() =>
item.key !== 'chat.renter_retention_days_after_order_end' &&
item.key !== 'integration.paddle_ocr_token' &&
item.key !== 'integration.paddle_ocr_job_url' &&
item.key !== 'integration.paddle_ocr_model'
item.key !== 'integration.paddle_ocr_model' &&
item.key !== 'renter.growth_level_rules'
)
)
@@ -197,6 +201,15 @@ const awRecycleStats = computed(() => {
}
})
const renterGrowthStats = computed(() => {
const config = parseRenterGrowthConfig(renterGrowthConfig.value?.value || '')
return {
enabled: config.enabled,
pointsPerYuan: config.points_per_yuan,
levels: config.levels.filter(level => level.code !== 'normal'),
}
})
const agreementStats = computed(() => {
const agreements = parseOrderAgreements(orderAgreementsConfig.value?.value || '')
return {
@@ -261,6 +274,8 @@ function openEdit(row: SystemConfig) {
agreementsVisible.value = true
} else if (row.key === 'profile.post_rental_notice') {
postRentalNoticeVisible.value = true
} else if (row.key === 'renter.growth_level_rules') {
renterGrowthVisible.value = true
} else if (row.key === 'chat.renter_retention_days_after_order_end') {
generalVisible.value = true
} else {
@@ -410,7 +425,7 @@ function formatConfigValue(row: SystemConfig) {
<div class="page-header">
<p class="eyebrow">Configs</p>
<h1>系统配置</h1>
<p>管理交接超时、归还超时、短信限流、最低押金和抽成比例。</p>
<p>管理发布、订单、成长等级、首页内容与外部集成参数。</p>
</div>
<section v-if="publishConfig" class="publish-config-panel">
@@ -514,6 +529,31 @@ function formatConfigValue(row: SystemConfig) {
</div>
</section>
<section v-if="renterGrowthConfig" class="publish-config-panel">
<div class="publish-config-main">
<div>
<p class="eyebrow">Renter Growth</p>
<h2>租客成长等级</h2>
<span>管理完成订单后的积分换算、各等级租金支付比例与等级免押额度。</span>
</div>
<el-button type="primary" @click="openEdit(renterGrowthConfig)">编辑成长等级</el-button>
</div>
<div class="publish-stat-grid home-stat-grid">
<div class="publish-stat">
<strong>{{ renterGrowthStats.enabled ? '已启用' : '已停用' }}</strong>
<span>成长权益</span>
</div>
<div class="publish-stat">
<strong>{{ renterGrowthStats.pointsPerYuan }}</strong>
<span>每元积分</span>
</div>
<div v-for="level in renterGrowthStats.levels" :key="level.code" class="publish-stat">
<strong>¥{{ level.deposit_free_quota_cent / 100 }}</strong>
<span>{{ level.name }}免押</span>
</div>
</div>
</section>
<section
v-if="homeAnnouncementsConfig || homeBannersConfig || awRecycleConfig"
class="publish-config-panel"
@@ -555,7 +595,9 @@ function formatConfigValue(row: SystemConfig) {
</div>
<div class="publish-stat">
<strong>更新</strong>
<span>{{ formatHomeConfigStatus(awRecycleConfig || homeBannersConfig, '未初始化') }}</span>
<span>{{
formatHomeConfigStatus(awRecycleConfig || homeBannersConfig, '未初始化')
}}</span>
</div>
</div>
</section>
@@ -836,6 +878,13 @@ function formatConfigValue(row: SystemConfig) {
@saved="loadConfigs"
/>
<RenterGrowthConfigDialog
v-if="renterGrowthConfig"
v-model="renterGrowthVisible"
:config="renterGrowthConfig"
@saved="loadConfigs"
/>
<GeneralConfigDialog
v-if="currentEditingConfig"
v-model="generalVisible"