243 lines
7.1 KiB
Vue
243 lines
7.1 KiB
Vue
<template>
|
||
<ElDialog
|
||
v-model="dialogVisible"
|
||
:title="`调整实际信用额度 - ${currentShop?.shop_name || ''}`"
|
||
width="520px"
|
||
:close-on-click-modal="false"
|
||
@closed="resetDialog"
|
||
>
|
||
<ElDescriptions :column="1" border class="credit-preview">
|
||
<ElDescriptionsItem label="店铺名称">
|
||
{{ currentShop?.shop_name || '-' }}
|
||
</ElDescriptionsItem>
|
||
<ElDescriptionsItem label="当前版本">
|
||
{{ currentShop?.version ?? '-' }}
|
||
</ElDescriptionsItem>
|
||
<ElDescriptionsItem label="修改前">
|
||
{{ formatCreditPreview(currentShop?.credit_enabled, currentShop?.credit_limit) }}
|
||
</ElDescriptionsItem>
|
||
<ElDescriptionsItem label="修改后">
|
||
{{ formatCreditPreview(creditForm.credit_enabled, creditLimitFen) }}
|
||
</ElDescriptionsItem>
|
||
</ElDescriptions>
|
||
|
||
<ElAlert
|
||
title="实际可用金额、欠款金额和欠款状态以后端刷新后的资金概况为准。"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
class="credit-dialog-alert"
|
||
/>
|
||
|
||
<ElForm ref="creditFormRef" :model="creditForm" :rules="creditRules" label-width="110px">
|
||
<ElFormItem label="启用信用">
|
||
<ElSwitch v-model="creditForm.credit_enabled" @change="handleCreditEnabledChange" />
|
||
</ElFormItem>
|
||
<ElFormItem label="实际信用额度" prop="credit_limit_yuan">
|
||
<ElInputNumber
|
||
v-model="creditForm.credit_limit_yuan"
|
||
:disabled="!creditForm.credit_enabled"
|
||
:min="0"
|
||
:precision="2"
|
||
:step="100"
|
||
controls-position="right"
|
||
style="width: 100%"
|
||
placeholder="请输入实际信用额度"
|
||
/>
|
||
<div class="credit-dialog-tip">单位:元;关闭信用时额度将自动归零</div>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||
<ElButton type="primary" :loading="submitting" @click="handleSubmit">确认调整</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
import { CommissionService, ShopService } from '@/api/modules'
|
||
import type { ShopFundSummaryItem } from '@/types/api/commission'
|
||
import { fenToYuan, formatMoney, yuanToFen } from '@/utils/business/format'
|
||
import { normalizeApiError } from '@/utils/business/apiError'
|
||
|
||
const props = defineProps<{
|
||
modelValue: boolean
|
||
shop: ShopFundSummaryItem | null
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
'update:modelValue': [value: boolean]
|
||
submitted: []
|
||
}>()
|
||
|
||
const dialogVisible = computed({
|
||
get: () => props.modelValue,
|
||
set: (value: boolean) => emit('update:modelValue', value)
|
||
})
|
||
|
||
const creditFormRef = ref<FormInstance>()
|
||
const submitting = ref(false)
|
||
const currentShop = ref<ShopFundSummaryItem | null>(null)
|
||
const creditForm = reactive({
|
||
credit_enabled: false,
|
||
credit_limit_yuan: 0
|
||
})
|
||
|
||
const creditLimitFen = computed(() =>
|
||
creditForm.credit_enabled ? yuanToFen(creditForm.credit_limit_yuan) || 0 : 0
|
||
)
|
||
|
||
const creditRules = computed<FormRules>(() => ({
|
||
credit_limit_yuan: [
|
||
{
|
||
validator: (
|
||
_rule: unknown,
|
||
value: number | undefined,
|
||
callback: (error?: Error) => void
|
||
) => {
|
||
if (!creditForm.credit_enabled) {
|
||
callback()
|
||
return
|
||
}
|
||
if (value === undefined || value === null || Number.isNaN(value)) {
|
||
callback(new Error('请输入实际信用额度'))
|
||
return
|
||
}
|
||
if (value <= 0) {
|
||
callback(new Error('实际信用额度必须大于0'))
|
||
return
|
||
}
|
||
callback()
|
||
},
|
||
trigger: 'blur'
|
||
}
|
||
]
|
||
}))
|
||
|
||
const formatCreditPreview = (enabled?: boolean, creditLimit?: number) =>
|
||
enabled ? `启用 / ${formatMoney(creditLimit || 0)}` : '关闭 / ¥0.00'
|
||
|
||
const syncForm = (summary: ShopFundSummaryItem) => {
|
||
creditForm.credit_enabled = Boolean(summary.credit_enabled)
|
||
creditForm.credit_limit_yuan = summary.credit_enabled ? fenToYuan(summary.credit_limit) : 0
|
||
nextTick(() => creditFormRef.value?.clearValidate())
|
||
}
|
||
|
||
watch(
|
||
() => [props.modelValue, props.shop] as const,
|
||
([visible, shop]) => {
|
||
if (visible && shop) {
|
||
currentShop.value = shop
|
||
syncForm(shop)
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
)
|
||
|
||
const handleCreditEnabledChange = (enabled: boolean | string | number) => {
|
||
if (!enabled) {
|
||
creditForm.credit_limit_yuan = 0
|
||
creditFormRef.value?.clearValidate('credit_limit_yuan')
|
||
}
|
||
}
|
||
|
||
const resetDialog = () => {
|
||
creditFormRef.value?.resetFields()
|
||
currentShop.value = null
|
||
creditForm.credit_enabled = false
|
||
creditForm.credit_limit_yuan = 0
|
||
}
|
||
|
||
const loadLatestSummary = async () => {
|
||
if (!currentShop.value) return null
|
||
const res = await CommissionService.getShopFundSummary({
|
||
page: 1,
|
||
page_size: 100,
|
||
shop_name: currentShop.value.shop_name
|
||
})
|
||
if (res.code !== 0) return null
|
||
return (
|
||
(res.data.items || []).find((item) => item.shop_id === currentShop.value?.shop_id) || null
|
||
)
|
||
}
|
||
|
||
const isConflict = (error: unknown) => {
|
||
const normalized = normalizeApiError(error)
|
||
return normalized.kind === 'conflict' || normalized.status === 409
|
||
}
|
||
|
||
const handleSubmit = async () => {
|
||
if (!currentShop.value || !creditFormRef.value) return
|
||
|
||
try {
|
||
await creditFormRef.value.validate()
|
||
} catch {
|
||
return
|
||
}
|
||
|
||
submitting.value = true
|
||
try {
|
||
const res = await ShopService.updateShopCreditLimit(currentShop.value.shop_id, {
|
||
credit_enabled: creditForm.credit_enabled,
|
||
credit_limit: creditLimitFen.value,
|
||
version: currentShop.value.version
|
||
})
|
||
|
||
if (res.code === 0) {
|
||
ElMessage.success('实际信用额度调整成功')
|
||
dialogVisible.value = false
|
||
emit('submitted')
|
||
return
|
||
}
|
||
|
||
if (res.code === 409) {
|
||
const latest = await loadLatestSummary()
|
||
if (latest) {
|
||
currentShop.value = latest
|
||
syncForm(latest)
|
||
}
|
||
ElMessage.warning('资金概况已被其他操作更新,已刷新最新版本;请确认后重新提交')
|
||
return
|
||
}
|
||
|
||
ElMessage.error(res.msg || '实际信用额度调整失败')
|
||
} catch (error) {
|
||
if (isConflict(error)) {
|
||
const latest = await loadLatestSummary()
|
||
if (latest) {
|
||
currentShop.value = latest
|
||
syncForm(latest)
|
||
}
|
||
ElMessage.warning('资金概况已被其他操作更新,已刷新最新版本;请确认后重新提交')
|
||
} else {
|
||
console.error('实际信用额度调整失败:', error)
|
||
}
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.credit-preview {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.credit-dialog-alert {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.credit-dialog-tip {
|
||
margin-top: 6px;
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
</style>
|