feat 搭建架构骨架

This commit is contained in:
Ironsp
2026-09-24 09:09:47 +08:00
parent dd9f6b77a4
commit 7a2efa3fea
180 changed files with 18967 additions and 9 deletions

View 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>