feat: iterate approval center cards and billing detail form.
Add lease billing and return settlement cards, insurance and billing detail pages, and card footer variants.
This commit is contained in:
@@ -21,7 +21,7 @@ function statusClassName(status: ApprovalCardItem['status']): string {
|
|||||||
|
|
||||||
export function ApprovalCard({ item, selected = false, onClick }: ApprovalCardProps) {
|
export function ApprovalCard({ item, selected = false, onClick }: ApprovalCardProps) {
|
||||||
const typeColor = getApprovalTypeColor(item.type);
|
const typeColor = getApprovalTypeColor(item.type);
|
||||||
const statusLabel = formatStatusLabel(item);
|
const statusLabel = item.statusLabel ?? formatStatusLabel(item);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
@@ -75,11 +75,23 @@ export function ApprovalCard({ item, selected = false, onClick }: ApprovalCardPr
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
{item.extraTags && item.extraTags.length > 0 ? (
|
||||||
|
<div className="ap-card__extra-tags">
|
||||||
|
{item.extraTags.map((tag) => (
|
||||||
|
<span key={`${item.id}-${tag}`} className="ap-card__extra-tag">
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ap-card__footer">
|
<div className="ap-card__footer">
|
||||||
<div className="ap-card__footer-meta">
|
<div className="ap-card__footer-meta">
|
||||||
{item.showInitiatorInFooter ? (
|
{item.initiatorSuffixInFooter ? (
|
||||||
|
<span className="ap-card__footer-text">{item.initiatedBy}发起</span>
|
||||||
|
) : item.showInitiatorInFooter ? (
|
||||||
<span className="ap-card__footer-text">发起人 {item.initiatedBy}</span>
|
<span className="ap-card__footer-text">发起人 {item.initiatedBy}</span>
|
||||||
) : null}
|
) : null}
|
||||||
<span className="ap-card__footer-text">
|
<span className="ap-card__footer-text">
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
getApprovalTypeLabel,
|
getApprovalTypeLabel,
|
||||||
} from '../config/approvalTypeConfig';
|
} from '../config/approvalTypeConfig';
|
||||||
import { InsuranceComparisonDetail } from './InsuranceComparisonDetail';
|
import { InsuranceComparisonDetail } from './InsuranceComparisonDetail';
|
||||||
|
import { LeaseBillingDetail } from './LeaseBillingDetail';
|
||||||
|
|
||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
@@ -56,6 +57,10 @@ export function ApprovalDetailPlaceholder({ item, onRefresh }: ApprovalDetailPla
|
|||||||
return <InsuranceComparisonDetail item={item} onRefresh={onRefresh} />;
|
return <InsuranceComparisonDetail item={item} onRefresh={onRefresh} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.type === 'billing') {
|
||||||
|
return <LeaseBillingDetail item={item} onRefresh={onRefresh} />;
|
||||||
|
}
|
||||||
|
|
||||||
const statusLabel = formatStatusLabel(item);
|
const statusLabel = formatStatusLabel(item);
|
||||||
const typeLabel = getApprovalTypeLabel(item.type);
|
const typeLabel = getApprovalTypeLabel(item.type);
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ function buildSummaryRows(item: ApprovalCardItem, comparisonNo: string) {
|
|||||||
{ label: '当前审批人', value: item.currentApprover ?? '-' },
|
{ label: '当前审批人', value: item.currentApprover ?? '-' },
|
||||||
{ label: '保险公司数量', value: companyCount },
|
{ label: '保险公司数量', value: companyCount },
|
||||||
{ label: '采购险种', value: insuranceType },
|
{ label: '采购险种', value: insuranceType },
|
||||||
{ label: '中选保险公司', value: item.subtitle?.replace(/^中选:/, '') ?? '-' },
|
{ label: '中选保险公司', value: item.subtitle ?? '-' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ function buildVehicleRows(item: ApprovalCardItem): VehicleRow[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildQuoteRows(item: ApprovalCardItem): QuoteRow[] {
|
function buildQuoteRows(item: ApprovalCardItem): QuoteRow[] {
|
||||||
const winner = item.subtitle?.replace(/^中选:/, '') ?? '国元农业保险上海分公司';
|
const winner = item.subtitle ?? '国元农业保险上海分公司';
|
||||||
const finalAmount = getFact(item, '最终报价').replace('¥', '');
|
const finalAmount = getFact(item, '最终报价').replace('¥', '');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|||||||
290
src/common/oneos-web-approval/components/LeaseBillingDetail.tsx
Normal file
290
src/common/oneos-web-approval/components/LeaseBillingDetail.tsx
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Empty,
|
||||||
|
Space,
|
||||||
|
Table,
|
||||||
|
Tabs,
|
||||||
|
Tag,
|
||||||
|
Timeline,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import type { ColumnsType } from 'antd/es/table';
|
||||||
|
import {
|
||||||
|
CheckCircleOutlined,
|
||||||
|
ClockCircleOutlined,
|
||||||
|
CopyOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import type { ApprovalCardItem } from '../types';
|
||||||
|
import { formatStatusLabel, getApprovalTypeLabel } from '../config/approvalTypeConfig';
|
||||||
|
|
||||||
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
|
export interface LeaseBillingDetailProps {
|
||||||
|
item: ApprovalCardItem;
|
||||||
|
onRefresh?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFact(item: ApprovalCardItem, label: string): string {
|
||||||
|
return item.keyFacts?.find((fact) => fact.label === label)?.value ?? '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseBillingCycle(text: string) {
|
||||||
|
const normalized = text.replace('·', ' ').trim();
|
||||||
|
const periodMatch = normalized.match(/第\d+期/);
|
||||||
|
const period = periodMatch?.[0] ?? '-';
|
||||||
|
const fullDateMatch = normalized.match(/(\d{4}-\d{2}-\d{2})至(\d{4}-\d{2}-\d{2})/);
|
||||||
|
if (fullDateMatch) {
|
||||||
|
return { period, startDate: fullDateMatch[1], endDate: fullDateMatch[2] };
|
||||||
|
}
|
||||||
|
const rangeMatch = normalized.match(/(\d{2}-\d{2})至(\d{2}-\d{2})/);
|
||||||
|
const startDate = rangeMatch ? `2026-${rangeMatch[1]}` : '-';
|
||||||
|
const endDate = rangeMatch ? `2026-${rangeMatch[2]}` : '-';
|
||||||
|
return { period, startDate, endDate };
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAmount(value: string): string {
|
||||||
|
return value.replace(/[¥,]/g, '').trim() || '0.00';
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBillNo(item: ApprovalCardItem): string {
|
||||||
|
const seq = item.id.replace(/\D/g, '').padStart(16, '0');
|
||||||
|
return `207${seq}994`;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BillDetailRow {
|
||||||
|
key: string;
|
||||||
|
index: number;
|
||||||
|
brand: string;
|
||||||
|
model: string;
|
||||||
|
plateNo: string;
|
||||||
|
rentReceivable: string;
|
||||||
|
rentReceived: string;
|
||||||
|
rentRemark: string;
|
||||||
|
waivedAmount: string;
|
||||||
|
depositReceivable: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBillDetailRows(item: ApprovalCardItem): BillDetailRow[] {
|
||||||
|
const vehicleCount = Number(getFact(item, '计费车辆数量').match(/(\d+)/)?.[1] ?? 2);
|
||||||
|
const amount = parseAmount(getFact(item, '应收款总额'));
|
||||||
|
const receivedAmount = parseAmount(getFact(item, '实收款总额'));
|
||||||
|
const perVehicleReceivable = (Number(amount) / vehicleCount).toFixed(2);
|
||||||
|
const perVehicleReceived = (Number(receivedAmount) / vehicleCount).toFixed(2);
|
||||||
|
|
||||||
|
return Array.from({ length: vehicleCount }, (_, index) => ({
|
||||||
|
key: String(index + 1),
|
||||||
|
index: index + 1,
|
||||||
|
brand: '帕力安',
|
||||||
|
model: '4.5T 厢式货车',
|
||||||
|
plateNo: index === 0 ? '粤AGR9901' : '粤AGR9902',
|
||||||
|
rentReceivable: perVehicleReceivable,
|
||||||
|
rentReceived: perVehicleReceived,
|
||||||
|
rentRemark: '-',
|
||||||
|
waivedAmount: '0.00',
|
||||||
|
depositReceivable: '0.00',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LeaseBillingDetail({ item, onRefresh }: LeaseBillingDetailProps) {
|
||||||
|
const [activeTab, setActiveTab] = useState('detail');
|
||||||
|
const billNo = buildBillNo(item);
|
||||||
|
const typeLabel = getApprovalTypeLabel(item.type);
|
||||||
|
const statusLabel = item.statusLabel ?? formatStatusLabel(item);
|
||||||
|
const cycle = parseBillingCycle(item.subtitle ?? '');
|
||||||
|
const receivableTotal = parseAmount(getFact(item, '应收款总额'));
|
||||||
|
const receivedTotal = parseAmount(getFact(item, '实收款总额'));
|
||||||
|
const invoicedTotal = parseAmount(getFact(item, '开票总额'));
|
||||||
|
const pendingInvoice = Math.max(Number(receivedTotal) - Number(invoicedTotal), 0).toFixed(2);
|
||||||
|
const billDetailRows = buildBillDetailRows(item);
|
||||||
|
|
||||||
|
const billInfoRows = [
|
||||||
|
{ label: '合同编码', value: 'AUTO_REG_20260703105722' },
|
||||||
|
{ label: '合同类型', value: '租赁合同' },
|
||||||
|
{ label: '项目名称', value: item.projectName ?? '-' },
|
||||||
|
{ label: '客户名称', value: item.title },
|
||||||
|
{ label: '交车任务编码', value: '-' },
|
||||||
|
{ label: '账单编码', value: `RS-ZD-${item.id.replace('ac-', '')}-${billNo.slice(-10)}` },
|
||||||
|
{ label: '账单期数', value: cycle.period },
|
||||||
|
{ label: '账单开始日期', value: cycle.startDate },
|
||||||
|
{ label: '账单结束日期', value: cycle.endDate },
|
||||||
|
];
|
||||||
|
|
||||||
|
const detailColumns: ColumnsType<BillDetailRow> = [
|
||||||
|
{ title: '序号', dataIndex: 'index', width: 56, fixed: 'left' },
|
||||||
|
{ title: '品牌', dataIndex: 'brand', width: 80 },
|
||||||
|
{ title: '型号', dataIndex: 'model', width: 120 },
|
||||||
|
{ title: '车牌号', dataIndex: 'plateNo', width: 100 },
|
||||||
|
{ title: '应收车辆月租金', dataIndex: 'rentReceivable', width: 120 },
|
||||||
|
{ title: '实收车辆月租金', dataIndex: 'rentReceived', width: 120 },
|
||||||
|
{ title: '车辆租金备注', dataIndex: 'rentRemark', width: 110 },
|
||||||
|
{ title: '减免金额', dataIndex: 'waivedAmount', width: 90 },
|
||||||
|
{ title: '应收车辆保证金', dataIndex: 'depositReceivable', width: 120 },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ap-detail ap-detail--billing">
|
||||||
|
<div className="ap-detail__toolbar">
|
||||||
|
<Space size={8}>
|
||||||
|
<Text type="secondary">编号:</Text>
|
||||||
|
<Text copyable={{ icon: <CopyOutlined />, text: billNo }}>{billNo}</Text>
|
||||||
|
</Space>
|
||||||
|
<Button type="text" icon={<ReloadOutlined />} onClick={onRefresh}>
|
||||||
|
刷新
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ap-detail__header">
|
||||||
|
<div className="ap-detail__header-main">
|
||||||
|
<Title level={4} className="ap-detail__title">
|
||||||
|
{typeLabel}审批
|
||||||
|
</Title>
|
||||||
|
<span className="ap-detail__badge ap-detail__badge--pending">{statusLabel}</span>
|
||||||
|
</div>
|
||||||
|
<div className="ap-detail__meta">
|
||||||
|
<Space size={16} wrap>
|
||||||
|
<Space size={6}>
|
||||||
|
<Avatar size={24} icon={<UserOutlined />} />
|
||||||
|
<Text>{item.initiatedBy}</Text>
|
||||||
|
</Space>
|
||||||
|
<Space size={6}>
|
||||||
|
<Text type="secondary">流程分类</Text>
|
||||||
|
<Text>{typeLabel}</Text>
|
||||||
|
</Space>
|
||||||
|
<Space size={6}>
|
||||||
|
<ClockCircleOutlined style={{ color: '#8c8c8c' }} />
|
||||||
|
<Text type="secondary">提交时间</Text>
|
||||||
|
<Text>{item.initiatedAt}</Text>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeTab}
|
||||||
|
onChange={setActiveTab}
|
||||||
|
className="ap-detail__tabs"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: 'detail',
|
||||||
|
label: '审批详情',
|
||||||
|
children: (
|
||||||
|
<div className="ap-detail__content">
|
||||||
|
<Text strong className="ap-detail__section-title">
|
||||||
|
账单信息
|
||||||
|
</Text>
|
||||||
|
<table className="ap-insurance-summary ap-billing-summary">
|
||||||
|
<tbody>
|
||||||
|
{Array.from({ length: Math.ceil(billInfoRows.length / 3) }).map((_, rowIndex) => {
|
||||||
|
const cells = billInfoRows.slice(rowIndex * 3, rowIndex * 3 + 3);
|
||||||
|
return (
|
||||||
|
<tr key={rowIndex}>
|
||||||
|
{cells.map((cell) => (
|
||||||
|
<React.Fragment key={cell.label}>
|
||||||
|
<th>{cell.label}</th>
|
||||||
|
<td>{cell.value}</td>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
{cells.length < 3
|
||||||
|
? Array.from({ length: 3 - cells.length }).map((__, fillIndex) => (
|
||||||
|
<React.Fragment key={`fill-${fillIndex}`}>
|
||||||
|
<th />
|
||||||
|
<td />
|
||||||
|
</React.Fragment>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div className="ap-billing-detail-section">
|
||||||
|
<Text strong className="ap-detail__section-title">
|
||||||
|
账单明细
|
||||||
|
</Text>
|
||||||
|
<div className="ap-billing-totals">
|
||||||
|
<span>
|
||||||
|
应收款总额 <Text className="ap-billing-totals__value">{receivableTotal} 元</Text>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
实收款总额 <Text className="ap-billing-totals__value">{receivedTotal} 元</Text>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
开票总额 <Text className="ap-billing-totals__value">{invoicedTotal} 元</Text>
|
||||||
|
</span>
|
||||||
|
<span className="ap-billing-totals__meta">
|
||||||
|
待开票 {pendingInvoice} 元
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
className="ap-insurance-table ap-billing-table"
|
||||||
|
columns={detailColumns}
|
||||||
|
dataSource={billDetailRows}
|
||||||
|
pagination={false}
|
||||||
|
size="small"
|
||||||
|
scroll={{ x: 1100 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ap-billing-timeline-section">
|
||||||
|
<Text strong className="ap-detail__section-title">
|
||||||
|
审批记录
|
||||||
|
</Text>
|
||||||
|
<Timeline
|
||||||
|
className="ap-detail__timeline"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
color: 'gray',
|
||||||
|
children: (
|
||||||
|
<div className="ap-billing-timeline-item">
|
||||||
|
<div className="ap-billing-timeline-head">
|
||||||
|
<Text strong>财务经理审批</Text>
|
||||||
|
<Tag>待审批</Tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: 'green',
|
||||||
|
dot: <CheckCircleOutlined style={{ fontSize: 14 }} />,
|
||||||
|
children: (
|
||||||
|
<div className="ap-billing-timeline-item">
|
||||||
|
<div className="ap-billing-timeline-head">
|
||||||
|
<Text strong>发起审批</Text>
|
||||||
|
<Tag color="success">通过</Tag>
|
||||||
|
</div>
|
||||||
|
<Text type="secondary">{item.initiatedBy}</Text>
|
||||||
|
<Text type="secondary" className="ap-detail__timeline-time">
|
||||||
|
{item.initiatedAt}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'flow',
|
||||||
|
label: '审批流程图',
|
||||||
|
children: (
|
||||||
|
<div className="ap-detail__flow-placeholder">
|
||||||
|
<Empty description="流程图占位,后续接入 BPM 流程引擎" />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="ap-detail__actions">
|
||||||
|
<Button>评论</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -27,18 +27,55 @@ export const MOCK_APPROVAL_CASES: ApprovalCardItem[] = [
|
|||||||
status: 'processing',
|
status: 'processing',
|
||||||
listTab: 'initiated',
|
listTab: 'initiated',
|
||||||
title: '沪A51676F',
|
title: '沪A51676F',
|
||||||
subtitle: '中选:国元农业保险上海分公司',
|
subtitle: '国元农业保险上海分公司',
|
||||||
keyFacts: [
|
keyFacts: [
|
||||||
{ label: '采购险种', value: '商业险' },
|
{ label: '采购险种', value: '商业险' },
|
||||||
{ label: '最终报价', value: '¥1000.00' },
|
{ label: '最终报价', value: '¥1000.00' },
|
||||||
{ label: '保险公司数量', value: '3家' },
|
{ label: '保险公司数量', value: '3家' },
|
||||||
{ label: '最晚付费日', value: '2026-08-09' },
|
{ label: '最晚付费日', value: '2026-08-09' },
|
||||||
],
|
],
|
||||||
currentApprover: '财务部-赵总',
|
currentApprover: '赵总',
|
||||||
showInitiatorInFooter: true,
|
showInitiatorInFooter: true,
|
||||||
initiatedBy: CURRENT_USER,
|
initiatedBy: CURRENT_USER,
|
||||||
initiatedAt: '2026-06-10 14:00',
|
initiatedAt: '2026-06-10 14:00',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'ac-24',
|
||||||
|
type: 'return_settlement',
|
||||||
|
status: 'processing',
|
||||||
|
listTab: 'initiated',
|
||||||
|
title: '粤AGR8536',
|
||||||
|
subtitle: '环迪新能源(广州)有限公司 · 荣达餐饮试-租赁帕力安4.5T',
|
||||||
|
keyFacts: [
|
||||||
|
{ label: '应退还总额', value: '¥11,610.18', emphasis: true },
|
||||||
|
{ label: '保证金总额', value: '¥10,000.00' },
|
||||||
|
{ label: '待结算总额', value: '¥-1,610.18' },
|
||||||
|
{ label: '应补缴总额', value: '¥0' },
|
||||||
|
],
|
||||||
|
currentApprover: '赵总',
|
||||||
|
showInitiatorInFooter: true,
|
||||||
|
initiatedBy: CURRENT_USER,
|
||||||
|
initiatedAt: '2026-06-10 14:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ac-25',
|
||||||
|
type: 'billing',
|
||||||
|
status: 'processing',
|
||||||
|
listTab: 'initiated',
|
||||||
|
title: '嘉兴市振鑫物流有限公司',
|
||||||
|
subtitle: '第1期 · 2026-07-03至2026-07-31',
|
||||||
|
projectName: '浮云测试-0703-试用-1',
|
||||||
|
keyFacts: [
|
||||||
|
{ label: '计费车辆数量', value: '2辆' },
|
||||||
|
{ label: '应收款总额', value: '¥288.00', emphasis: true },
|
||||||
|
{ label: '实收款总额', value: '¥288.00' },
|
||||||
|
{ label: '开票总额', value: '¥244.00' },
|
||||||
|
],
|
||||||
|
currentApprover: '赵总',
|
||||||
|
showInitiatorInFooter: true,
|
||||||
|
initiatedBy: '王雨昊',
|
||||||
|
initiatedAt: '2026-07-31 16:40',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function filterCasesByTab(
|
export function filterCasesByTab(
|
||||||
|
|||||||
@@ -272,6 +272,7 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ap-card__fact-value--emphasis {
|
.ap-card__fact-value--emphasis {
|
||||||
@@ -310,6 +311,25 @@
|
|||||||
border-color: #fde68a;
|
border-color: #fde68a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ap-card__extra-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-card__extra-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: #f1f5f9;
|
||||||
|
color: var(--ap-muted);
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
.ap-card__footer {
|
.ap-card__footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
@@ -571,6 +591,56 @@
|
|||||||
background: #f1f5f9;
|
background: #f1f5f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ap-billing-summary th {
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-summary td {
|
||||||
|
width: 23%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-detail-section {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-totals {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f8fafc;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ap-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-totals__value {
|
||||||
|
color: var(--ap-primary) !important;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-totals__meta {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-timeline-section {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-timeline-item {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-billing-timeline-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 960px) {
|
||||||
.ap-page {
|
.ap-page {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|||||||
@@ -50,8 +50,12 @@ export interface ApprovalCardItem {
|
|||||||
initiatedBy: string;
|
initiatedBy: string;
|
||||||
initiatedAt: string;
|
initiatedAt: string;
|
||||||
typeLabel?: string;
|
typeLabel?: string;
|
||||||
|
statusLabel?: string;
|
||||||
|
projectName?: string;
|
||||||
footerText?: string;
|
footerText?: string;
|
||||||
showInitiatorInFooter?: boolean;
|
showInitiatorInFooter?: boolean;
|
||||||
|
initiatorSuffixInFooter?: boolean;
|
||||||
|
extraTags?: string[];
|
||||||
ccUsers?: string[];
|
ccUsers?: string[];
|
||||||
handledBy?: string;
|
handledBy?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user