Commit ce3e433a by yuzhenWang

修改样式

parent 5491ae58
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -36,7 +36,7 @@ function isActive(path: string): boolean { ...@@ -36,7 +36,7 @@ function isActive(path: string): boolean {
<div class="h-[3px] bg-brand-600"></div> <div class="h-[3px] bg-brand-600"></div>
<header class="sticky top-0 z-20 border-b border-silver-200/70 bg-white/80 backdrop-blur-lg"> <header class="sticky top-0 z-20 border-b border-silver-200/70 bg-white/80 backdrop-blur-lg">
<div class="mx-auto flex max-w-3xl items-center justify-between px-4 py-3"> <div class="mx-auto flex max-w-3xl items-center justify-between px-4 py-3">
<div class="text-[15px] font-semibold tracking-tight text-brand-700">{{ t('app.title') }}</div> <div class="text-[18px] font-semibold tracking-tight text-brand-700">{{ t('app.title') }}</div>
<LoginBadge /> <LoginBadge />
</div> </div>
</header> </header>
......
...@@ -145,6 +145,7 @@ export interface PolicyCommissionYear { ...@@ -145,6 +145,7 @@ export interface PolicyCommissionYear {
status: CommissionStatus status: CommissionStatus
/** 保留/失效原因(财务登记,可能为空) */ /** 保留/失效原因(财务登记,可能为空) */
statusDesc?: string statusDesc?: string
stage?: string
} }
export interface PipelineItem { export interface PipelineItem {
......
...@@ -17,28 +17,28 @@ const open = ref(false) ...@@ -17,28 +17,28 @@ const open = ref(false)
const keyword = ref('') const keyword = ref('')
const selectedName = computed( const selectedName = computed(
() => brokers.value.find((b) => b.brokerBizId === selectedBizId.value)?.brokerName ?? '' () => brokers.value.find(b => b.brokerBizId === selectedBizId.value)?.brokerName ?? ''
) )
const filtered = computed(() => { const filtered = computed(() => {
const kw = keyword.value.trim().toLowerCase() const kw = keyword.value.trim().toLowerCase()
const all = kw const all = kw
? brokers.value.filter((b) => b.brokerName.toLowerCase().includes(kw)) ? brokers.value.filter(b => b.brokerName.toLowerCase().includes(kw))
: brokers.value : brokers.value
// 后端已按 hasStatement 倒序返回,这里分组保持顺序 // 后端已按 hasStatement 倒序返回,这里分组保持顺序
return { return {
withStatement: all.filter((b) => b.hasStatement), withStatement: all.filter(b => b.hasStatement),
rest: all.filter((b) => !b.hasStatement) rest: all.filter(b => !b.hasStatement)
} }
}) })
onMounted(async () => { onMounted(async () => {
try { // try {
brokers.value = await get<BrokerOption[]>('/c/dev/brokers') // brokers.value = await get<BrokerOption[]>('')
loaded.value = true // loaded.value = true
} catch (e) { // } catch (e) {
error.value = e instanceof Error ? e.message : 'error' // error.value = e instanceof Error ? e.message : 'error'
} // }
}) })
function toggle() { function toggle() {
...@@ -72,7 +72,7 @@ function pick(broker: BrokerOption) { ...@@ -72,7 +72,7 @@ function pick(broker: BrokerOption) {
type="text" type="text"
placeholder="搜索姓名…" placeholder="搜索姓名…"
class="w-full border-b border-amber-200 px-2.5 py-2 text-xs outline-none placeholder:text-slate-400" class="w-full border-b border-amber-200 px-2.5 py-2 text-xs outline-none placeholder:text-slate-400"
> />
<ul class="max-h-[50vh] overflow-y-auto py-1"> <ul class="max-h-[50vh] overflow-y-auto py-1">
<li <li
class="cursor-pointer px-2.5 py-1.5 text-slate-600 hover:bg-amber-50" class="cursor-pointer px-2.5 py-1.5 text-slate-600 hover:bg-amber-50"
...@@ -81,7 +81,10 @@ function pick(broker: BrokerOption) { ...@@ -81,7 +81,10 @@ function pick(broker: BrokerOption) {
— 未选择 — — 未选择 —
</li> </li>
<li v-if="filtered.withStatement.length" class="px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-amber-700"> <li
v-if="filtered.withStatement.length"
class="px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-amber-700"
>
有月结单 · {{ filtered.withStatement.length }} 有月结单 · {{ filtered.withStatement.length }}
</li> </li>
<li <li
...@@ -94,7 +97,10 @@ function pick(broker: BrokerOption) { ...@@ -94,7 +97,10 @@ function pick(broker: BrokerOption) {
{{ b.brokerName }} {{ b.brokerName }}
</li> </li>
<li v-if="filtered.rest.length" class="px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-slate-400"> <li
v-if="filtered.rest.length"
class="px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-slate-400"
>
其他有保单归属 · {{ filtered.rest.length }} 其他有保单归属 · {{ filtered.rest.length }}
</li> </li>
<li <li
...@@ -107,7 +113,12 @@ function pick(broker: BrokerOption) { ...@@ -107,7 +113,12 @@ function pick(broker: BrokerOption) {
{{ b.brokerName }} {{ b.brokerName }}
</li> </li>
<li v-if="filtered.withStatement.length + filtered.rest.length === 0" class="px-2.5 py-2 text-slate-400">无匹配</li> <li
v-if="filtered.withStatement.length + filtered.rest.length === 0"
class="px-2.5 py-2 text-slate-400"
>
无匹配
</li>
</ul> </ul>
</div> </div>
......
...@@ -18,15 +18,24 @@ function statusClass(status: PipelineItem['status']): string { ...@@ -18,15 +18,24 @@ function statusClass(status: PipelineItem['status']): string {
</script> </script>
<template> <template>
<div class="rounded-2xl border border-silver-200 bg-white p-4 shadow-card"> <div
class="rounded-2xl border border-silver-200 bg-white p-4 shadow-card"
v-if="item.expectedAmount > 0"
>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<div class="text-sm font-medium tracking-tight">{{ item.policyNo }}</div> <div class="text-sm font-medium tracking-tight">{{ item.policyNo }}</div>
<div class="mt-1 text-xs text-slate-500">{{ t('pipeline.payoutMonth') }} {{ item.payoutMonth }}</div> <div class="mt-1 text-xs text-slate-500">
{{ t('pipeline.payoutMonth') }} {{ item.payoutMonth }}
</div>
</div> </div>
<div class="text-right"> <div class="text-right">
<div class="tnum text-sm font-semibold">{{ formatDetailMoney(item.expectedAmount, item.currency) }}</div> <div class="tnum text-sm font-semibold">
<div class="mt-1 text-xs font-medium" :class="statusClass(item.status)">{{ t(`stage.${item.status}`) }}</div> 总保费: {{ formatDetailMoney(item.expectedAmount, item.currency) }}
</div>
<div class="mt-1 text-xs font-medium" :class="statusClass(item.status)">
{{ t(`stage.${item.status}`) }}
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -30,7 +30,9 @@ const statusTone = computed(() => (props.policy.status === 'LAPSED' ? 'neutral' ...@@ -30,7 +30,9 @@ const statusTone = computed(() => (props.policy.status === 'LAPSED' ? 'neutral'
<div class="min-w-0"> <div class="min-w-0">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="truncate text-sm font-medium tracking-tight">{{ policy.policyNo }}</span> <span class="truncate text-sm font-medium tracking-tight">{{ policy.policyNo }}</span>
<Badge v-if="showStatus" :tone="statusTone">{{ t(`policyStatus.${policy.status}`) }}</Badge> <Badge v-if="showStatus" :tone="statusTone">{{
t(`policyStatus.${policy.status}`)
}}</Badge>
</div> </div>
<div class="mt-1 truncate text-xs text-silver-600">{{ policy.productName || '—' }}</div> <div class="mt-1 truncate text-xs text-silver-600">{{ policy.productName || '—' }}</div>
<div v-if="policy.insurerName" class="mt-0.5 truncate text-xs text-silver-400"> <div v-if="policy.insurerName" class="mt-0.5 truncate text-xs text-silver-400">
...@@ -39,7 +41,7 @@ const statusTone = computed(() => (props.policy.status === 'LAPSED' ? 'neutral' ...@@ -39,7 +41,7 @@ const statusTone = computed(() => (props.policy.status === 'LAPSED' ? 'neutral'
</div> </div>
<div class="shrink-0 text-right"> <div class="shrink-0 text-right">
<div class="tnum text-sm font-semibold"> <div class="tnum text-sm font-semibold">
{{ formatDetailMoney(policy.fullPremium, policy.currency) }} 总保费: {{ formatDetailMoney(policy.fullPremium, policy.currency) }}
</div> </div>
<div class="mt-0.5 text-xs text-silver-400"> <div class="mt-0.5 text-xs text-silver-400">
{{ t('policies.myRatio') }} {{ policy.myRatio ? formatPercent(policy.myRatio) : '—' }} {{ t('policies.myRatio') }} {{ policy.myRatio ? formatPercent(policy.myRatio) : '—' }}
......
...@@ -4,7 +4,11 @@ import { useI18n } from 'vue-i18n' ...@@ -4,7 +4,11 @@ import { useI18n } from 'vue-i18n'
import { formatDetailMoney, formatHkd } from '@/utils/money' import { formatDetailMoney, formatHkd } from '@/utils/money'
import { formatPercent } from '@/utils/number' import { formatPercent } from '@/utils/number'
import { calcPremiumTotals } from '@/utils/premium' import { calcPremiumTotals } from '@/utils/premium'
import type { PaymentFrequency, StatementDetail as StatementDetailType, StatementItem } from '@/api/types' import type {
PaymentFrequency,
StatementDetail as StatementDetailType,
StatementItem
} from '@/api/types'
const props = defineProps<{ const props = defineProps<{
detail: StatementDetailType detail: StatementDetailType
...@@ -81,10 +85,13 @@ function rateText(rate: number): string { ...@@ -81,10 +85,13 @@ function rateText(rate: number): string {
</div> </div>
</div> </div>
</div> </div>
<p class="mt-2 text-[11px] text-silver-400">{{ t('statement.amountHint') }}</p> <p class="mt-2 text-[12px] text-silver-400">{{ t('statement.amountHint') }}</p>
<!-- 减项:没值就不显示 --> <!-- 减项:没值就不显示 -->
<dl v-if="hasMpf || hasAdjustment" class="mt-3 space-y-2 border-t border-silver-100 pt-3 text-sm"> <dl
v-if="hasMpf || hasAdjustment"
class="mt-3 space-y-2 border-t border-silver-100 pt-3 text-sm"
>
<div v-if="hasMpf"> <div v-if="hasMpf">
<div class="flex items-center justify-between gap-3"> <div class="flex items-center justify-between gap-3">
<dt class="text-silver-600">{{ t('statement.mpfItem') }}</dt> <dt class="text-silver-600">{{ t('statement.mpfItem') }}</dt>
...@@ -103,7 +110,10 @@ function rateText(rate: number): string { ...@@ -103,7 +110,10 @@ function rateText(rate: number): string {
</div> </div>
</dl> </dl>
<div v-if="detail.remark" class="mt-3 rounded-xl bg-silver-50 px-3 py-2 text-xs text-silver-600"> <div
v-if="detail.remark"
class="mt-3 rounded-xl bg-silver-50 px-3 py-2 text-xs text-silver-600"
>
<span class="font-medium">{{ t('statement.remark') }}</span> <span class="font-medium">{{ t('statement.remark') }}</span>
<p class="mt-1 whitespace-pre-line leading-relaxed">{{ detail.remark }}</p> <p class="mt-1 whitespace-pre-line leading-relaxed">{{ detail.remark }}</p>
</div> </div>
...@@ -165,7 +175,7 @@ function rateText(rate: number): string { ...@@ -165,7 +175,7 @@ function rateText(rate: number): string {
:key="item.id" :key="item.id"
:class="index ? 'mt-3 border-t border-silver-100 pt-3' : ''" :class="index ? 'mt-3 border-t border-silver-100 pt-3' : ''"
> >
<div class="flex items-start justify-between gap-3"> <div class="flex items-start justify-between gap-3" v-if="item.originalAmount > 0">
<div class="min-w-0"> <div class="min-w-0">
<div class="truncate text-sm font-medium">{{ item.policyNo }}</div> <div class="truncate text-sm font-medium">{{ item.policyNo }}</div>
<div class="mt-0.5 truncate text-xs text-silver-500"> <div class="mt-0.5 truncate text-xs text-silver-500">
...@@ -173,10 +183,10 @@ function rateText(rate: number): string { ...@@ -173,10 +183,10 @@ function rateText(rate: number): string {
</div> </div>
</div> </div>
<div class="shrink-0 text-right"> <div class="shrink-0 text-right">
<div class="tnum text-sm font-semibold"> <div class="tnum text-sm font-semibold">≈ {{ formatHkd(item.hkdAmount) }}</div>
<div class="tnum mt-0.5 text-xs text-silver-400">
{{ formatDetailMoney(item.originalAmount, item.originalCurrency) }} {{ formatDetailMoney(item.originalAmount, item.originalCurrency) }}
</div> </div>
<div class="tnum mt-0.5 text-xs text-silver-400">≈ {{ formatHkd(item.hkdAmount) }}</div>
</div> </div>
</div> </div>
...@@ -193,7 +203,9 @@ function rateText(rate: number): string { ...@@ -193,7 +203,9 @@ function rateText(rate: number): string {
</div> </div>
<div class="flex gap-1.5"> <div class="flex gap-1.5">
<dt class="shrink-0 text-silver-500">{{ t('statement.ratioShare') }}</dt> <dt class="shrink-0 text-silver-500">{{ t('statement.ratioShare') }}</dt>
<dd class="text-silver-700">{{ item.myRatio ? formatPercent(item.myRatio) : '—' }}</dd> <dd class="text-silver-700">
{{ item.myRatio ? formatPercent(item.myRatio) : '—' }}
</dd>
</div> </div>
<div class="flex gap-1.5"> <div class="flex gap-1.5">
<dt class="shrink-0 text-silver-500">{{ t('statement.policyRate') }}</dt> <dt class="shrink-0 text-silver-500">{{ t('statement.policyRate') }}</dt>
...@@ -203,6 +215,7 @@ function rateText(rate: number): string { ...@@ -203,6 +215,7 @@ function rateText(rate: number): string {
<dt class="shrink-0 text-silver-500">{{ t('statement.premiumTerm') }}</dt> <dt class="shrink-0 text-silver-500">{{ t('statement.premiumTerm') }}</dt>
<dd class="tnum text-silver-700">{{ premiumText(item) }}</dd> <dd class="tnum text-silver-700">{{ premiumText(item) }}</dd>
</div> </div>
<div v-if="item.remark" class="col-span-2 flex gap-1.5"> <div v-if="item.remark" class="col-span-2 flex gap-1.5">
<dt class="shrink-0 text-silver-500">{{ t('statement.itemRemark') }}</dt> <dt class="shrink-0 text-silver-500">{{ t('statement.itemRemark') }}</dt>
<dd class="text-silver-600">{{ item.remark }}</dd> <dd class="text-silver-600">{{ item.remark }}</dd>
......
...@@ -25,14 +25,14 @@ const { t } = useI18n() ...@@ -25,14 +25,14 @@ const { t } = useI18n()
<div class="min-w-0"> <div class="min-w-0">
<div class="flex items-baseline gap-2"> <div class="flex items-baseline gap-2">
<span class="text-sm font-medium tracking-tight">{{ statement.month || '—' }}</span> <span class="text-sm font-medium tracking-tight">{{ statement.month || '—' }}</span>
<span class="text-[11px] text-silver-400">{{ t('statement.salaryMonth') }}</span> <span class="text-[14px] text-silver-400">{{ t('statement.salaryMonth') }}</span>
</div> </div>
<div class="mt-1 truncate text-xs text-silver-500"> <div class="mt-1 truncate text-xs text-silver-500">
{{ t('statement.payDate') }} {{ statement.payDate || '—' }} {{ t('statement.payDate') }} {{ statement.payDate || '—' }}
</div> </div>
</div> </div>
<div class="shrink-0 text-right"> <div class="shrink-0 text-right">
<div class="text-[11px] text-silver-500"> <div class="text-[14px] text-silver-500">
{{ t('statement.gross') }} {{ t('statement.gross') }}
<span class="tnum">{{ formatHkd(statement.grossAmount) }}</span> <span class="tnum">{{ formatHkd(statement.grossAmount) }}</span>
</div> </div>
......
...@@ -20,12 +20,14 @@ const heroCard = computed(() => ...@@ -20,12 +20,14 @@ const heroCard = computed(() =>
: null : null
) )
const restCards = computed(() => { type RestCard = { label: string; value: string; to?: string }
const restCards = computed<RestCard[]>(() => {
if (!metrics.value) return [] if (!metrics.value) return []
return [ return [
{ label: t('metric.taxYearPaid'), value: formatHkd(metrics.value.taxYearPaidHkd) }, { label: t('metric.taxYearPaid'), value: formatHkd(metrics.value.taxYearPaidHkd) },
{ label: t('metric.pipeline'), value: formatHkd(metrics.value.pipelineHkd) }, { label: t('metric.pipeline'), value: formatHkd(metrics.value.pipelineHkd), to: '/pipeline' },
{ label: t('metric.inforceCount'), value: String(metrics.value.inforceCount) }, { label: t('metric.inforceCount'), value: String(metrics.value.inforceCount), to: '/policies' },
{ label: t('metric.firstYearFyp'), value: formatHkd(metrics.value.firstYearFypHkd) } { label: t('metric.firstYearFyp'), value: formatHkd(metrics.value.firstYearFypHkd) }
] ]
}) })
...@@ -63,9 +65,19 @@ onMounted(load) ...@@ -63,9 +65,19 @@ onMounted(load)
<ApiLoader :loading="loading" :error="error" @retry="load"> <ApiLoader :loading="loading" :error="error" @retry="load">
<MetricCard v-if="heroCard" feature :label="heroCard.label" :value="heroCard.value" /> <MetricCard v-if="heroCard" feature :label="heroCard.label" :value="heroCard.value" />
<div class="mt-3 grid grid-cols-2 gap-3"> <div class="mt-3 grid grid-cols-2 gap-3">
<MetricCard v-for="card in restCards" :key="card.label" :label="card.label" :value="card.value" /> <!-- <MetricCard
v-for="card in restCards"
:key="card.label"
:label="card.label"
:value="card.value"
/> -->
<template v-for="card in restCards" :key="card.label">
<router-link v-if="card.to" :to="card.to" class="block">
<MetricCard :label="card.label" :value="card.value" />
</router-link>
<MetricCard v-else :label="card.label" :value="card.value" />
</template>
</div> </div>
<router-link <router-link
v-if="metrics" v-if="metrics"
to="/customers" to="/customers"
...@@ -73,37 +85,58 @@ onMounted(load) ...@@ -73,37 +85,58 @@ onMounted(load)
> >
<div> <div>
<div class="text-xs text-slate-500">{{ t('metric.myCustomers') }}</div> <div class="text-xs text-slate-500">{{ t('metric.myCustomers') }}</div>
<div class="tnum mt-2 text-xl font-semibold tracking-tight text-slate-900">{{ metrics.caseCount }}</div> <div class="tnum mt-2 text-xl font-semibold tracking-tight text-slate-900">
{{ metrics.caseCount }}
</div>
</div> </div>
<div class="flex items-center gap-1 text-xs text-slate-400"> <div class="flex items-center gap-1 text-xs text-slate-400">
{{ t('customer.followingHint', { count: metrics.followingCount }) }} {{ t('customer.followingHint', { count: metrics.followingCount }) }}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4"> <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-4 w-4"
>
<polyline points="9 18 15 12 9 6" /> <polyline points="9 18 15 12 9 6" />
</svg> </svg>
</div> </div>
</router-link> </router-link>
<section class="mt-7"> <!-- <section class="mt-7">
<div class="mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2">
<h2 class="text-[13px] font-semibold tracking-wide text-silver-600">{{ t('dashboard.actions') }}</h2> <h2 class="text-[13px] font-semibold tracking-wide text-silver-600">
{{ t('dashboard.actions') }}
</h2>
<span <span
v-if="todoDataSource === 'mock'" v-if="todoDataSource === 'mock'"
class="rounded-full bg-amber-50 px-2 py-0.5 text-[11px] font-medium text-amber-700" class="rounded-full bg-amber-50 px-2 py-0.5 text-[11px] font-medium text-amber-700"
>{{ t('todo.sample') }}</span> >{{ t('todo.sample') }}</span
>
</div> </div>
<div class="mb-3 flex flex-wrap gap-2 text-xs text-slate-500"> <div class="mb-3 flex flex-wrap gap-2 text-xs text-slate-500">
<span class="rounded-full bg-slate-100 px-2.5 py-1">{{ t('todo.renewal') }} {{ countByType.renewal }}</span> <span class="rounded-full bg-slate-100 px-2.5 py-1"
<span class="rounded-full bg-slate-100 px-2.5 py-1">{{ t('todo.lapse') }} {{ countByType.lapse }}</span> >{{ t('todo.renewal') }} {{ countByType.renewal }}</span
<span class="rounded-full bg-slate-100 px-2.5 py-1">{{ t('todo.birthday') }} {{ countByType.birthday }}</span> >
<span class="rounded-full bg-slate-100 px-2.5 py-1"
>{{ t('todo.lapse') }} {{ countByType.lapse }}</span
>
<span class="rounded-full bg-slate-100 px-2.5 py-1"
>{{ t('todo.birthday') }} {{ countByType.birthday }}</span
>
</div> </div>
<div class="space-y-3"> <div class="space-y-3">
1111
<TodoCard v-for="todo in todos" :key="todo.id" :todo="todo" /> <TodoCard v-for="todo in todos" :key="todo.id" :todo="todo" />
<div class="rounded-2xl border border-dashed border-silver-200 bg-white/60 p-4"> <div class="rounded-2xl border border-dashed border-silver-200 bg-white/60 p-4">
<div class="text-sm font-medium">{{ t('todo.claim') }}</div> <div class="text-sm font-medium">{{ t('todo.claim') }}</div>
<div class="mt-1 text-xs text-slate-400">{{ t('todo.claimPlaceholder') }}</div> <div class="mt-1 text-xs text-slate-400">{{ t('todo.claimPlaceholder') }}</div>
</div> </div>
</div> </div>
</section> </section> -->
</ApiLoader> </ApiLoader>
</div> </div>
</template> </template>
...@@ -42,7 +42,11 @@ onMounted(load) ...@@ -42,7 +42,11 @@ onMounted(load)
<template> <template>
<div class="space-y-4"> <div class="space-y-4">
<div class="rounded-2xl border border-amber-100 bg-amber-50 px-4 py-3 text-xs font-medium text-amber-700">{{ t('pipeline.adjustNote') }}</div> <div
class="rounded-2xl border border-amber-100 bg-amber-50 px-4 py-3 text-xs font-medium text-amber-700"
>
{{ t('pipeline.adjustNote') }}
</div>
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
<label class="block"> <label class="block">
...@@ -51,26 +55,58 @@ onMounted(load) ...@@ -51,26 +55,58 @@ onMounted(load)
v-model="policyQuery" v-model="policyQuery"
type="search" type="search"
:placeholder="t('pipeline.filterPolicyPlaceholder')" :placeholder="t('pipeline.filterPolicyPlaceholder')"
class="w-full rounded-xl border border-silver-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition-colors placeholder:text-silver-400 focus:border-brand-200" class="w-full rounded-xl border border-silver-200 bg-white px-3 py-2 text-base text-slate-900 outline-none transition-colors placeholder:text-silver-400 focus:border-brand-200"
> />
</label> </label>
<!-- <label class="block">
<span class="mb-1 block text-xs text-slate-500">{{ t('pipeline.filterMonth') }}</span>
<select
v-model="selectedMonth"
class="w-full rounded-xl border border-silver-200 bg-white px-3 py-2 text-slate-900 outline-none transition-colors focus:border-brand-200"
>
<option value="">{{ t('pipeline.allMonths') }}</option>
<option v-for="month in months" :key="month" :value="month">{{ month }}</option>
</select>
</label> -->
<label class="block"> <label class="block">
<span class="mb-1 block text-xs text-slate-500">{{ t('pipeline.filterMonth') }}</span> <span class="mb-1 block text-xs text-slate-500">{{ t('pipeline.filterMonth') }}</span>
<div class="relative">
<select <select
v-model="selectedMonth" v-model="selectedMonth"
class="w-full rounded-xl border border-silver-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none transition-colors focus:border-brand-200" class="w-full appearance-none rounded-xl border border-silver-200 bg-white px-3 py-2 pr-10 text-base text-slate-900 outline-none transition-colors focus:border-brand-200"
> >
<option value="">{{ t('pipeline.allMonths') }}</option> <option value="">{{ t('pipeline.allMonths') }}</option>
<option v-for="month in months" :key="month" :value="month">{{ month }}</option> <option v-for="month in months" :key="month" :value="month">{{ month }}</option>
</select> </select>
<!-- 自定义箭头:right-3 就是箭头离右边框的间隔,想大改这里 -->
<svg
class="pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-silver-400"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</div>
</label> </label>
</div> </div>
<ApiLoader :loading="loading" :error="error" :empty="!loading && !error && items.length === 0" @retry="load"> <ApiLoader
:loading="loading"
:error="error"
:empty="!loading && !error && items.length === 0"
@retry="load"
>
<div v-if="filtered.length" class="space-y-3"> <div v-if="filtered.length" class="space-y-3">
<PipelineCard v-for="item in filtered" :key="item.id" :item="item" /> <PipelineCard v-for="item in filtered" :key="item.id" :item="item" />
</div> </div>
<div v-else class="py-10 text-center text-sm text-slate-400">{{ t('pipeline.noResult') }}</div> <div v-else class="py-10 text-center text-sm text-slate-400">
{{ t('pipeline.noResult') }}
</div>
</ApiLoader> </ApiLoader>
</div> </div>
</template> </template>
...@@ -18,8 +18,8 @@ const modalError = ref<string | null>(null) ...@@ -18,8 +18,8 @@ const modalError = ref<string | null>(null)
const commissions = ref<PolicyCommissionYear[]>([]) const commissions = ref<PolicyCommissionYear[]>([])
const selectedPolicyNo = ref('') const selectedPolicyNo = ref('')
const inforce = computed(() => policies.value.filter((p) => p.status === 'INFORCE')) const inforce = computed(() => policies.value.filter(p => p.status === 'INFORCE'))
const inactive = computed(() => policies.value.filter((p) => p.status !== 'INFORCE')) const inactive = computed(() => policies.value.filter(p => p.status !== 'INFORCE'))
async function load() { async function load() {
loading.value = true loading.value = true
...@@ -59,19 +59,38 @@ onMounted(load) ...@@ -59,19 +59,38 @@ onMounted(load)
</script> </script>
<template> <template>
<ApiLoader :loading="loading" :error="error" :empty="!loading && !error && policies.length === 0" @retry="load"> <ApiLoader
:loading="loading"
:error="error"
:empty="!loading && !error && policies.length === 0"
@retry="load"
>
<div class="space-y-6"> <div class="space-y-6">
<section> <section>
<h2 class="mb-3 text-[13px] font-semibold tracking-wide text-silver-600">{{ t('policies.inforce') }}</h2> <h2 class="mb-3 text-[13px] font-semibold tracking-wide text-silver-600">
{{ t('policies.inforce') }}
</h2>
<div class="space-y-3"> <div class="space-y-3">
<PolicyCard v-for="policy in inforce" :key="policy.policyNo" :policy="policy" @select="openCommissions" /> <PolicyCard
v-for="policy in inforce"
:key="policy.policyNo"
:policy="policy"
@select="openCommissions"
/>
</div> </div>
</section> </section>
<section v-if="inactive.length"> <section v-if="inactive.length">
<h2 class="mb-3 text-[13px] font-semibold tracking-wide text-silver-600">{{ t('policies.inactive') }}</h2> <h2 class="mb-3 text-[13px] font-semibold tracking-wide text-silver-600">
{{ t('policies.inactive') }}
</h2>
<div class="space-y-3"> <div class="space-y-3">
<PolicyCard v-for="policy in inactive" :key="policy.policyNo" :policy="policy" @select="openCommissions" /> <PolicyCard
v-for="policy in inactive"
:key="policy.policyNo"
:policy="policy"
@select="openCommissions"
/>
</div> </div>
</section> </section>
</div> </div>
...@@ -90,10 +109,16 @@ onMounted(load) ...@@ -90,10 +109,16 @@ onMounted(load)
:key="`${item.year}-${item.status}-${index}`" :key="`${item.year}-${item.status}-${index}`"
class="flex items-center justify-between gap-3 text-sm" class="flex items-center justify-between gap-3 text-sm"
> >
<span>{{ item.year }} · {{ item.type }}</span> <span
>{{ item.year }} · {{ item.type }}
<span v-if="item.status == 'PIPELINE'">(预估)</span>
</span>
<span class="text-right"> <span class="text-right">
<span class="tnum">{{ formatDetailMoney(item.amount, item.currency) }}</span> · {{ t(`stage.${item.status}`) }} <span class="tnum">{{ formatDetailMoney(item.amount, item.currency) }}</span> ·
<span v-if="item.statusDesc" class="block text-xs text-slate-400">{{ item.statusDesc }}</span> {{ t(`stage.${item.status}`) }}
<span v-if="item.statusDesc" class="block text-xs text-slate-400">{{
item.statusDesc
}}</span>
</span> </span>
</div> </div>
</div> </div>
......
...@@ -47,6 +47,11 @@ export default { ...@@ -47,6 +47,11 @@ export default {
borderRadius: { borderRadius: {
xl: '0.75rem', xl: '0.75rem',
'2xl': '1rem' '2xl': '1rem'
},
fontSize: {
xs: ['.9375rem', { lineHeight: '1.25rem' }], // 13px + 20px 行高
sm: ['1.125rem'],
lg: ['1.25rem', { lineHeight: '1.25rem' }] // 13px + 20px 行高
} }
} }
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment