费用优化
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import { actOnOverseasFee, type OverseasFee } from '../api/overseasFees'
|
||||
import { adjustStorageRentFee } from '../api/storageRent'
|
||||
import { feePermissions, feeMoney } from '../overseasFeePresentation'
|
||||
import StorageRentFeeDetails from './StorageRentFeeDetails.vue'
|
||||
const props = defineProps<{ fee: OverseasFee | null; action: string; readonly?: boolean }>()
|
||||
const open = defineModel<boolean>({ required: true })
|
||||
const emit = defineEmits<{ saved: [] }>()
|
||||
const access = useAccessPreviewStore()
|
||||
const amount = ref(0), reason = ref(''), busy = ref(false), error = ref<ApiErrorDetails | null>(null)
|
||||
const key = ref(''), fingerprint = ref('')
|
||||
const adjusting = computed(() => props.action === 'ADJUST_RENT')
|
||||
const allowed = (action: string) => !props.readonly && props.fee?.allowedActions.includes(action) && access.can(action === 'ADJUST_RENT' ? feePermissions.edit : feePermissions.review)
|
||||
function reset() { amount.value = props.fee?.originalAmount ?? 0; reason.value = ''; error.value = null; key.value = ''; fingerprint.value = '' }
|
||||
watch(open, value => { if (value) reset() }, { immediate: true })
|
||||
async function submit(decision?: 'APPROVE' | 'REJECT') {
|
||||
const fee = props.fee, action = adjusting.value ? 'ADJUST_RENT' : decision
|
||||
if (!fee || !action || !allowed(action) || busy.value) return
|
||||
if ((adjusting.value || decision === 'REJECT') && !reason.value.trim()) { ElMessage.warning('请填写说明'); return }
|
||||
if (adjusting.value && (!Number.isFinite(amount.value) || amount.value < 0)) { ElMessage.warning('请输入有效金额'); return }
|
||||
const body = adjusting.value ? { expectedVersion: fee.sourceVersion, amount: amount.value, reason: reason.value.trim() }
|
||||
: { decision, reason: reason.value.trim() || undefined, expectedVersion: fee.sourceVersion }
|
||||
const next = JSON.stringify([fee.sourceFeeId, body])
|
||||
if (fingerprint.value !== next) { fingerprint.value = next; key.value = crypto.randomUUID() }
|
||||
busy.value = true; error.value = null
|
||||
try {
|
||||
if (adjusting.value) await adjustStorageRentFee(fee.sourceFeeId, { expectedVersion: fee.sourceVersion, amount: amount.value, reason: reason.value.trim(), idempotencyKey: key.value })
|
||||
else await actOnOverseasFee(fee.sourceFeeId, decision!, { ...body, idempotencyKey: key.value })
|
||||
open.value = false; ElMessage.success(adjusting.value ? '仓租已调整' : decision === 'APPROVE' ? '审核通过,正在处理扣款' : '仓租已驳回'); emit('saved')
|
||||
} catch (failure) { error.value = getApiErrorDetails(failure, '仓租操作失败') }
|
||||
finally { busy.value = false }
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<AppDialog v-model="open" append-to-body :title="adjusting ? '调整仓租' : '审核仓租'" width="760px" class="admin-density-dialog admin-workbench is-dialog" :show-confirm="false" :confirm-loading="busy" lock-while-submitting>
|
||||
<template v-if="fee">
|
||||
<p>{{ fee.businessNo }} · 仓租 {{ feeMoney(fee.originalAmount, fee.originalCurrency) }}</p>
|
||||
<StorageRentFeeDetails :fee="fee" />
|
||||
<p v-if="fee.feeRemark">费用说明:{{ fee.feeRemark }}</p>
|
||||
<el-form label-position="top" :disabled="busy" class="density-form">
|
||||
<el-form-item v-if="adjusting" :label="`仓租金额(${fee.originalCurrency})`" required><el-input-number v-model="amount" :precision="2" :min="0" :max="999999999999.99" /></el-form-item>
|
||||
<el-form-item :label="adjusting ? '调整说明' : '审核说明(驳回必填)'" :required="adjusting"><el-input v-model="reason" type="textarea" :maxlength="500" show-word-limit /></el-form-item>
|
||||
</el-form>
|
||||
<el-alert v-if="error" :title="error.message" type="error" :closable="false"><ApiErrorMeta :details="error" /></el-alert>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button :disabled="busy" @click="open = false">关闭</el-button>
|
||||
<template v-if="adjusting"><el-button v-if="allowed('ADJUST_RENT')" type="primary" :loading="busy" :disabled="!reason.trim()" @click="submit()">保存调整</el-button></template>
|
||||
<template v-else>
|
||||
<el-button v-if="allowed('REJECT')" type="danger" :disabled="busy || !reason.trim()" @click="submit('REJECT')">驳回</el-button>
|
||||
<el-button v-if="allowed('APPROVE')" type="primary" :loading="busy" @click="submit('APPROVE')">审核通过</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</AppDialog>
|
||||
</template>
|
||||
Reference in New Issue
Block a user