更新
This commit is contained in:
1 parent
5718a00e31
commit
1850ac640e
226 files changed
+37772
-12071
No files matched your search
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view v-if="loading && !profile" class="state-box">
|
||||
<text class="state-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<block v-else-if="profile">
|
||||
<view class="hero">
|
||||
<view class="hero-top">
|
||||
<text class="hero-name">{{ name }}</text>
|
||||
<u-tag :text="partnerTypeLabel(partnerType)" type="primary" size="mini" />
|
||||
</view>
|
||||
<text class="hero-sub">{{ [profile.contact_person, profile.contact_phone].filter(Boolean).join(' · ') || '未填联系人' }}</text>
|
||||
<view class="hero-grid">
|
||||
<view class="hero-cell">
|
||||
<text class="cell-label">{{ isSupplier ? '未付应付' : '未收应收' }}</text>
|
||||
<text class="cell-value owe">¥{{ moneyText(openAmount) }}</text>
|
||||
</view>
|
||||
<view class="hero-cell">
|
||||
<text class="cell-label">{{ isSupplier ? '累计应付' : '累计应收' }}</text>
|
||||
<text class="cell-value">¥{{ moneyText(totalAmount) }}</text>
|
||||
</view>
|
||||
<view class="hero-cell">
|
||||
<text class="cell-label">账期</text>
|
||||
<text class="cell-value">{{ Number(profile.payment_days) > 0 ? profile.payment_days + ' 天' : '现结' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="block-head">
|
||||
<text class="block-title">基础资料</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">等级 / 类型</text>
|
||||
<text class="line-value">{{ join([profile.supplier_level || profile.customer_level, profile.supplier_type || profile.customer_type]) }}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">联系电话</text>
|
||||
<text class="line-value link" @tap="callPhone">{{ dash(profile.contact_phone) }}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">邮箱</text>
|
||||
<text class="line-value">{{ dash(profile.contact_email) }}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">地址</text>
|
||||
<text class="line-value">{{ dash(profile.address) }}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">开票抬头</text>
|
||||
<text class="line-value">{{ join([profile.invoice_title, profile.tax_number]) }}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<text class="line-label">收款账户</text>
|
||||
<text class="line-value">{{ join([profile.bank_name, profile.bank_account]) }}</text>
|
||||
</view>
|
||||
<view v-if="Number(profile.credit_limit) > 0" class="line">
|
||||
<text class="line-label">信用额度</text>
|
||||
<text class="line-value">¥{{ moneyText(profile.credit_limit) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="block-head">
|
||||
<text class="block-title">未结账单({{ bills.length }} 张)</text>
|
||||
<text class="block-tip" @tap="goAllBills">全部 {{ billTotal }} 张</text>
|
||||
</view>
|
||||
<view v-if="!bills.length" class="empty-line">
|
||||
<text>没有未结账单</text>
|
||||
</view>
|
||||
<view v-for="b in bills" :key="b.id" class="line tap" @tap="goBill(b)">
|
||||
<view class="line-label grow">
|
||||
<text>{{ b.source_doc_no || `账单#${b.id}` }}</text>
|
||||
<text class="sub">{{ b.bill_date }}{{ b.due_date ? ' · 到期 ' + b.due_date : '' }}</text>
|
||||
</view>
|
||||
<view class="line-value right">
|
||||
<text class="bal">¥{{ moneyText(b.balance) }}</text>
|
||||
<text v-if="b.overdue_days > 0" class="over">逾期 {{ b.overdue_days }} 天</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="footer-space"></view>
|
||||
|
||||
<view class="actions">
|
||||
<view class="act" @tap="goDocs">
|
||||
<text>历史单据</text>
|
||||
</view>
|
||||
<view class="act primary" @tap="goFund">
|
||||
<text>{{ isSupplier ? '去付款' : '去收款' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 客商详情:档案 + 未结账单 + 一键收付款。
|
||||
* 余额口径直接取往来账(bill)与对账汇总,和 Web 端「应收应付」页一致,
|
||||
* 端上不另算一套,避免业务在手机上看到的欠款跟财务对不上。
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import {
|
||||
fetchBills,
|
||||
fetchPartnerSummary,
|
||||
getPartner,
|
||||
moneyText,
|
||||
partnerTypeLabel
|
||||
} from '@/api/erp.js'
|
||||
|
||||
const profile = ref(null)
|
||||
const bills = ref([])
|
||||
const billTotal = ref(0)
|
||||
const summary = ref({})
|
||||
const loading = ref(false)
|
||||
const partnerId = ref(0)
|
||||
const partnerType = ref('customer')
|
||||
|
||||
const isSupplier = computed(() => partnerType.value === 'supplier')
|
||||
const name = computed(() => {
|
||||
const p = profile.value || {}
|
||||
return p.supplier_name || p.customer_name || p.name || '未命名客商'
|
||||
})
|
||||
const openAmount = computed(() => {
|
||||
const s = summary.value || {}
|
||||
return Number(isSupplier.value ? s.pay_open : s.recv_open) || 0
|
||||
})
|
||||
const totalAmount = computed(() => {
|
||||
const s = summary.value || {}
|
||||
return Number(isSupplier.value ? s.pay_total : s.recv_total) || 0
|
||||
})
|
||||
|
||||
onLoad(async (query = {}) => {
|
||||
partnerId.value = Number(query.id) || 0
|
||||
partnerType.value = String(query.partner_type) === 'supplier' ? 'supplier' : 'customer'
|
||||
uni.setNavigationBarTitle({ title: partnerTypeLabel(partnerType.value) })
|
||||
await load()
|
||||
})
|
||||
|
||||
async function load() {
|
||||
if (!partnerId.value) {
|
||||
uni.showToast({ title: '缺少客商 ID', icon: 'none' })
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const [p, b, rows] = await Promise.all([
|
||||
getPartner(partnerId.value, partnerType.value),
|
||||
fetchBills({ partnerId: partnerId.value, partnerType: partnerType.value, settleState: 'open', pageSize: 10 }),
|
||||
fetchPartnerSummary(partnerType.value)
|
||||
])
|
||||
profile.value = p
|
||||
bills.value = b.list || []
|
||||
billTotal.value = b.total || 0
|
||||
// 对账汇总按 partner_type:id 归并,这里只取当前这一家
|
||||
summary.value = rows.find((r) => Number(r.partner_id) === partnerId.value) || {}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '客商信息加载失败', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goFund() {
|
||||
const fundType = isSupplier.value ? 2 : 1
|
||||
uni.navigateTo({
|
||||
url: `/pages/erp/finance/fund-edit?fund_type=${fundType}&partner_id=${partnerId.value}&partner_name=${encodeURIComponent(name.value)}`
|
||||
})
|
||||
}
|
||||
|
||||
function goDocs() {
|
||||
uni.navigateTo({ url: `/pages/erp/document/index?partner_id=${partnerId.value}` })
|
||||
}
|
||||
|
||||
function goAllBills() {
|
||||
const billType = isSupplier.value ? 2 : 1
|
||||
uni.navigateTo({ url: `/pages/erp/finance/bill?bill_type=${billType}&partner_id=${partnerId.value}` })
|
||||
}
|
||||
|
||||
function goBill(bill) {
|
||||
uni.navigateTo({ url: `/pages/erp/finance/bill-detail?id=${bill.id}` })
|
||||
}
|
||||
|
||||
function callPhone() {
|
||||
const phone = String(profile.value?.contact_phone || '').trim()
|
||||
if (!phone) return
|
||||
uni.makePhoneCall({ phoneNumber: phone, fail: () => {} })
|
||||
}
|
||||
|
||||
function dash(v) {
|
||||
const s = String(v ?? '').trim()
|
||||
return s || '—'
|
||||
}
|
||||
|
||||
function join(arr) {
|
||||
const s = (arr || []).filter(Boolean).join(' / ')
|
||||
return s || '—'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/src/styles/page-common.scss';
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: $color-bg-page;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.hero {
|
||||
margin: 0 $page-padding-x 24rpx;
|
||||
padding: 32rpx;
|
||||
border-radius: $radius-lg;
|
||||
background: $hero-gradient;
|
||||
color: #ffffff;
|
||||
box-shadow: $shadow-float;
|
||||
}
|
||||
|
||||
.hero-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.hero-name {
|
||||
flex: 1;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hero-sub {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: flex;
|
||||
margin-top: 28rpx;
|
||||
padding-top: 22rpx;
|
||||
border-top: 1rpx solid rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.hero-cell {
|
||||
flex: 1;
|
||||
|
||||
.cell-label {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.cell-value {
|
||||
display: block;
|
||||
margin-top: 6rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&.owe {
|
||||
color: #fecaca;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
@include card;
|
||||
margin: 0 $page-padding-x 24rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
}
|
||||
|
||||
.block-head {
|
||||
@include block-head;
|
||||
}
|
||||
|
||||
.block-title {
|
||||
@include section-title;
|
||||
}
|
||||
|
||||
.block-tip {
|
||||
font-size: 22rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1rpx solid $color-divider;
|
||||
font-size: 26rpx;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.tap:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.line-label {
|
||||
color: $color-text-secondary;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.grow {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sub {
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
font-size: 22rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.line-value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
color: $color-text;
|
||||
word-break: break-all;
|
||||
|
||||
&.link {
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.bal {
|
||||
font-size: 27rpx;
|
||||
font-weight: 500;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.over {
|
||||
font-size: 21rpx;
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.empty-line {
|
||||
padding: 40rpx 0;
|
||||
text-align: center;
|
||||
font-size: 25rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.footer-space {
|
||||
height: calc(150rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
padding: 18rpx $page-padding-x calc(18rpx + env(safe-area-inset-bottom));
|
||||
background: $color-card;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(15, 23, 42, 0.06);
|
||||
@include dialog-responsive;
|
||||
}
|
||||
|
||||
.act {
|
||||
flex: 1;
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
text-align: center;
|
||||
border-radius: $radius-full;
|
||||
background: $color-bg-page;
|
||||
font-size: 26rpx;
|
||||
color: $color-text-secondary;
|
||||
|
||||
&.primary {
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
.state-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 140rpx 0;
|
||||
}
|
||||
|
||||
.state-text {
|
||||
font-size: 28rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,320 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="filter-bar">
|
||||
<view class="type-row">
|
||||
<view
|
||||
v-for="t in PARTNER_TYPES"
|
||||
:key="t.value"
|
||||
class="type-item"
|
||||
:class="{ active: partnerType === t.value }"
|
||||
@tap="switchType(t.value)"
|
||||
>
|
||||
<text>{{ t.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-box">
|
||||
<FaIcon name="magnifying-glass" color="#94a3b8" :size="16" />
|
||||
<input
|
||||
v-model="keyword"
|
||||
class="search-input"
|
||||
:placeholder="`搜索${partnerTypeLabel(partnerType)}名称`"
|
||||
confirm-type="search"
|
||||
@confirm="refresh"
|
||||
/>
|
||||
<text v-if="keyword" class="search-clear" @tap="clearKeyword">清空</text>
|
||||
</view>
|
||||
<view class="sum-row">
|
||||
<text class="sum-item">共 {{ total }} 家</text>
|
||||
<text class="sum-item">未结合计 ¥{{ moneyText(openTotal) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading && !list.length" class="state-box">
|
||||
<text class="state-text">加载中...</text>
|
||||
</view>
|
||||
<view v-else-if="!list.length" class="state-box">
|
||||
<u-empty mode="search" :text="`没有匹配的${partnerTypeLabel(partnerType)}`" />
|
||||
<text class="state-tip">客商建档请在 Web 后台 CRM / 进销存里完成</text>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view v-for="row in list" :key="row.partner_id" class="p-card" @tap="openDetail(row)">
|
||||
<view class="p-top">
|
||||
<text class="p-name">{{ row.partner_name }}</text>
|
||||
<text class="p-open" :class="{ owe: Number(row.open_amount) > 0 }">
|
||||
{{ Number(row.open_amount) > 0 ? `未结 ¥${moneyText(row.open_amount)}` : '已结清' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="p-meta">
|
||||
<text v-if="row.contact_person">{{ row.contact_person }} {{ row.contact_phone || '' }}</text>
|
||||
<text v-if="row.level">等级 {{ row.level }}</text>
|
||||
<text v-if="Number(row.payment_days) > 0">账期 {{ row.payment_days }} 天</text>
|
||||
<text v-if="Number(row.credit_limit) > 0">信用额 ¥{{ moneyText(row.credit_limit) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="finished" class="load-done">
|
||||
<text>{{ list.length ? '没有更多了' : '' }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="fab" @tap="goBills">
|
||||
<FaIcon name="receipt" color="#ffffff" :size="20" />
|
||||
<text>{{ partnerType === 'supplier' ? '应付账单' : '应收账单' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 客商列表(供应商 / 客户同一个页,靠 partner_type 分流)。
|
||||
* 与后端 partner/list 一致:只列正式启用、有归属的对象,公海客户不参与开单也不在这里出现。
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import FaIcon from '@/components/FaIcon.vue'
|
||||
import { PARTNER_TYPES, fetchPartners, moneyText, partnerTypeLabel } from '@/api/erp.js'
|
||||
|
||||
const PAGE_SIZE = 20
|
||||
|
||||
const list = ref([])
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
const keyword = ref('')
|
||||
const partnerType = ref('customer')
|
||||
|
||||
const openTotal = computed(() => list.value.reduce((sum, r) => sum + Number(r.open_amount || 0), 0))
|
||||
|
||||
onLoad((query = {}) => {
|
||||
if (query.partner_type) partnerType.value = String(query.partner_type) === 'supplier' ? 'supplier' : 'customer'
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
refresh()
|
||||
})
|
||||
|
||||
onReachBottom(() => {
|
||||
if (finished.value || loading.value) return
|
||||
loadMore()
|
||||
})
|
||||
|
||||
function switchType(value) {
|
||||
if (partnerType.value === value) return
|
||||
partnerType.value = value
|
||||
list.value = []
|
||||
refresh()
|
||||
uni.setNavigationBarTitle({ title: partnerTypeLabel(value) })
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
page.value = 1
|
||||
finished.value = false
|
||||
list.value = []
|
||||
await loadPage()
|
||||
}
|
||||
|
||||
async function loadMore() {
|
||||
page.value += 1
|
||||
await loadPage()
|
||||
}
|
||||
|
||||
async function loadPage() {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await fetchPartners({
|
||||
page: page.value,
|
||||
pageSize: PAGE_SIZE,
|
||||
partnerType: partnerType.value,
|
||||
keyword: keyword.value.trim()
|
||||
})
|
||||
const rows = data.list || []
|
||||
list.value = page.value === 1 ? rows : [...list.value, ...rows]
|
||||
total.value = data.total || 0
|
||||
finished.value = list.value.length >= total.value
|
||||
} catch (e) {
|
||||
if (page.value > 1) page.value -= 1
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function clearKeyword() {
|
||||
keyword.value = ''
|
||||
refresh()
|
||||
}
|
||||
|
||||
function openDetail(row) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/erp/partner/detail?id=${row.partner_id}&partner_type=${partnerType.value}`
|
||||
})
|
||||
}
|
||||
|
||||
function goBills() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/erp/finance/bill?bill_type=${partnerType.value === 'supplier' ? 2 : 1}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/src/styles/page-common.scss';
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: $color-bg-page;
|
||||
padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: $color-bg-page;
|
||||
padding: 20rpx $page-padding-x 8rpx;
|
||||
}
|
||||
|
||||
.type-row {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.type-item {
|
||||
padding: 10rpx 32rpx;
|
||||
border-radius: $radius-full;
|
||||
background: $color-card;
|
||||
font-size: 26rpx;
|
||||
color: $color-text-secondary;
|
||||
box-shadow: $shadow-card;
|
||||
|
||||
&.active {
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
height: 72rpx;
|
||||
padding: 0 24rpx;
|
||||
background: $color-card;
|
||||
border-radius: $radius-full;
|
||||
box-shadow: $shadow-card;
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: $color-text;
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
font-size: 24rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
.sum-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 8rpx 4rpx;
|
||||
}
|
||||
|
||||
.sum-item {
|
||||
font-size: 24rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.p-card {
|
||||
@include card;
|
||||
margin: 0 $page-padding-x 20rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
|
||||
&:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
.p-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.p-name {
|
||||
flex: 1;
|
||||
font-size: 29rpx;
|
||||
font-weight: 500;
|
||||
color: $color-text;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.p-open {
|
||||
flex-shrink: 0;
|
||||
font-size: 25rpx;
|
||||
color: $color-text-muted;
|
||||
|
||||
&.owe {
|
||||
color: #dc2626;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.p-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8rpx 24rpx;
|
||||
margin-top: 10rpx;
|
||||
font-size: 23rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.load-done {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 8rpx 0 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.state-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 120rpx 40rpx;
|
||||
}
|
||||
|
||||
.state-text,
|
||||
.state-tip {
|
||||
font-size: 26rpx;
|
||||
color: $color-text-muted;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.fab {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: calc(48rpx + env(safe-area-inset-bottom));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
height: 84rpx;
|
||||
padding: 0 44rpx;
|
||||
border-radius: $radius-full;
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
font-size: 27rpx;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 8rpx 24rpx rgba(37, 99, 235, 0.4);
|
||||
|
||||
&:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user