Files
BMS/bms-front/src/views/report/arProfit/index.vue
T
2026-11-15 16:29:58 +08:00

336 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container ar-profit-report">
<el-card shadow="never">
<el-form :model="query" inline @submit.prevent>
<el-form-item label="账单日期">
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item>
<el-form-item label="客户">
<customer-select v-model="query.customerId" :fetch-options="listArBillCustomerOptions"
placeholder="请输入客户名称或代码搜索" :remote-search="true" :page-size="20" />
</el-form-item>
<el-form-item label="销售员">
<el-select v-model="query.salesUserId" placeholder="姓名或工号搜索" clearable filterable remote
:remote-method="searchSales" :loading="salesLoading" style="width: 180px"
@input="handleSalesInput">
<el-option v-for="person in salesOptions" :key="person.userId" :label="person.name || person.code || String(person.userId)" :value="person.userId">
<span>{{ person.name || person.code || person.userId }}</span>
<span v-if="person.code" class="sales-code">{{ person.code }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="账单号"><el-input v-model="query.billNo" clearable @keyup.enter="search" /></el-form-item>
<el-form-item label="状态">
<el-select v-model="query.status" placeholder="全部状态" clearable style="width: 140px">
<el-option label="已确认" value="CONFIRMED" /><el-option label="部分核销" value="PARTIAL_WRITTEN_OFF" /><el-option label="已核销" value="WRITTEN_OFF" />
</el-select>
</el-form-item>
<el-form-item><el-button type="primary" icon="Search" @click="search">搜索</el-button><el-button icon="Refresh" @click="reset">重置</el-button></el-form-item>
</el-form>
</el-card>
<el-card v-for="summary in summaryCards" :key="summary.currency || 'empty'" shadow="never" class="summary-card">
<template #header>{{ summary.currency ? summary.currency + ' 汇总' : '汇总' }}</template>
<div class="metrics">
<div>账单数 <b>{{ summary.billCount ?? '-' }}</b></div>
<div>销售价 <b>{{ money(summary.salesAmount) }}</b></div><div>产品价 <b>{{ money(summary.productAmount) }}</b></div>
<div>销售毛利 <b>{{ money(summary.salesGrossProfit) }}</b></div>
<div>销售毛利率 <b>{{ rate(summary.salesGrossMarginRate) }}</b></div>
<div>
<el-tooltip content="仅统计已全部核销、提成计算成功且未冲回的订单提成;未全部核销或提成异常的订单暂不计入,无已计算提成时显示 -。" placement="top">
<span>正式提成 ⓘ</span>
</el-tooltip>
<b>{{ money(summary.commissionAmount) }}</b>
</div>
<div>账单已核销 <b>{{ money(summary.writtenOffAmount) }}</b></div><div>账单未核销 <b>{{ money(summary.unwrittenAmount) }}</b></div>
</div>
</el-card>
<el-card shadow="never" class="data-card">
<div class="heading">
<span class="table-title">账单列表</span>
<div>
<el-button v-hasPermi="['report:arProfit:export']" icon="Download" @click="exportRows">导出账单</el-button>
<el-button v-hasPermi="['report:arProfit:commission']" @click="openCommission()">提成管理</el-button>
</div>
</div>
<el-table v-loading="loading" :data="rows" border stripe>
<el-table-column prop="billNo" label="账单号" min-width="170" show-overflow-tooltip />
<el-table-column prop="billName" label="账单名称" min-width="170" show-overflow-tooltip />
<el-table-column prop="billDate" label="账单日期" width="115" />
<el-table-column prop="customerCode" label="客户代码" width="110" />
<el-table-column prop="customerName" label="客户名称" min-width="160" show-overflow-tooltip />
<el-table-column prop="salesUserName" label="销售员" width="110" />
<el-table-column prop="currency" label="币种" width="80" />
<el-table-column label="销售价" min-width="110" align="right"><template #default="{ row }">{{ money(row.salesAmount) }}</template></el-table-column>
<el-table-column label="产品价" min-width="110" align="right"><template #default="{ row }">{{ money(row.productAmount) }}</template></el-table-column>
<el-table-column label="销售毛利" min-width="110" align="right"><template #default="{ row }">{{ money(row.salesGrossProfit) }}</template></el-table-column>
<el-table-column label="销售毛利率" width="110" align="right"><template #default="{ row }">{{ rate(row.salesGrossMarginRate) }}</template></el-table-column>
<el-table-column label="已核销" min-width="110" align="right"><template #default="{ row }">{{ money(row.writtenOffAmount) }}</template></el-table-column>
<el-table-column label="未核销" min-width="110" align="right"><template #default="{ row }">{{ money(row.unwrittenAmount) }}</template></el-table-column>
<el-table-column label="状态" width="110"><template #default="{ row }">{{ statusLabel(row.status) }}</template></el-table-column>
<el-table-column label="操作" width="250" fixed="right">
<template #default="{ row }">
<div class="ar-profit-actions">
<el-button link type="primary" @click="openBillDetails(row)">账单明细</el-button>
<el-button v-hasPermi="['report:arProfit:list']" link type="primary" @click="openBillCommission(row)">查看提成</el-button>
<el-button v-hasPermi="['report:arProfit:commission']" link type="primary" @click="openWriteoffRates(row)">核销比例</el-button>
</div>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" @pagination="loadRows" />
</el-card>
<el-dialog v-model="detailsVisible" :title="'账单明细:' + detailBillNo" width="900px" append-to-body>
<el-table :data="details" border v-loading="detailsLoading">
<el-table-column prop="orderNo" label="订单号" min-width="160" />
<el-table-column prop="productName" label="产品名称" min-width="150" />
<el-table-column prop="currency" label="币种" width="80" />
<el-table-column label="销售价" align="right"><template #default="{ row }">{{ money(row.totalAmount) }}</template></el-table-column>
<el-table-column label="操作" width="100"><template #default="{ row }"><el-button link type="primary" @click="openFees(row)">费用明细</el-button></template></el-table-column>
</el-table>
<pagination v-show="detailsTotal > 0" v-model:page="detailsPage" v-model:limit="detailsSize" :total="detailsTotal" @pagination="loadBillDetails" />
</el-dialog>
<el-dialog v-model="feeVisible" title="本次出账费用明细" width="800px" append-to-body>
<el-table :data="fees" border v-loading="feeLoading">
<el-table-column prop="feeName" label="费用名称" min-width="140" /><el-table-column prop="currency" label="币种" width="80" />
<el-table-column label="销售价" align="right"><template #default="{ row }">{{ money(row.amount) }}</template></el-table-column>
<el-table-column label="产品价" align="right"><template #default="{ row }">{{ money(feeProductAmount(row)) }}</template></el-table-column>
</el-table>
</el-dialog>
<el-dialog v-model="commissionVisible" title="提成管理" width="1100px" append-to-body>
<el-tabs v-model="commissionTab" @tab-change="loadCommissionTab">
<el-tab-pane label="正式提成" name="results">
<el-button icon="Download" style="margin-bottom: 12px" @click="exportCommissions">导出提成明细</el-button>
<el-checkbox v-model="includeReversed" style="margin: 0 0 12px 12px" @change="loadCommissionTab">显示已冲回记录</el-checkbox>
<el-table :data="commissionSummary" border size="small" style="margin-bottom: 16px">
<el-table-column prop="salesUserName" label="销售员" /><el-table-column prop="currency" label="币种" width="80" />
<el-table-column prop="orderCount" label="订单明细数" /><el-table-column prop="pendingCount" label="异常订单数" />
<el-table-column label="正式提成合计" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
</el-table>
<el-table :data="results" border size="small" v-loading="commissionLoading">
<el-table-column prop="billNo" label="账单号" min-width="160" /><el-table-column prop="orderNo" label="订单号" min-width="150" />
<el-table-column prop="salesUserName" label="销售员" width="110" /><el-table-column prop="currency" label="币种" width="75" />
<el-table-column label="销售毛利" width="110" align="right"><template #default="{ row }">{{ money(row.grossProfit) }}</template></el-table-column>
<el-table-column label="正式提成" width="110" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
<el-table-column label="状态" min-width="120"><template #default="{ row }">{{ resultLabel(row.resultStatus) }}</template></el-table-column>
<el-table-column v-if="includeReversed" prop="reversedBy" label="冲回人" width="110" />
<el-table-column v-if="includeReversed" label="冲回时间" width="170"><template #default="{ row }">{{ row.reversedTime ? parseTime(row.reversedTime) : '-' }}</template></el-table-column>
<el-table-column label="依据" width="100"><template #default="{ row }"><el-button link type="primary" @click="openWriteoffRates(row)">核销比例</el-button></template></el-table-column>
</el-table>
<pagination v-show="commissionTotal > 0" v-model:page="commissionPage" v-model:limit="commissionSize" :total="commissionTotal" @pagination="loadCommissionTab" />
</el-tab-pane>
<el-tab-pane label="提成比例" name="rates">
<el-form inline><el-form-item label="销售员"><user-select v-model="rateForm.salesUserId" placeholder="选择销售员" style="width: 200px" /></el-form-item>
<el-form-item label="比例(%)"><el-input-number v-model="rateForm.rate" :min="0" :max="100" :precision="4" /></el-form-item>
<el-form-item><el-button type="primary" @click="saveRate">立即生效</el-button></el-form-item>
</el-form>
<el-table :data="rates" border size="small" height="400" v-loading="commissionLoading">
<el-table-column prop="salesUserName" label="销售员" /><el-table-column prop="salesUserCode" label="销售员编码" />
<el-table-column prop="rate" label="比例(%)" /><el-table-column prop="effectiveAt" label="生效时间" /><el-table-column prop="createBy" label="操作人" />
</el-table>
</el-tab-pane>
<el-tab-pane label="比例待确认" name="missing">
<el-table :data="missingRates" border size="small" v-loading="commissionLoading">
<el-table-column prop="billNo" label="账单号" min-width="150" /><el-table-column prop="customerName" label="客户" min-width="140" />
<el-table-column prop="salesUserName" label="销售员" width="110" /><el-table-column prop="writeoffAmount" label="核销金额" width="110" />
<el-table-column prop="writeoffDate" label="核销日期" width="165"><template #default="{ row }">{{ parseTime(row.writeoffDate, '{y}-{m}-{d}') }}</template></el-table-column>
<el-table-column label="操作" width="140"><template #default="{ row }"><el-button v-if="row.rate === null || row.rate === undefined" link type="primary" @click="openConfirm(row)">确认比例</el-button><span v-else>比例异常,请核对</span></template></el-table-column>
</el-table>
<pagination v-show="missingTotal > 0" v-model:page="missingPage" v-model:limit="missingSize" :total="missingTotal" @pagination="loadCommissionTab" />
</el-tab-pane>
</el-tabs>
</el-dialog>
<el-dialog v-model="billCommissionVisible" :title="'账单提成明细:' + billCommissionNo" width="1000px" append-to-body>
<el-table :data="billCommissionSummary" border size="small" style="margin-bottom: 16px">
<el-table-column prop="salesUserName" label="销售员" /><el-table-column prop="currency" label="币种" width="80" />
<el-table-column prop="orderCount" label="订单明细数" /><el-table-column prop="pendingCount" label="异常订单数" />
<el-table-column label="正式提成合计" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
</el-table>
<el-table :data="billCommissionResults" border size="small" v-loading="billCommissionLoading">
<el-table-column prop="orderNo" label="订单号" min-width="170" show-overflow-tooltip />
<el-table-column prop="salesUserName" label="销售员" width="110" /><el-table-column prop="currency" label="币种" width="80" />
<el-table-column label="销售毛利" width="120" align="right"><template #default="{ row }">{{ money(row.grossProfit) }}</template></el-table-column>
<el-table-column label="正式提成" width="120" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
<el-table-column label="状态" min-width="130"><template #default="{ row }">{{ resultLabel(row.resultStatus) }}</template></el-table-column>
</el-table>
<pagination v-show="billCommissionTotal > 0" v-model:page="billCommissionPage" v-model:limit="billCommissionSize" :total="billCommissionTotal" @pagination="loadBillCommission" />
</el-dialog>
<el-dialog v-model="confirmVisible" title="确认历史核销比例" width="480px" append-to-body>
<el-form label-width="100px"><el-form-item label="账单号">{{ confirmForm.billNo }}</el-form-item>
<el-form-item label="比例(%)"><el-input-number v-model="confirmForm.rate" :min="0" :max="100" :precision="4" /></el-form-item>
<el-form-item label="核对说明"><el-input v-model="confirmForm.remark" type="textarea" maxlength="500" /></el-form-item>
</el-form>
<template #footer><el-button @click="confirmVisible = false">取消</el-button><el-button type="primary" @click="confirmRate">确认</el-button></template>
</el-dialog>
<el-dialog v-model="writeoffRatesVisible" title="账单核销与提成比例" width="950px" append-to-body>
<el-table :data="writeoffRates" border size="small" v-loading="writeoffRatesLoading">
<el-table-column prop="writeoffDate" label="核销日期" width="130"><template #default="{ row }">{{ parseTime(row.writeoffDate, '{y}-{m}-{d}') }}</template></el-table-column>
<el-table-column prop="writeoffAmount" label="核销金额" width="120" /><el-table-column prop="rate" label="比例(%)" width="110" />
<el-table-column label="状态" width="100"><template #default="{ row }">{{ row.status === 'EFFECTIVE' ? '有效' : '已反核销' }}</template></el-table-column>
<el-table-column prop="confirmedBy" label="补录人" width="110" /><el-table-column prop="remark" label="核对说明" min-width="180" show-overflow-tooltip />
</el-table>
</el-dialog>
</div>
</template>
<script setup name="ArProfitReport">
import { listArBillCustomerOptions } from '@/api/ar/bill'
import { addArProfitRate, confirmArProfitMissingRate, listArProfitAreaRules, listArProfitBillDetails, listArProfitBills, listArProfitCommissions, listArProfitCommissionSummary, listArProfitFees, listArProfitMissingRates, listArProfitRates, listArProfitSalesOptions, listArProfitSummary, listArProfitWriteoffRates } from '@/api/report/arProfit'
import { parseTime } from '@/utils/bms'
import { ElMessage } from 'element-plus'
const { proxy } = getCurrentInstance()
const query = reactive({ customerId: null, salesUserId: null, billNo: '', status: '' })
const salesOptions = ref([])
const salesLoading = ref(false)
let salesSearchVersion = 0
const areaRules = ref({})
const dateRange = ref(defaultBillDateRange())
const pageNum = ref(1), pageSize = ref(10), total = ref(0), rows = ref([]), loading = ref(false)
const summaries = ref([]), summaryLoaded = ref(false)
const detailsVisible = ref(false), detailsLoading = ref(false), details = ref([]), detailsTotal = ref(0)
const detailBillId = ref(null), detailBillNo = ref(''), detailsPage = ref(1), detailsSize = ref(10)
let detailsVersion = 0
const feeVisible = ref(false), feeLoading = ref(false), feeArea = ref(''), fees = ref([])
const summaryCards = computed(() => !summaryLoaded.value ? [] : summaries.value.length ? summaries.value : [{}])
let requestVersion = 0
let commissionVersion = 0
const commissionVisible = ref(false), commissionTab = ref('results'), commissionLoading = ref(false)
const results = ref([]), commissionTotal = ref(0), commissionPage = ref(1), commissionSize = ref(10)
const commissionSummary = ref([])
const billCommissionVisible = ref(false), billCommissionLoading = ref(false), billCommissionNo = ref('')
const billCommissionId = ref(null)
const billCommissionResults = ref([]), billCommissionTotal = ref(0), billCommissionPage = ref(1), billCommissionSize = ref(10)
const billCommissionSummary = ref([])
let billCommissionVersion = 0
const includeReversed = ref(false)
const rates = ref([]), rateForm = reactive({ salesUserId: null, rate: null })
const missingRates = ref([]), missingTotal = ref(0), missingPage = ref(1), missingSize = ref(10)
const confirmVisible = ref(false), confirmForm = reactive({ writeoffId: null, billNo: '', rate: null, remark: '' })
const writeoffRatesVisible = ref(false), writeoffRatesLoading = ref(false), writeoffRates = ref([])
function formatLocalDate(offset) {
const date = new Date()
date.setDate(date.getDate() + offset)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
function defaultBillDateRange() { return [formatLocalDate(-30), formatLocalDate(0)] }
function params() { return { ...query, beginBillDate: dateRange.value?.[0], endBillDate: dateRange.value?.[1] } }
function search() { pageNum.value = 1; loadRows(); loadSummary() }
function reset() { Object.assign(query, { customerId: null, salesUserId: null, billNo: '', status: '' }); dateRange.value = defaultBillDateRange(); search() }
function handleSalesInput() {
salesSearchVersion++
salesOptions.value = []
salesLoading.value = false
}
async function searchSales(keyword) {
const version = ++salesSearchVersion
salesOptions.value = []
salesLoading.value = true
try {
const res = await listArProfitSalesOptions({ keyword: keyword?.trim() || '' })
if (version !== salesSearchVersion) return
salesOptions.value = res.data || []
} finally {
if (version === salesSearchVersion) salesLoading.value = false
}
}
function loadRows() {
const version = ++requestVersion
loading.value = true
rows.value = []
listArProfitBills({ ...params(), pageNum: pageNum.value, pageSize: pageSize.value }).then(res => {
if (version === requestVersion) { rows.value = res.rows || []; total.value = res.total || 0 }
}).finally(() => { if (version === requestVersion) loading.value = false })
}
let summaryVersion = 0
function loadSummary() {
const version = ++summaryVersion
summaryLoaded.value = false
listArProfitSummary(params()).then(res => { if (version === summaryVersion) { summaries.value = res.data || []; summaryLoaded.value = true } })
}
function openBillDetails(row) { detailBillId.value = row.arBillId; detailBillNo.value = row.billNo; feeArea.value = row.customerArea; detailsPage.value = 1; detailsVisible.value = true; loadBillDetails() }
async function loadBillDetails() {
const version = ++detailsVersion
detailsLoading.value = true
details.value = []
try { const res = await listArProfitBillDetails(detailBillId.value, { pageNum: detailsPage.value, pageSize: detailsSize.value }); if (version === detailsVersion) { details.value = res.rows || []; detailsTotal.value = res.total || 0 } }
finally { if (version === detailsVersion) detailsLoading.value = false }
}
async function openFees(row) { feeVisible.value = true; feeLoading.value = true; fees.value = []; try { fees.value = (await listArProfitFees(row.detailId)).data || [] } finally { feeLoading.value = false } }
function exportRows() { proxy.download('/report/ar-profit/export', params(), `应收账单毛利分析_${Date.now()}.xlsx`) }
function exportCommissions() { proxy.download('/report/ar-profit/commissions/export', {}, `应收账单提成明细_${Date.now()}.xlsx`) }
function money(v) { return v === null || v === undefined || v === '' || !Number.isFinite(Number(v)) ? '-' : Number(v).toFixed(2) }
function rate(v) { return v === null || v === undefined || v === '' || !Number.isFinite(Number(v)) ? '-' : Number(v).toFixed(2) + '%' }
function feeProductAmount(row) {
if (areaRules.value[feeArea.value] === 'GUANGZHOU') return row.redlineAmount
if (areaRules.value[feeArea.value] === 'SHENZHEN') return row.productAmount
return null
}
function statusLabel(v) { return ({ CONFIRMED: '已确认', PARTIAL_WRITTEN_OFF: '部分核销', WRITTEN_OFF: '已核销' })[v] || v || '-' }
function resultLabel(v) { return ({ READY: '已计算', MISSING_RATE: '比例待确认', MISSING_PRICE: '价格缺失', MISSING_SNAPSHOT: '归属或区域缺失', WRITEOFF_MISMATCH: '核销金额不一致', REVERSED: '已冲回' })[v] || v || '-' }
function openCommission() { commissionPage.value = 1; commissionVisible.value = true; loadCommissionTab() }
function openBillCommission(row) { billCommissionId.value = row.arBillId; billCommissionNo.value = row.billNo; billCommissionPage.value = 1; billCommissionResults.value = []; billCommissionSummary.value = []; billCommissionTotal.value = 0; billCommissionVisible.value = true; loadBillCommission() }
async function loadBillCommission() {
const version = ++billCommissionVersion
const currentBillId = billCommissionId.value
if (!currentBillId) return
billCommissionLoading.value = true
billCommissionResults.value = []
billCommissionSummary.value = []
try {
const [result, summary] = await Promise.all([
listArProfitCommissions({ billId: currentBillId, pageNum: billCommissionPage.value, pageSize: billCommissionSize.value }),
listArProfitCommissionSummary({ billId: currentBillId })
])
if (version === billCommissionVersion) {
billCommissionResults.value = result.rows || []
billCommissionTotal.value = result.total || 0
billCommissionSummary.value = summary.data || []
}
} finally {
if (version === billCommissionVersion) billCommissionLoading.value = false
}
}
async function loadCommissionTab() {
const version = ++commissionVersion
const tab = commissionTab.value
commissionLoading.value = true
if (tab === 'results') { results.value = []; commissionSummary.value = [] }
try {
if (tab === 'rates') { const r = await listArProfitRates(); if (version === commissionVersion) rates.value = r.data || [] }
else if (tab === 'missing') { const r = await listArProfitMissingRates({ pageNum: missingPage.value, pageSize: missingSize.value }); if (version === commissionVersion) { missingRates.value = r.rows || []; missingTotal.value = r.total || 0 } }
else { const [r, summary] = await Promise.all([listArProfitCommissions({ pageNum: commissionPage.value, pageSize: commissionSize.value, includeReversed: includeReversed.value }), listArProfitCommissionSummary()]); if (version === commissionVersion) { results.value = r.rows || []; commissionTotal.value = r.total || 0; commissionSummary.value = summary.data || [] } }
} finally { if (version === commissionVersion) commissionLoading.value = false }
}
async function saveRate() {
if (!rateForm.salesUserId || rateForm.rate === null) return ElMessage.warning('请选择销售员并填写提成比例')
await addArProfitRate(rateForm); ElMessage.success('提成比例已保存'); loadCommissionTab()
}
function openConfirm(row) { Object.assign(confirmForm, { writeoffId: row.writeoffId, billNo: row.billNo, rate: null, remark: '' }); confirmVisible.value = true }
async function openWriteoffRates(row) { writeoffRatesVisible.value = true; writeoffRatesLoading.value = true; writeoffRates.value = []; try { writeoffRates.value = (await listArProfitWriteoffRates(row.arBillId)).data || [] } finally { writeoffRatesLoading.value = false } }
async function confirmRate() {
if (confirmForm.rate === null || !confirmForm.remark.trim()) return ElMessage.warning('请填写比例及核对说明')
await confirmArProfitMissingRate(confirmForm); confirmVisible.value = false; ElMessage.success('已确认提成比例'); loadCommissionTab()
}
listArProfitAreaRules().then(res => { areaRules.value = res.data || {} })
search()
</script>
<style scoped>
.summary-card, .data-card { margin-top: 14px; }
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: 14px; }
.metrics > div { min-width: 0; padding: 10px; background: var(--el-fill-color-lighter); color: var(--el-text-color-secondary); }
.metrics b { display: block; margin-top: 5px; color: var(--el-text-color-primary); }
.heading { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.table-title { font-size: 16px; font-weight: 500; }
.sales-code { float: right; margin-left: 16px; color: var(--el-text-color-secondary); font-size: 12px; }
.ar-profit-actions { display: flex; align-items: center; justify-content: center; gap: 2px; white-space: nowrap; }
.ar-profit-actions .el-button { margin: 0; padding: 0 2px; }
</style>