737 lines
20 KiB
Vue
737 lines
20 KiB
Vue
<template>
|
||
<div class="finance-layout-page">
|
||
<div class="page-top">
|
||
<div>
|
||
<h2>
|
||
利润概览
|
||
<em>{{ financialOverview.is_business_owner ? '业主机构' : '分销机构' }}</em>
|
||
</h2>
|
||
<p>
|
||
核算机构:<b>{{ displayValue(financialOverview.accounting_orgname) }}</b>
|
||
<span>编号 {{ displayValue(financialOverview.accounting_orgid) }}</span>
|
||
</p>
|
||
<div class="chips">
|
||
<span>含下级分销客户:<b>{{ customerScope.include_sub_reseller_customers ? '是' : '否' }}</b></span>
|
||
<span>下级分销机构:<b>{{ formatNumber(customerScope.descendant_reseller_count) }}</b> 家</span>
|
||
<span>账单总数:<b>{{ formatNumber(financialOverview.bill_count) }}</b></span>
|
||
<span>仅已入账:<b>{{ filters.only_accounted ? '是' : '否' }}</b></span>
|
||
<span>数据截断:<b>{{ financialOverview.truncated ? '是' : '否' }}</b></span>
|
||
</div>
|
||
</div>
|
||
<!-- <div class="view-meta">
|
||
查看计费统计
|
||
</div> -->
|
||
</div>
|
||
|
||
<div class="summary-grid">
|
||
<div v-for="card in summaryCards" :key="card.label" class="summary-card" :class="card.type">
|
||
<i></i>
|
||
<span>{{ card.label }}</span>
|
||
<strong>{{ card.value }}</strong>
|
||
<p>{{ card.desc }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<el-card shadow="never" class="panel">
|
||
<div class="panel-head">
|
||
<h3>收益构成(按客户来源)</h3>
|
||
</div>
|
||
<el-table
|
||
v-loading="loading"
|
||
:data="sourceRows"
|
||
size="small"
|
||
class="finance-table"
|
||
show-summary
|
||
:summary-method="getSourceSummary"
|
||
>
|
||
<el-table-column label="客户来源" min-width="180">
|
||
<template slot-scope="{ row }">
|
||
<span class="source-cell">
|
||
<i class="dot" :class="row.type"></i>{{ row.name }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="销售额" align="right" min-width="140">
|
||
<template slot-scope="{ row }">{{ money(row.sales_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="利润" align="right" min-width="140">
|
||
<template slot-scope="{ row }">
|
||
<span :class="amountClass(row.profit_total)">{{ money(row.profit_total) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="利润率" align="right" width="120">
|
||
<template slot-scope="{ row }">
|
||
<span :class="amountClass(row.margin)">{{ percent(row.margin) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :label="settleLabel" align="right" min-width="140">
|
||
<template slot-scope="{ row }">{{ money(row.settle_upstream_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="账单数" align="right" width="110">
|
||
<template slot-scope="{ row }">{{ formatNumber(row.bill_count) }}</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-card>
|
||
|
||
<el-card shadow="never" class="panel">
|
||
<div class="panel-head">
|
||
<h3>供应商 / 产品明细</h3>
|
||
|
||
</div>
|
||
<el-table
|
||
v-loading="loading"
|
||
:data="filteredProductRows"
|
||
size="small"
|
||
class="finance-table product-table"
|
||
show-summary
|
||
:summary-method="getProductSummary"
|
||
@row-click="openProductDetail"
|
||
>
|
||
<el-table-column label="供应商" min-width="170" show-overflow-tooltip>
|
||
<template slot-scope="{ row }">
|
||
{{ row.providerName }}
|
||
<el-tag v-if="row.hasSubReseller" size="mini" type="primary" effect="plain">含下级</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="productName" label="产品" min-width="190" show-overflow-tooltip />
|
||
<el-table-column prop="sales_total" label="销售额" align="right" min-width="140" sortable>
|
||
<template slot-scope="{ row }">{{ money(row.sales_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="profit_total" label="利润" align="right" min-width="140" sortable>
|
||
<template slot-scope="{ row }">
|
||
<span :class="amountClass(row.profit_total)">{{ money(row.profit_total) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="margin" label="利润率" align="right" width="120" sortable>
|
||
<template slot-scope="{ row }">
|
||
<span :class="amountClass(row.margin)">{{ percent(row.margin) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="settle_upstream_total" :label="settleLabel" align="right" min-width="140">
|
||
<template slot-scope="{ row }">{{ money(row.settle_upstream_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="bill_count" label="账单数" align="right" width="110" sortable>
|
||
<template slot-scope="{ row }">{{ formatNumber(row.bill_count) }}</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<p class="note">共 {{ productRows.length }} 个供应商/产品组合</p>
|
||
</el-card>
|
||
|
||
<el-dialog
|
||
:visible.sync="detailVisible"
|
||
width="680px"
|
||
custom-class="finance-detail-dialog"
|
||
append-to-body
|
||
:show-close="false"
|
||
>
|
||
<div v-if="currentProduct" class="detail-card">
|
||
<button class="detail-close" @click="detailVisible = false">×</button>
|
||
<div class="detail-head">
|
||
<h3>{{ currentProduct.providerName }} · {{ currentProduct.productName }}</h3>
|
||
<p>
|
||
销售额 {{ money(currentProduct.sales_total) }} ·
|
||
利润率 {{ percent(currentProduct.margin) }}
|
||
</p>
|
||
</div>
|
||
<el-table :data="detailRows" size="small" class="detail-table">
|
||
<el-table-column label="客户来源" min-width="160">
|
||
<template slot-scope="{ row }">
|
||
<span class="source-cell">
|
||
<i class="dot" :class="row.type"></i>{{ row.name }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="销售额" align="right" min-width="150">
|
||
<template slot-scope="{ row }">{{ money(row.sales_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="利润" align="right" min-width="150">
|
||
<template slot-scope="{ row }">
|
||
<span :class="amountClass(row.profit_total)">{{ money(row.profit_total) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :label="settleLabel" align="right" min-width="150">
|
||
<template slot-scope="{ row }">{{ money(row.settle_upstream_total) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="账单数" align="right" width="110">
|
||
<template slot-scope="{ row }">{{ formatNumber(row.bill_count) }}</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { reqFinancialOverview } from '@/api/FinancialOverview/FinancialOverview'
|
||
|
||
export default {
|
||
name: 'FinancialOverview',
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
keyword: '',
|
||
orgid: '',
|
||
financialOverview: {},
|
||
detailVisible: false,
|
||
currentProduct: null
|
||
}
|
||
},
|
||
computed: {
|
||
// 客户范围信息:是否包含下级分销客户、下级分销数量等。
|
||
customerScope() {
|
||
return this.financialOverview.customer_scope || {}
|
||
},
|
||
// 接口筛选条件展示,例如是否仅统计已入账账单。
|
||
filters() {
|
||
return this.financialOverview.filters || {}
|
||
},
|
||
// 统计周期,接口为空时页面展示“全部周期”。
|
||
period() {
|
||
return this.financialOverview.period || {}
|
||
},
|
||
// 财务汇总数据,包含直客、下级分销和总计。
|
||
totals() {
|
||
return this.financialOverview.totals || {}
|
||
},
|
||
// 总计数据用于顶部卡片和表格合计行。
|
||
grandTotal() {
|
||
return this.totals.grand_total || {}
|
||
},
|
||
// 上游结算字段文案由接口返回,业主机构时通常为“应付供应商”。
|
||
settleLabel() {
|
||
return this.financialOverview.settle_upstream_label || '应付供应商'
|
||
},
|
||
// 格式化统计周期文案。
|
||
periodText() {
|
||
if (this.period.start_date || this.period.end_date) {
|
||
return `${this.period.start_date || '-'} 至 ${this.period.end_date || '-'}`
|
||
}
|
||
return '全部周期'
|
||
},
|
||
// 顶部四个核心指标卡片。
|
||
summaryCards() {
|
||
return [
|
||
{
|
||
label: '销售总额',
|
||
value: this.money(this.grandTotal.sales_total),
|
||
desc: 'grand_total · sales_total',
|
||
type: 'blue'
|
||
},
|
||
{
|
||
label: '利润总额',
|
||
value: this.money(this.grandTotal.profit_total),
|
||
desc: `利润率 ${this.percent(this.margin(this.grandTotal.profit_total, this.grandTotal.sales_total))}`,
|
||
type: 'green'
|
||
},
|
||
{
|
||
label: this.settleLabel,
|
||
value: this.money(this.grandTotal.settle_upstream_total),
|
||
desc: 'settle_upstream_total',
|
||
type: 'amber'
|
||
},
|
||
{
|
||
label: '账单总数',
|
||
value: this.formatNumber(this.grandTotal.bill_count),
|
||
desc: `含 ${this.formatNumber(this.totals.from_sub_resellers && this.totals.from_sub_resellers.bill_count)} 笔下级分销`,
|
||
type: 'purple'
|
||
}
|
||
]
|
||
},
|
||
// 收益构成表:按直接客户和下级分销客户拆分。
|
||
sourceRows() {
|
||
return [
|
||
this.buildSourceRow('直接客户', this.totals.direct_customers, 'blue-dot'),
|
||
this.buildSourceRow('下级分销客户', this.totals.from_sub_resellers, 'purple-dot')
|
||
]
|
||
},
|
||
// 供应商/产品明细表:把接口 by_provider_product 结构扁平化,便于 el-table 渲染。
|
||
productRows() {
|
||
return (this.financialOverview.by_provider_product || []).map((item, index) => {
|
||
const total = item.total || {}
|
||
const direct = item.direct_customers || {}
|
||
const sub = item.from_sub_resellers || {}
|
||
return {
|
||
index,
|
||
providerName: this.displayValue(item.provider && item.provider.name),
|
||
productName: this.displayValue(item.product && item.product.name),
|
||
direct_customers: direct,
|
||
from_sub_resellers: sub,
|
||
sales_total: Number(total.sales_total || 0),
|
||
profit_total: Number(total.profit_total || 0),
|
||
settle_upstream_total: Number(total.settle_upstream_total || 0),
|
||
bill_count: Number(total.bill_count || 0),
|
||
margin: this.margin(total.profit_total, total.sales_total),
|
||
hasSubReseller: Number(sub.bill_count || 0) > 0 || Number(sub.sales_total || 0) !== 0 || Number(sub.profit_total || 0) !== 0
|
||
}
|
||
})
|
||
},
|
||
// 根据搜索关键词过滤供应商或产品名称。
|
||
filteredProductRows() {
|
||
const keyword = this.keyword.trim().toLowerCase()
|
||
if (!keyword) return this.productRows
|
||
return this.productRows.filter(item => {
|
||
return `${item.providerName} ${item.productName}`.toLowerCase().includes(keyword)
|
||
})
|
||
},
|
||
// 明细弹窗数据:展示当前产品的直客、下级分销和合计拆分。
|
||
detailRows() {
|
||
if (!this.currentProduct) return []
|
||
return [
|
||
this.buildSourceRow('直接客户', this.currentProduct.direct_customers, 'blue-dot'),
|
||
this.buildSourceRow('下级分销客户', this.currentProduct.from_sub_resellers, 'purple-dot'),
|
||
this.buildSourceRow('合计', this.currentProduct, 'total-dot')
|
||
]
|
||
}
|
||
},
|
||
mounted() {
|
||
this.getFinancialOverview()
|
||
},
|
||
methods: {
|
||
// 获取当前核算机构 orgid,优先使用路由参数,其次使用本地缓存。
|
||
getOrgId() {
|
||
const orgid = this.$route.query.orgid || sessionStorage.getItem('orgid') || localStorage.getItem('orgid') || ''
|
||
this.orgid = orgid
|
||
return orgid
|
||
},
|
||
// 请求财务概览接口,并保存原始返回数据供 computed 统一派生。
|
||
async getFinancialOverview() {
|
||
this.loading = true
|
||
try {
|
||
const orgid = this.getOrgId()
|
||
const res = await reqFinancialOverview({ accounting_orgid:orgid })
|
||
if (res && res.status === true) {
|
||
this.financialOverview = res.data || {}
|
||
}
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
// 统一构造金额行,避免直客、下级分销、合计三类数据重复处理。
|
||
buildSourceRow(name, data = {}, type) {
|
||
return {
|
||
name,
|
||
type,
|
||
sales_total: Number(data.sales_total || 0),
|
||
profit_total: Number(data.profit_total || 0),
|
||
settle_upstream_total: Number(data.settle_upstream_total || 0),
|
||
bill_count: Number(data.bill_count || 0),
|
||
margin: this.margin(data.profit_total, data.sales_total)
|
||
}
|
||
},
|
||
// 收益构成表合计行,取接口 totals.grand_total 保持与后端汇总一致。
|
||
getSourceSummary() {
|
||
return [
|
||
'合计',
|
||
this.money(this.grandTotal.sales_total),
|
||
this.money(this.grandTotal.profit_total),
|
||
this.percent(this.margin(this.grandTotal.profit_total, this.grandTotal.sales_total)),
|
||
this.money(this.grandTotal.settle_upstream_total),
|
||
this.formatNumber(this.grandTotal.bill_count)
|
||
]
|
||
},
|
||
// 供应商/产品表合计行,金额同样以接口 grand_total 为准。
|
||
getProductSummary() {
|
||
return [
|
||
'合计',
|
||
'',
|
||
this.money(this.grandTotal.sales_total),
|
||
this.money(this.grandTotal.profit_total),
|
||
this.percent(this.margin(this.grandTotal.profit_total, this.grandTotal.sales_total)),
|
||
this.money(this.grandTotal.settle_upstream_total),
|
||
this.formatNumber(this.grandTotal.bill_count)
|
||
]
|
||
},
|
||
// 打开单个供应商/产品的拆分详情弹窗。
|
||
openProductDetail(row) {
|
||
this.currentProduct = row
|
||
this.detailVisible = true
|
||
},
|
||
// 计算利润率:利润 / 销售额。
|
||
margin(profit, sales) {
|
||
const salesValue = Number(sales || 0)
|
||
return salesValue ? (Number(profit || 0) / salesValue) * 100 : 0
|
||
},
|
||
// 金额格式化,统一显示人民币和两位小数。
|
||
money(value) {
|
||
return `¥${Number(value || 0).toLocaleString('zh-CN', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2
|
||
})}`
|
||
},
|
||
// 百分比格式化,统一保留一位小数。
|
||
percent(value) {
|
||
return `${Number(value || 0).toFixed(1)}%`
|
||
},
|
||
// 数字格式化,补千分位。
|
||
formatNumber(value) {
|
||
return Number(value || 0).toLocaleString('zh-CN')
|
||
},
|
||
// 空值兜底,避免供应商或产品名称为空时页面留白。
|
||
displayValue(value) {
|
||
if (value === undefined || value === null || value === '') return '未命名'
|
||
return String(value)
|
||
},
|
||
// 金额正负颜色:负数标红,非负数标绿。
|
||
amountClass(value) {
|
||
return Number(value || 0) < 0 ? 'red-text' : 'green-text'
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.finance-layout-page {
|
||
min-height: 100vh;
|
||
padding: 18px 20px 36px;
|
||
color: #1f2733;
|
||
background: #f4f6fb;
|
||
}
|
||
|
||
.page-top {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 14px;
|
||
|
||
.crumb {
|
||
margin-bottom: 8px;
|
||
color: #667085;
|
||
font-size: 12px;
|
||
|
||
span {
|
||
margin: 0 6px;
|
||
color: #c4cad5;
|
||
}
|
||
}
|
||
|
||
h2 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin: 0 0 6px;
|
||
font-size: 22px;
|
||
line-height: 1;
|
||
|
||
em {
|
||
padding: 2px 9px;
|
||
color: #6d5df6;
|
||
font-size: 12px;
|
||
font-style: normal;
|
||
background: #f0edff;
|
||
border-radius: 999px;
|
||
}
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: #667085;
|
||
font-size: 13px;
|
||
|
||
span {
|
||
margin-left: 8px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.view-meta {
|
||
color: #667085;
|
||
font-size: 13px;
|
||
text-align: right;
|
||
|
||
small {
|
||
display: block;
|
||
margin-top: 4px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
.chips {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-top: 10px;
|
||
|
||
span {
|
||
padding: 4px 10px;
|
||
color: #667085;
|
||
font-size: 12px;
|
||
background: #fff;
|
||
border: 1px solid #e6eaf1;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
b {
|
||
color: #1f2733;
|
||
}
|
||
}
|
||
|
||
.summary-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 14px;
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.summary-card {
|
||
position: relative;
|
||
min-height: 102px;
|
||
padding: 16px 18px 14px;
|
||
overflow: hidden;
|
||
background: #fff;
|
||
border: 1px solid #e6eaf1;
|
||
border-radius: 12px;
|
||
box-shadow: 0 1px 3px rgba(20, 30, 55, 0.06), 0 8px 24px rgba(20, 30, 55, 0.05);
|
||
|
||
i {
|
||
position: absolute;
|
||
top: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 4px;
|
||
}
|
||
|
||
span {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: #667085;
|
||
font-size: 13px;
|
||
}
|
||
|
||
strong {
|
||
display: block;
|
||
font-size: 24px;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
p {
|
||
margin: 7px 0 0;
|
||
color: #98a2b3;
|
||
font-size: 12px;
|
||
}
|
||
|
||
&.blue {
|
||
i { background: #3a6df0; }
|
||
strong { color: #3a6df0; }
|
||
}
|
||
|
||
&.green {
|
||
i { background: #18a058; }
|
||
strong { color: #18a058; }
|
||
}
|
||
|
||
&.amber {
|
||
i { background: #d08e18; }
|
||
strong { color: #d08e18; }
|
||
}
|
||
|
||
&.purple {
|
||
i { background: #7a5af0; }
|
||
strong { color: #7a5af0; }
|
||
}
|
||
}
|
||
|
||
.panel {
|
||
margin-bottom: 14px;
|
||
border: 1px solid #e6eaf1;
|
||
border-radius: 12px;
|
||
box-shadow: 0 1px 3px rgba(20, 30, 55, 0.05);
|
||
|
||
.el-card__body {
|
||
padding: 14px 18px 10px;
|
||
}
|
||
}
|
||
|
||
.panel-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 10px;
|
||
|
||
h3 {
|
||
margin: 0;
|
||
color: #1f2733;
|
||
font-size: 15px;
|
||
}
|
||
}
|
||
|
||
.panel-tools {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
color: #98a2b3;
|
||
font-size: 12px;
|
||
|
||
.el-input {
|
||
width: 220px;
|
||
}
|
||
}
|
||
|
||
.finance-table {
|
||
th {
|
||
padding: 8px 0;
|
||
color: #667085;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
background: #fafbfe;
|
||
}
|
||
|
||
td {
|
||
padding: 7px 0;
|
||
color: #273142;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.el-table__footer td {
|
||
color: #1f2733;
|
||
font-weight: 700;
|
||
background: #fafbfe;
|
||
}
|
||
}
|
||
|
||
.product-table {
|
||
.el-table__row {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.el-table__row:hover > td {
|
||
background: #f0f5ff;
|
||
}
|
||
}
|
||
|
||
/deep/ .finance-detail-dialog {
|
||
overflow: hidden;
|
||
background: #fff;
|
||
border-radius: 18px;
|
||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.28);
|
||
|
||
.el-dialog__header {
|
||
display: none;
|
||
}
|
||
|
||
.el-dialog__body {
|
||
padding: 0;
|
||
}
|
||
}
|
||
|
||
.detail-card {
|
||
position: relative;
|
||
padding: 22px 24px 22px;
|
||
}
|
||
|
||
.detail-close {
|
||
position: absolute;
|
||
top: 18px;
|
||
right: 22px;
|
||
width: 34px;
|
||
height: 34px;
|
||
color: #667085;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
line-height: 32px;
|
||
text-align: center;
|
||
background: #f5f7fb;
|
||
border: 0;
|
||
border-radius: 10px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.detail-head {
|
||
padding-right: 48px;
|
||
margin-bottom: 18px;
|
||
|
||
h3 {
|
||
margin: 0 0 6px;
|
||
color: #1f2733;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: #667085;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
|
||
.detail-table {
|
||
/deep/ th {
|
||
padding: 12px 0;
|
||
color: #667085;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
background: #f7f8fb;
|
||
}
|
||
|
||
/deep/ td {
|
||
padding: 12px 0;
|
||
color: #273142;
|
||
font-size: 13px;
|
||
}
|
||
|
||
/deep/ .el-table__row:last-child td {
|
||
font-weight: 700;
|
||
background: #fafbfe;
|
||
}
|
||
}
|
||
|
||
.source-cell {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
}
|
||
|
||
.dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.blue-dot {
|
||
background: #3a6df0;
|
||
}
|
||
|
||
.purple-dot {
|
||
background: #7a5af0;
|
||
}
|
||
|
||
.total-dot {
|
||
background: #1f2733;
|
||
}
|
||
|
||
.green-text {
|
||
color: #18a058 !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.red-text {
|
||
color: #d03050 !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.note {
|
||
margin: 10px 0 2px;
|
||
color: #98a2b3;
|
||
font-size: 12px;
|
||
text-align: center;
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.summary-grid {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
}
|
||
|
||
@media (max-width: 760px) {
|
||
.page-top,
|
||
.panel-head,
|
||
.panel-tools {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.summary-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style>
|