feat 搭建架构骨架
This commit is contained in:
182
src/views/finance/cpns/BillTable.vue
Normal file
182
src/views/finance/cpns/BillTable.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { StatusTag } from '@/components'
|
||||
import type { Bill, BillStatus } from '@/types/business/finance'
|
||||
import { formatMoney } from '@/utils/format'
|
||||
|
||||
interface Props {
|
||||
bills: Bill[]
|
||||
selectedIds: string[]
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
view: [id: string]
|
||||
pay: [id: string]
|
||||
'update:selection': [ids: string[]]
|
||||
}>()
|
||||
|
||||
/** 本地勾选集合(由 selectedIds prop 同步) */
|
||||
const selection = ref<Set<string>>(new Set(props.selectedIds))
|
||||
|
||||
watch(
|
||||
() => props.selectedIds,
|
||||
(ids) => {
|
||||
selection.value = new Set(ids)
|
||||
},
|
||||
)
|
||||
|
||||
function toggle(id: string): void {
|
||||
if (selection.value.has(id)) selection.value.delete(id)
|
||||
else selection.value.add(id)
|
||||
emit('update:selection', [...selection.value])
|
||||
}
|
||||
|
||||
function toggleAll(): void {
|
||||
const allSelected = props.bills.length > 0 && props.bills.every((b) => selection.value.has(b.id))
|
||||
if (allSelected) {
|
||||
for (const bill of props.bills) selection.value.delete(bill.id)
|
||||
}
|
||||
else {
|
||||
for (const bill of props.bills) selection.value.add(bill.id)
|
||||
}
|
||||
emit('update:selection', [...selection.value])
|
||||
}
|
||||
|
||||
const allSelected = () => props.bills.length > 0 && props.bills.every((b) => selection.value.has(b.id))
|
||||
|
||||
const STATUS_VARIANTS: Record<BillStatus, 'warning' | 'success' | 'info'> = {
|
||||
待支付: 'warning',
|
||||
已支付: 'success',
|
||||
未到期: 'info',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bill-table card">
|
||||
<table class="bill-table__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="bill-table__check">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="allSelected()"
|
||||
@change="toggleAll"
|
||||
>
|
||||
</th>
|
||||
<th>序号</th>
|
||||
<th>账单名称</th>
|
||||
<th>账单号</th>
|
||||
<th>交易流水号</th>
|
||||
<th>项目名称</th>
|
||||
<th>订单金额</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(bill, index) in bills" :key="bill.id">
|
||||
<td class="bill-table__check">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="selection.has(bill.id)"
|
||||
@change="toggle(bill.id)"
|
||||
>
|
||||
</td>
|
||||
<td>{{ index + 1 }}</td>
|
||||
<td>{{ bill.planName }}</td>
|
||||
<td>{{ bill.billNo }}</td>
|
||||
<td>{{ bill.tradeNo ?? '—' }}</td>
|
||||
<td>{{ bill.projectName }}</td>
|
||||
<td class="bill-table__amount">¥{{ formatMoney(bill.amount) }}</td>
|
||||
<td>
|
||||
<StatusTag :label="bill.status" :variant="STATUS_VARIANTS[bill.status]" />
|
||||
</td>
|
||||
<td class="bill-table__ops">
|
||||
<button
|
||||
v-if="bill.status === '待支付'"
|
||||
class="bill-table__link"
|
||||
@click="emit('pay', bill.id)"
|
||||
>
|
||||
去支付
|
||||
</button>
|
||||
<button class="bill-table__link" @click="emit('view', bill.id)">
|
||||
详情
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="bills.length === 0">
|
||||
<td colspan="9" class="bill-table__empty text-secondary">
|
||||
暂无账单数据
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.bill-table {
|
||||
padding: @spacing-base;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
overflow-x: auto;
|
||||
|
||||
&__table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: @font-size-base;
|
||||
color: @text-color;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: @spacing-sm @spacing-sm;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
border-bottom: 1px solid @border-color;
|
||||
}
|
||||
|
||||
th {
|
||||
background: @bg-color-light;
|
||||
color: @text-color-secondary;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: @bg-color-light;
|
||||
}
|
||||
}
|
||||
|
||||
&__check {
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__amount {
|
||||
color: @heading-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__ops {
|
||||
.flex(row, flex-start);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
&__link {
|
||||
color: @primary-color;
|
||||
font-size: @font-size-base;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: @primary-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&__empty {
|
||||
text-align: center;
|
||||
padding: @spacing-xl 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user