| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- import 'package:flutter/material.dart';
- import 'package:tdesign_flutter/tdesign_flutter.dart';
- import '../../core/theme/app_colors.dart';
- /// Skeleton 占位卡片,匹配 [ListCard] 布局:
- /// ┌────────────────────────┐
- /// │ cardNo amount │ ← Row: 单号(14/600) + 金额(16/700)
- /// │ │
- /// │ description │ ← 描述(14)
- /// │ │
- /// │ date statusTag │ ← Row: 日期(12) + 状态标签
- /// └────────────────────────┘
- class SkeletonListCard extends StatelessWidget {
- const SkeletonListCard({super.key});
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: AppColors.bgCard,
- borderRadius: BorderRadius.circular(8),
- ),
- child: TDSkeleton.fromRowCol(
- animation: TDSkeletonAnimation.flashed,
- rowCol: TDSkeletonRowCol(
- objects: const [
- // R1: cardNo + spacer + amount
- [
- TDSkeletonRowColObj.text(width: 120, height: 14),
- TDSkeletonRowColObj.spacer(),
- TDSkeletonRowColObj.text(width: 80, height: 16),
- ],
- // R2: description
- [
- TDSkeletonRowColObj.text(height: 14),
- ],
- // R3: date + spacer + statusTag
- [
- TDSkeletonRowColObj.text(width: 100, height: 12),
- TDSkeletonRowColObj.spacer(),
- TDSkeletonRowColObj.rect(width: 48, height: 20),
- ],
- ],
- style: TDSkeletonRowColStyle(
- rowSpacing: (_) => 8,
- ),
- ),
- ),
- );
- }
- }
- /// Skeleton 占位卡片,匹配车辆列表卡片布局:
- /// ┌────────────────────────┐
- /// │ 车牌号 状态徽章 │ ← Row: 车牌(16/700) + 徽章(12)
- /// │ │
- /// │ 申请单号 用途标签 │ ← Row: 单号(12) + 标签(10)
- /// │ │
- /// │ 路线 ... 时间 │ ← Row: 路线(13/ellipsis) + 时间(12)
- /// └────────────────────────┘
- class SkeletonVehicleCard extends StatelessWidget {
- const SkeletonVehicleCard({super.key});
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: AppColors.bgCard,
- borderRadius: BorderRadius.circular(8),
- ),
- child: TDSkeleton.fromRowCol(
- animation: TDSkeletonAnimation.flashed,
- rowCol: TDSkeletonRowCol(
- objects: const [
- // R1: licensePlate + spacer + status badge
- [
- TDSkeletonRowColObj.text(width: 100, height: 16),
- TDSkeletonRowColObj.spacer(),
- TDSkeletonRowColObj.rect(width: 48, height: 20),
- ],
- // R2: applicationNo + spacer + purpose tag
- [
- TDSkeletonRowColObj.text(width: 140, height: 12),
- TDSkeletonRowColObj.spacer(),
- TDSkeletonRowColObj.rect(width: 40, height: 16),
- ],
- // R3: route (flex) + spacer + date
- [
- TDSkeletonRowColObj.text(flex: 2, height: 13),
- TDSkeletonRowColObj.spacer(flex: 1),
- TDSkeletonRowColObj.text(width: 120, height: 12),
- ],
- ],
- style: TDSkeletonRowColStyle(
- rowSpacing: (_) => 6,
- ),
- ),
- ),
- );
- }
- }
- /// 外勤日志 Skeleton 占位卡片
- ///
- /// 匹配外勤日志卡片布局:visitNo → customerName+状态 → address → summary+date
- class SkeletonOutingLogCard extends StatelessWidget {
- const SkeletonOutingLogCard({super.key});
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: AppColors.bgCard,
- borderRadius: BorderRadius.circular(8),
- ),
- child: TDSkeleton.fromRowCol(
- animation: TDSkeletonAnimation.flashed,
- rowCol: TDSkeletonRowCol(
- objects: const [
- // R1: visitNo
- [TDSkeletonRowColObj.text(width: 100, height: 11)],
- // R2: customerName + spacer + statusTag
- [
- TDSkeletonRowColObj.text(flex: 3, height: 15),
- TDSkeletonRowColObj.spacer(flex: 1),
- TDSkeletonRowColObj.rect(width: 48, height: 20),
- ],
- // R3: checkInAddress
- [TDSkeletonRowColObj.text(height: 12)],
- // R4: summary + spacer + date
- [
- TDSkeletonRowColObj.text(flex: 2, height: 12),
- TDSkeletonRowColObj.spacer(flex: 1),
- TDSkeletonRowColObj.text(width: 80, height: 11),
- ],
- ],
- style: TDSkeletonRowColStyle(rowSpacing: (_) => 4),
- ),
- ),
- );
- }
- }
- /// 公告 Skeleton 占位卡片
- ///
- /// 匹配公告卡片布局:title 行 + typeTag/publisher/date 行
- class SkeletonAnnouncementCard extends StatelessWidget {
- const SkeletonAnnouncementCard({super.key});
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: AppColors.bgCard,
- borderRadius: BorderRadius.circular(8),
- ),
- child: TDSkeleton.fromRowCol(
- animation: TDSkeletonAnimation.flashed,
- rowCol: TDSkeletonRowCol(
- objects: const [
- // R1: title (full width)
- [TDSkeletonRowColObj.text(height: 15)],
- // R2: typeTag + spacer + date
- [
- TDSkeletonRowColObj.rect(width: 56, height: 20),
- TDSkeletonRowColObj.spacer(width: 8),
- TDSkeletonRowColObj.text(width: 60, height: 12),
- TDSkeletonRowColObj.spacer(),
- TDSkeletonRowColObj.text(width: 120, height: 12),
- ],
- ],
- style: TDSkeletonRowColStyle(rowSpacing: (_) => 8),
- ),
- ),
- );
- }
- }
- /// 列表加载态:骨架卡片占位
- ///
- /// [cardCount] 骨架卡片数量,默认 5
- /// [cardBuilder] 骨架卡片构建器,默认 [SkeletonListCard]
- class SkeletonLoadingList extends StatelessWidget {
- final int cardCount;
- final Widget Function() cardBuilder;
- const SkeletonLoadingList({
- super.key,
- this.cardCount = 5,
- this.cardBuilder = _defaultBuilder,
- });
- static Widget _defaultBuilder() => const SkeletonListCard();
- @override
- Widget build(BuildContext context) {
- return ListView(
- padding: const EdgeInsets.fromLTRB(16, 16, 16, 24),
- physics: const NeverScrollableScrollPhysics(),
- children: List.generate(
- cardCount,
- (_) => Padding(
- padding: const EdgeInsets.only(bottom: 16),
- child: cardBuilder(),
- ),
- ),
- );
- }
- }
|