This commit is contained in:
2026-08-11 18:43:56 +08:00
parent 6456278ec8
commit 6622815d6c
37 changed files with 739 additions and 205 deletions
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { Eye } from '@lucide/vue'
import { Eye, FileCheck2, Link2 } from '@lucide/vue'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
@@ -43,6 +43,9 @@ const page = ref(1)
const pageSize = ref(20)
const canView = computed(() => access.can('platform:finance:bill:view'))
const canViewSource = computed(() => access.can('platform:finance:fee-source:view'))
const canReviewSource = computed(() => access.can('platform:finance:fee-source:review'))
const canSettleSource = computed(() => access.can('platform:finance:fee-source:settlement'))
const stateError = computed(() => customersError.value || loadError.value)
const queryFields = computed<QueryField[]>(() => [
{ key: 'customerId', type: 'select', label: '客户', width: 260, placeholder: '请选择客户', props: { 'aria-label': '客户', filterable: true, loading: customersLoading.value }, options: customers.value.map((item) => ({ label: item.tenantName, value: String(item.id), disabled: item.status !== 'ACTIVE' })) },
@@ -93,18 +96,20 @@ onMounted(() => void loadCustomers())
<template #toolbar><QueryToolbar v-model="filters" class="surface-panel" ariaLabel="客户应收应付筛选" :fields="queryFields" preference-key="finance-customer-arap-query" @search="load" /></template>
<template v-if="stateError" #state><LoadErrorState title="客户应收应付加载失败" :message="stateError.message" :loading="customersLoading || loading" @retry="customersError ? loadCustomers() : load()"><template #details><ApiErrorMeta :details="stateError" /></template></LoadErrorState></template>
<section v-if="!customersError && !loadError" class="surface-panel table-panel"><DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="filteredRows.length" preference-key="finance-customer-arap-table" aria-label="客户应收应付列表" row-key="id" empty-text="请选择客户查询应收应付">
<template #actions="{ row }"><el-button link type="primary" @click="openDetail(row)"><Eye :size="15" />查看</el-button></template>
<template #actions="{ row }"><div class="row-actions"><el-button link type="primary" :disabled="!canViewSource" :title="canViewSource ? '费用来源详情接口尚未提供' : '无费用来源查看权限'" @click="openDetail(row)"><Eye :size="15" />摘要</el-button><el-button v-if="canReviewSource" link type="primary" disabled title="审核接口尚未提供,暂不可操作"><FileCheck2 :size="15" />审核</el-button><el-button v-if="canSettleSource" link type="primary" disabled title="参与结算接口尚未提供,暂不可操作"><Link2 :size="15" />结算</el-button></div></template>
<template #direction="{ row }"><el-tag :type="row.direction === 'RECEIVABLE' ? 'success' : 'warning'">{{ row.direction === 'RECEIVABLE' ? '应收' : '应付' }}</el-tag></template>
<template #status="{ row }"><el-tag :type="row.status === 'PAID' ? 'success' : row.status === 'VOIDED' ? 'info' : 'warning'">{{ statusLabel(row.status) }}</el-tag></template>
<template #pagination-left>费用来源来自真实账单明细、入库费用快照和成本台账 · CNY</template>
</DataTable></section>
</ListPageLayout>
<AppDrawer v-model="drawerOpen" title="应收应付详情" size="min(680px, 94vw)"><el-descriptions v-if="selected" :column="2" border class="arap-detail"><el-descriptions-item label="收付方向">{{ selected.direction === 'RECEIVABLE' ? '应收' : '应付' }}</el-descriptions-item><el-descriptions-item label="状态">{{ statusLabel(selected.status) }}</el-descriptions-item><el-descriptions-item label="客户">{{ selected.customerName }}</el-descriptions-item><el-descriptions-item label="费用单据">{{ selected.documentNo }}</el-descriptions-item><el-descriptions-item label="来源类型">{{ selected.sourceType }}</el-descriptions-item><el-descriptions-item label="来源追溯">{{ selected.sourceId }}</el-descriptions-item><el-descriptions-item label="费用项目">{{ selected.feeName }}</el-descriptions-item><el-descriptions-item label="金额">{{ selected.amount }} CNY</el-descriptions-item><el-descriptions-item label="发生日期">{{ selected.occurredAt }}</el-descriptions-item></el-descriptions><template #footer><el-button @click="drawerOpen = false">关闭</el-button></template></AppDrawer>
<AppDrawer v-model="drawerOpen" title="费用来源摘要" size="min(680px, 94vw)"><el-descriptions v-if="selected" :column="2" border class="arap-detail"><el-descriptions-item label="收付方向">{{ selected.direction === 'RECEIVABLE' ? '应收' : '应付' }}</el-descriptions-item><el-descriptions-item label="状态">{{ statusLabel(selected.status) }}</el-descriptions-item><el-descriptions-item label="客户">{{ selected.customerName }}</el-descriptions-item><el-descriptions-item label="费用单据">{{ selected.documentNo }}</el-descriptions-item><el-descriptions-item label="来源类型">{{ selected.sourceType }}</el-descriptions-item><el-descriptions-item label="来源追溯">{{ selected.sourceId }}</el-descriptions-item><el-descriptions-item label="费用项目">{{ selected.feeName }}</el-descriptions-item><el-descriptions-item label="金额">{{ selected.amount }} CNY</el-descriptions-item><el-descriptions-item label="发生日期">{{ selected.occurredAt }}</el-descriptions-item></el-descriptions><el-alert type="info" :closable="false" title="费用来源详情、审核和参与结算接口尚未提供,当前仅展示列表摘要。" /><template #footer><el-button @click="drawerOpen = false">关闭</el-button></template></AppDrawer>
</AdminPage>
</template>
<style scoped>
.finance-arap-page { min-width: 0; }
.row-actions { display: flex; align-items: center; gap: 4px; white-space: nowrap; }
.row-actions .el-button { margin-left: 0; }
.arap-detail { margin-bottom: 16px; }
@media (max-width: 720px) { :deep(.el-drawer__footer .el-button) { min-height: 44px; } :deep(.arap-detail .el-descriptions__body .el-descriptions__table) { table-layout: fixed; } }
@media (max-width: 480px) { :deep(.arap-detail .el-descriptions__cell) { display: block; width: 100%; } }