新增其他线下出款记账
This commit is contained in:
@@ -54,6 +54,8 @@ export interface FinanceDailyItem {
|
||||
offline_settlement_paid_count: number
|
||||
withdrawal_paid_amount_cent: number
|
||||
withdrawal_paid_count: number
|
||||
manual_paid_amount_cent: number
|
||||
manual_paid_count: number
|
||||
disbursement_paid_amount_cent: number
|
||||
disbursement_paid_count: number
|
||||
}
|
||||
@@ -82,6 +84,8 @@ export interface FinanceDisbursementSummary {
|
||||
withdrawal_pending_count: number
|
||||
withdrawal_review_amount_cent: number
|
||||
withdrawal_review_count: number
|
||||
manual_paid_amount_cent: number
|
||||
manual_paid_count: number
|
||||
}
|
||||
|
||||
export interface FinanceDisbursementListSummary {
|
||||
@@ -96,7 +100,7 @@ export interface FinanceDisbursementListSummary {
|
||||
}
|
||||
|
||||
export interface FinanceDisbursementItem {
|
||||
source_type: 'platform_managed' | 'withdrawal'
|
||||
source_type: 'platform_managed' | 'withdrawal' | 'manual_offline'
|
||||
source_id: number
|
||||
business_no: string
|
||||
order_id?: number
|
||||
@@ -113,13 +117,47 @@ export interface FinanceDisbursementItem {
|
||||
amount_cent: number
|
||||
fee_cent: number
|
||||
actual_amount_cent: number
|
||||
status: 'review_pending' | 'payment_pending' | 'paid' | 'rejected' | 'cancelled'
|
||||
status: 'review_pending' | 'payment_pending' | 'paid' | 'rejected' | 'cancelled' | 'voided'
|
||||
raw_status: string
|
||||
business_created_at?: string
|
||||
paid_at?: string
|
||||
operator_id?: number
|
||||
operator_name: string
|
||||
remark: string
|
||||
category: string
|
||||
voucher_url: string
|
||||
voided_at?: string
|
||||
voided_by?: number
|
||||
voided_by_name: string
|
||||
void_reason: string
|
||||
}
|
||||
|
||||
export interface CreateManualDisbursementPayload {
|
||||
category: string
|
||||
payee_name: string
|
||||
amount_cent: number
|
||||
paid_at: string
|
||||
remark: string
|
||||
voucher_url?: string
|
||||
}
|
||||
|
||||
export interface ManualDisbursement {
|
||||
id: number
|
||||
disbursement_no: string
|
||||
category: string
|
||||
payee_name: string
|
||||
amount_cent: number
|
||||
paid_at: string
|
||||
remark: string
|
||||
voucher_url: string
|
||||
status: 'paid' | 'voided'
|
||||
created_by: number
|
||||
created_by_name: string
|
||||
voided_by?: number
|
||||
voided_by_name: string
|
||||
voided_at?: string
|
||||
void_reason: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface FinanceDisbursementQuery extends FinanceDateQuery {
|
||||
@@ -239,6 +277,8 @@ export async function fetchFinanceDashboard(query: FinanceDateQuery = {}) {
|
||||
withdrawal_pending_count: 0,
|
||||
withdrawal_review_amount_cent: 0,
|
||||
withdrawal_review_count: 0,
|
||||
manual_paid_amount_cent: 0,
|
||||
manual_paid_count: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -280,3 +320,19 @@ export async function fetchFinanceDisbursements(query: FinanceDisbursementQuery
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function createManualDisbursement(payload: CreateManualDisbursementPayload) {
|
||||
const { data } = await apiClient.post<ApiResponse<ManualDisbursement>>(
|
||||
'/admin/finance/manual-disbursements',
|
||||
payload
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function voidManualDisbursement(id: number, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<ManualDisbursement>>(
|
||||
`/admin/finance/manual-disbursements/${id}/void`,
|
||||
{ reason }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ function rowOfflinePendingClass(row: FinanceDailyItem) {
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Finance Dashboard</p>
|
||||
<h1>财务仪表盘</h1>
|
||||
<p>按天查看收付款、平台收入、号主结算、平台代管打款和用户提现。</p>
|
||||
<p>按天查看收付款、平台收入、号主结算及全部资金出款。</p>
|
||||
</div>
|
||||
<div class="toolbar-actions">
|
||||
<el-date-picker
|
||||
@@ -157,7 +157,7 @@ function rowOfflinePendingClass(row: FinanceDailyItem) {
|
||||
|
||||
<div v-if="dashboard?.disbursement_summary" class="metric-grid disbursement-grid">
|
||||
<div class="metric-card disbursement-card">
|
||||
<span>代管及提现出款</span>
|
||||
<span>全部实际出款</span>
|
||||
<strong>{{ moneyCent(dashboard.disbursement_summary.paid_amount_cent) }}</strong>
|
||||
<small>{{ dashboard.disbursement_summary.paid_count }} 笔实际出款合计</small>
|
||||
</div>
|
||||
@@ -177,6 +177,11 @@ function rowOfflinePendingClass(row: FinanceDailyItem) {
|
||||
{{ moneyCent(dashboard.disbursement_summary.withdrawal_fee_amount_cent) }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="metric-card disbursement-card">
|
||||
<span>其他线下出款</span>
|
||||
<strong>{{ moneyCent(dashboard.disbursement_summary.manual_paid_amount_cent) }}</strong>
|
||||
<small>{{ dashboard.disbursement_summary.manual_paid_count }} 笔有效记账</small>
|
||||
</div>
|
||||
<div class="metric-card pending-card">
|
||||
<span>当前待出款</span>
|
||||
<strong>{{ moneyCent(dashboard.disbursement_summary.pending_payment_amount_cent) }}</strong>
|
||||
@@ -262,6 +267,11 @@ function rowOfflinePendingClass(row: FinanceDailyItem) {
|
||||
{{ moneyCent(row.withdrawal_paid_amount_cent) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="其他线下" width="130">
|
||||
<template #default="{ row }">
|
||||
{{ moneyCent(row.manual_paid_amount_cent) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待线下" width="130">
|
||||
<template #default="{ row }">
|
||||
<span :class="rowOfflinePendingClass(row)">
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { Search, View } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { CircleClose, Plus, Search, UploadFilled, View } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
|
||||
import {
|
||||
createManualDisbursement,
|
||||
fetchFinanceDisbursements,
|
||||
voidManualDisbursement,
|
||||
type FinanceDisbursementItem,
|
||||
type FinanceDisbursementListSummary,
|
||||
} from '@/features/admin/api/adminFinance'
|
||||
import { fetchAdminWithdrawal, type WithdrawalDetail } from '@/features/admin/api/adminWithdrawal'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
import { uploadAdminFile } from '@/shared/api/files'
|
||||
import { useAdminSessionStore } from '@/stores/adminSession'
|
||||
import { adminPath } from '@/shared/utils/adminPath'
|
||||
import { readError } from '@/shared/utils/error'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCentWithSymbol, yuanToCent } from '@/shared/utils/money'
|
||||
import { formatDateTime, formatInputDate } from '@/shared/utils/time'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
import WithdrawalDetailDialog from '../components/WithdrawalDetailDialog.vue'
|
||||
@@ -26,7 +30,28 @@ const currentPage = ref(1)
|
||||
const currentPageSize = ref(20)
|
||||
const showWithdrawalDetail = ref(false)
|
||||
const selectedWithdrawal = ref<WithdrawalDetail | null>(null)
|
||||
const createVisible = ref(false)
|
||||
const createSaving = ref(false)
|
||||
const voucherUploading = ref(false)
|
||||
const manualActionID = ref(0)
|
||||
const selectedManual = ref<FinanceDisbursementItem | null>(null)
|
||||
const summary = ref<FinanceDisbursementListSummary>(emptySummary())
|
||||
const canManageManual = computed(() => adminSession.hasPermission('finance:manual_disbursement'))
|
||||
const manualCategories = [
|
||||
{ value: 'user_compensation', label: '用户补偿' },
|
||||
{ value: 'seller_supplement', label: '卖家补款' },
|
||||
{ value: 'operating_expense', label: '运营支出' },
|
||||
{ value: 'channel_fee', label: '渠道费用' },
|
||||
{ value: 'other', label: '其他' },
|
||||
]
|
||||
const createForm = reactive({
|
||||
category: '',
|
||||
payee_name: '',
|
||||
amount_yuan: 0,
|
||||
paid_at: new Date(),
|
||||
remark: '',
|
||||
voucher_url: '',
|
||||
})
|
||||
const filters = reactive({
|
||||
date_type: 'created',
|
||||
start_date: defaultStartDate(),
|
||||
@@ -98,6 +123,103 @@ function onWithdrawalSaved() {
|
||||
void loadItems()
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
resetCreateForm()
|
||||
createVisible.value = true
|
||||
}
|
||||
|
||||
function resetCreateForm() {
|
||||
createForm.category = ''
|
||||
createForm.payee_name = ''
|
||||
createForm.amount_yuan = 0
|
||||
createForm.paid_at = new Date()
|
||||
createForm.remark = ''
|
||||
createForm.voucher_url = ''
|
||||
}
|
||||
|
||||
async function uploadVoucher(options: { file: File }) {
|
||||
if (!options.file.type.startsWith('image/')) {
|
||||
ElMessage.warning('付款凭证仅支持图片')
|
||||
return
|
||||
}
|
||||
voucherUploading.value = true
|
||||
try {
|
||||
const uploaded = await uploadAdminFile(options.file, 'manual-disbursement')
|
||||
createForm.voucher_url = uploaded.url
|
||||
ElMessage.success('凭证已上传')
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '凭证上传失败'))
|
||||
} finally {
|
||||
voucherUploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function submitManualDisbursement() {
|
||||
const amountCent = yuanToCent(createForm.amount_yuan)
|
||||
if (
|
||||
!createForm.category ||
|
||||
!createForm.payee_name.trim() ||
|
||||
amountCent <= 0 ||
|
||||
!createForm.paid_at
|
||||
) {
|
||||
ElMessage.warning('请填写完整的出款信息')
|
||||
return
|
||||
}
|
||||
if (!createForm.remark.trim()) {
|
||||
ElMessage.warning('请填写出款用途')
|
||||
return
|
||||
}
|
||||
createSaving.value = true
|
||||
try {
|
||||
await createManualDisbursement({
|
||||
category: createForm.category,
|
||||
payee_name: createForm.payee_name.trim(),
|
||||
amount_cent: amountCent,
|
||||
paid_at: createForm.paid_at.toISOString(),
|
||||
remark: createForm.remark.trim(),
|
||||
voucher_url: createForm.voucher_url || undefined,
|
||||
})
|
||||
createVisible.value = false
|
||||
ElMessage.success('线下出款已记账')
|
||||
await loadItems()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '线下出款记账失败'))
|
||||
} finally {
|
||||
createSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openManualDetail(row: FinanceDisbursementItem) {
|
||||
selectedManual.value = row
|
||||
}
|
||||
|
||||
async function handleVoidManual(row: FinanceDisbursementItem) {
|
||||
if (manualActionID.value) return
|
||||
try {
|
||||
const { value } = await ElMessageBox.prompt(
|
||||
`确认作废出款单 ${row.business_no}?作废后将从财务统计中排除。`,
|
||||
'作废线下出款',
|
||||
{
|
||||
confirmButtonText: '确认作废',
|
||||
cancelButtonText: '取消',
|
||||
inputPlaceholder: '请输入作废原因',
|
||||
inputValidator: value => !!value.trim() || '请输入作废原因',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
manualActionID.value = row.source_id
|
||||
await voidManualDisbursement(row.source_id, value.trim())
|
||||
selectedManual.value = null
|
||||
ElMessage.success('线下出款已作废')
|
||||
await loadItems()
|
||||
} catch (error) {
|
||||
if (error === 'cancel' || error === 'close') return
|
||||
ElMessage.error(readError(error, '作废线下出款失败'))
|
||||
} finally {
|
||||
manualActionID.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
function emptySummary(): FinanceDisbursementListSummary {
|
||||
return {
|
||||
record_count: 0,
|
||||
@@ -122,11 +244,18 @@ function money(value: number) {
|
||||
}
|
||||
|
||||
function sourceLabel(source: string) {
|
||||
return source === 'platform_managed' ? '平台代管' : '用户提现'
|
||||
const labels: Record<string, string> = {
|
||||
platform_managed: '平台代管',
|
||||
withdrawal: '用户提现',
|
||||
manual_offline: '其他线下出款',
|
||||
}
|
||||
return labels[source] || source
|
||||
}
|
||||
|
||||
function sourceType(source: string) {
|
||||
return source === 'platform_managed' ? 'primary' : 'info'
|
||||
if (source === 'platform_managed') return 'primary'
|
||||
if (source === 'manual_offline') return 'warning'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
function statusLabel(status: string) {
|
||||
@@ -136,6 +265,7 @@ function statusLabel(status: string) {
|
||||
paid: '已打款',
|
||||
rejected: '已拒绝',
|
||||
cancelled: '已取消',
|
||||
voided: '已作废',
|
||||
}
|
||||
return labels[status] || status
|
||||
}
|
||||
@@ -144,9 +274,19 @@ function statusType(status: string) {
|
||||
if (status === 'paid') return 'success'
|
||||
if (status === 'review_pending' || status === 'payment_pending') return 'warning'
|
||||
if (status === 'rejected') return 'danger'
|
||||
if (status === 'voided') return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
function itemStatusLabel(row: FinanceDisbursementItem) {
|
||||
if (row.source_type === 'manual_offline' && row.status === 'paid') return '已出款'
|
||||
return statusLabel(row.status)
|
||||
}
|
||||
|
||||
function categoryLabel(category: string) {
|
||||
return manualCategories.find(item => item.value === category)?.label || category || '-'
|
||||
}
|
||||
|
||||
function accountTypeLabel(type: string) {
|
||||
const labels: Record<string, string> = {
|
||||
alipay: '支付宝',
|
||||
@@ -163,9 +303,12 @@ function accountTypeLabel(type: string) {
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Disbursements</p>
|
||||
<h1>资金出款</h1>
|
||||
<p>查询平台代管线下结算与用户提现的应付、待办和实际打款记录。</p>
|
||||
<p>统一查询平台代管、用户提现和其他线下出款记录。</p>
|
||||
</div>
|
||||
<div class="toolbar-actions">
|
||||
<el-button v-if="canManageManual" type="success" :icon="Plus" @click="openCreate">
|
||||
新增线下出款
|
||||
</el-button>
|
||||
<el-button @click="resetFilters">重置</el-button>
|
||||
<el-button type="primary" :icon="Search" :loading="loading" @click="search">
|
||||
查询
|
||||
@@ -233,6 +376,7 @@ function accountTypeLabel(type: string) {
|
||||
>
|
||||
<el-option label="平台代管" value="platform_managed" />
|
||||
<el-option label="用户提现" value="withdrawal" />
|
||||
<el-option label="其他线下出款" value="manual_offline" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出款状态">
|
||||
@@ -242,10 +386,15 @@ function accountTypeLabel(type: string) {
|
||||
<el-option label="已打款" value="paid" />
|
||||
<el-option label="已拒绝" value="rejected" />
|
||||
<el-option label="已取消" value="cancelled" />
|
||||
<el-option label="已作废" value="voided" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业务单号">
|
||||
<el-input v-model="filters.business_no" clearable placeholder="订单号或提现单号" />
|
||||
<el-input
|
||||
v-model="filters.business_no"
|
||||
clearable
|
||||
placeholder="订单号、提现单号或出款单号"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="收款人">
|
||||
<el-input v-model="filters.keyword" clearable placeholder="姓名、手机号或账号" />
|
||||
@@ -279,19 +428,26 @@ function accountTypeLabel(type: string) {
|
||||
<strong>{{ row.payee_name || '-' }}</strong>
|
||||
<small v-if="row.payee_phone">{{ row.payee_phone }}</small>
|
||||
<small v-else-if="row.source_type === 'withdrawal'">用户 ID {{ row.user_id }}</small>
|
||||
<small v-else-if="row.source_type === 'manual_offline'">
|
||||
{{ categoryLabel(row.category) }}
|
||||
</small>
|
||||
<small v-else>联系方式未登记</small>
|
||||
<small v-if="row.uploader_name">上传:{{ row.uploader_name }}</small>
|
||||
<small v-if="row.source_channel">渠道:{{ row.source_channel }}</small>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收款账户" min-width="205">
|
||||
<el-table-column label="出款信息" min-width="205">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.source_type === 'withdrawal'" class="stack-cell">
|
||||
<span>{{ accountTypeLabel(row.account_type) }} · {{ row.account_name || '-' }}</span>
|
||||
<small>{{ row.account_no || '-' }}</small>
|
||||
<small v-if="row.bank_name">{{ row.bank_name }}</small>
|
||||
</div>
|
||||
<div v-else-if="row.source_type === 'manual_offline'" class="stack-cell">
|
||||
<el-tag size="small" effect="plain">{{ categoryLabel(row.category) }}</el-tag>
|
||||
<small>{{ row.voucher_url ? '已上传付款凭证' : '未上传付款凭证' }}</small>
|
||||
</div>
|
||||
<span v-else class="muted-text">线下约定</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -307,7 +463,7 @@ function accountTypeLabel(type: string) {
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="105" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag>
|
||||
<el-tag :type="statusType(row.status)">{{ itemStatusLabel(row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="形成时间" min-width="175">
|
||||
@@ -322,7 +478,7 @@ function accountTypeLabel(type: string) {
|
||||
<el-table-column label="备注" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.remark || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right">
|
||||
<el-table-column label="操作" width="155" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.withdrawal_id && adminSession.hasPermission('withdrawal:detail')"
|
||||
@@ -337,6 +493,21 @@ function accountTypeLabel(type: string) {
|
||||
<RouterLink v-else-if="row.order_id" :to="adminPath(`orders/${row.order_id}`)">
|
||||
<el-button link type="primary" :icon="View">详情</el-button>
|
||||
</RouterLink>
|
||||
<template v-else-if="row.source_type === 'manual_offline'">
|
||||
<el-button link type="primary" :icon="View" @click="openManualDetail(row)">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 'paid' && canManageManual"
|
||||
link
|
||||
type="danger"
|
||||
:icon="CircleClose"
|
||||
:loading="manualActionID === row.source_id"
|
||||
@click="handleVoidManual(row)"
|
||||
>
|
||||
作废
|
||||
</el-button>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -356,6 +527,159 @@ function accountTypeLabel(type: string) {
|
||||
:withdrawal="selectedWithdrawal"
|
||||
@saved="onWithdrawalSaved"
|
||||
/>
|
||||
|
||||
<el-dialog
|
||||
v-model="createVisible"
|
||||
title="新增其他线下出款"
|
||||
width="560px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form class="manual-form" label-position="top" @submit.prevent="submitManualDisbursement">
|
||||
<el-form-item label="出款分类" required>
|
||||
<el-select v-model="createForm.category" class="full-control" placeholder="请选择分类">
|
||||
<el-option
|
||||
v-for="item in manualCategories"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收款人" required>
|
||||
<el-input v-model="createForm.payee_name" maxlength="100" placeholder="姓名或单位名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="出款金额" required>
|
||||
<el-input-number
|
||||
v-model="createForm.amount_yuan"
|
||||
class="full-control"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
:step="100"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="出款时间" required>
|
||||
<el-date-picker
|
||||
v-model="createForm.paid_at"
|
||||
class="full-control"
|
||||
type="datetime"
|
||||
placeholder="选择出款时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="manual-form-wide" label="备注" required>
|
||||
<el-input
|
||||
v-model="createForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="填写出款用途"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="manual-form-wide" label="付款凭证(选填)">
|
||||
<div v-if="createForm.voucher_url" class="voucher-preview">
|
||||
<AuthImage
|
||||
:source="createForm.voucher_url"
|
||||
:admin="true"
|
||||
fit="cover"
|
||||
:preview-src-list="[createForm.voucher_url]"
|
||||
:image-style="{ width: '104px', height: '104px', borderRadius: '6px' }"
|
||||
/>
|
||||
<el-button
|
||||
class="voucher-remove"
|
||||
circle
|
||||
plain
|
||||
type="danger"
|
||||
:icon="CircleClose"
|
||||
title="移除凭证"
|
||||
@click="createForm.voucher_url = ''"
|
||||
/>
|
||||
</div>
|
||||
<el-upload
|
||||
v-else
|
||||
:show-file-list="false"
|
||||
:http-request="uploadVoucher"
|
||||
accept="image/jpeg,image/png,image/webp"
|
||||
>
|
||||
<el-button :icon="UploadFilled" :loading="voucherUploading">上传凭证</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button :disabled="createSaving" @click="createVisible = false">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="createSaving"
|
||||
:disabled="voucherUploading"
|
||||
@click="submitManualDisbursement"
|
||||
>
|
||||
确认记账
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:model-value="!!selectedManual"
|
||||
title="其他线下出款详情"
|
||||
width="620px"
|
||||
@update:model-value="selectedManual = null"
|
||||
>
|
||||
<el-descriptions v-if="selectedManual" :column="2" border>
|
||||
<el-descriptions-item label="出款单号">{{
|
||||
selectedManual.business_no
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="statusType(selectedManual.status)">
|
||||
{{ itemStatusLabel(selectedManual) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="出款分类">
|
||||
{{ categoryLabel(selectedManual.category) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="收款人">{{ selectedManual.payee_name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出款金额">
|
||||
<strong>{{ money(selectedManual.actual_amount_cent) }}</strong>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="出款时间">
|
||||
{{ formatDateTime(selectedManual.paid_at) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="录入人">
|
||||
{{ selectedManual.operator_name || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="录入时间">
|
||||
{{ formatDateTime(selectedManual.business_created_at) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">
|
||||
{{ selectedManual.remark || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedManual.voucher_url" label="付款凭证" :span="2">
|
||||
<AuthImage
|
||||
:source="selectedManual.voucher_url"
|
||||
:admin="true"
|
||||
fit="cover"
|
||||
:preview-src-list="[selectedManual.voucher_url]"
|
||||
:image-style="{ width: '140px', height: '140px', borderRadius: '6px' }"
|
||||
/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedManual.status === 'voided'" label="作废信息" :span="2">
|
||||
{{ selectedManual.voided_by_name || '-' }} ·
|
||||
{{ formatDateTime(selectedManual.voided_at) }} ·
|
||||
{{ selectedManual.void_reason || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template #footer>
|
||||
<el-button @click="selectedManual = null">关闭</el-button>
|
||||
<el-button
|
||||
v-if="selectedManual?.status === 'paid' && canManageManual"
|
||||
type="danger"
|
||||
:icon="CircleClose"
|
||||
:loading="manualActionID === selectedManual.source_id"
|
||||
@click="handleVoidManual(selectedManual)"
|
||||
>
|
||||
作废记录
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -432,6 +756,28 @@ function accountTypeLabel(type: string) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.manual-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0 16px;
|
||||
}
|
||||
|
||||
.manual-form-wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.voucher-preview {
|
||||
position: relative;
|
||||
width: 104px;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
.voucher-remove {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
}
|
||||
|
||||
@media (max-width: 1440px) {
|
||||
.disbursement-metrics {
|
||||
grid-template-columns: repeat(3, minmax(170px, 1fr));
|
||||
@@ -444,8 +790,13 @@ function accountTypeLabel(type: string) {
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.disbursement-metrics,
|
||||
.disbursement-filters {
|
||||
.disbursement-filters,
|
||||
.manual-form {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.manual-form-wide {
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user