first
This commit is contained in:
113
src/views/home/cpns/HomeBusinessCards.vue
Normal file
113
src/views/home/cpns/HomeBusinessCards.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<script setup lang="ts">
|
||||
import type { BusinessLine } from '@/types/business/home'
|
||||
|
||||
interface Props {
|
||||
lines: BusinessLine[]
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-business">
|
||||
<div class="home-business__head">
|
||||
<h3 class="home-business__title">
|
||||
业务服务
|
||||
</h3>
|
||||
<span class="home-business__slogan text-secondary">研发智造一体化自营平台,全链路质量兜底</span>
|
||||
</div>
|
||||
<div class="home-business__grid">
|
||||
<RouterLink
|
||||
v-for="line in lines"
|
||||
:key="line.id"
|
||||
:to="`/business/${line.id}`"
|
||||
class="home-business__card"
|
||||
>
|
||||
<div class="home-business__icon">
|
||||
<!-- TODO(蓝湖): 替换业务图标切图 -->
|
||||
<span>{{ line.name.slice(0, 2) }}</span>
|
||||
</div>
|
||||
<h4 class="home-business__name">
|
||||
{{ line.name }}
|
||||
</h4>
|
||||
<p class="home-business__desc text-secondary">
|
||||
{{ line.desc }}
|
||||
</p>
|
||||
<span class="home-business__more">了解详细 ></span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-business {
|
||||
&__head {
|
||||
.flex(row, space-between);
|
||||
margin-bottom: @spacing-base;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: @font-size-xl;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__slogan {
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: @spacing-base;
|
||||
}
|
||||
|
||||
&__card {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-sm;
|
||||
padding: @spacing-lg;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: @shadow-lg;
|
||||
transform: translateY(-2px);
|
||||
|
||||
.home-business__more {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
.flex(row, center);
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: @radius-base;
|
||||
background: @primary-light;
|
||||
color: @primary-color;
|
||||
font-size: @font-size-base;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: @font-size-lg;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
min-height: 40px;
|
||||
font-size: @font-size-sm;
|
||||
.multi-ellipsis(2);
|
||||
}
|
||||
|
||||
&__more {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-secondary;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
106
src/views/home/cpns/HomeCaseShowcase.vue
Normal file
106
src/views/home/cpns/HomeCaseShowcase.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { CaseCard } from '@/components'
|
||||
import type { BusinessType } from '@/types/api'
|
||||
import type { Case } from '@/types/business/cases'
|
||||
|
||||
interface Props {
|
||||
cases: Case[]
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{ categoryChange: [category: BusinessType | 'all'] }>()
|
||||
|
||||
const activeCategory = ref<BusinessType | 'all'>('all')
|
||||
|
||||
const categories: Array<{ label: string; value: BusinessType | 'all' }> = [
|
||||
{ label: '全部', value: 'all' },
|
||||
{ label: '互联网软件', value: 'internet' },
|
||||
{ label: '硬件电路', value: 'hardware' },
|
||||
{ label: '物联网全案', value: 'iot' },
|
||||
{ label: '生产制造', value: 'manufacturing' },
|
||||
]
|
||||
|
||||
function switchCategory(value: BusinessType | 'all'): void {
|
||||
activeCategory.value = value
|
||||
emit('categoryChange', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-cases">
|
||||
<div class="home-cases__head">
|
||||
<h3 class="home-cases__title">
|
||||
案例库精选
|
||||
</h3>
|
||||
<div class="home-cases__tabs">
|
||||
<button
|
||||
v-for="cat in categories"
|
||||
:key="cat.value"
|
||||
class="home-cases__tab"
|
||||
:class="{ 'is-active': activeCategory === cat.value }"
|
||||
@click="switchCategory(cat.value)"
|
||||
>
|
||||
{{ cat.label }}
|
||||
</button>
|
||||
</div>
|
||||
<RouterLink to="/cases" class="home-cases__more link">
|
||||
查看更多 >
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="home-cases__grid">
|
||||
<CaseCard
|
||||
v-for="item in cases"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
@view="$router.push(`/cases/${$event}`)"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-cases {
|
||||
&__head {
|
||||
.flex(row, space-between);
|
||||
margin-bottom: @spacing-base;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: @font-size-xl;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__tabs {
|
||||
.flex(row, center);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
&__tab {
|
||||
height: 30px;
|
||||
padding: 0 @spacing-base;
|
||||
border-radius: @radius-round;
|
||||
background: @white;
|
||||
color: @text-color;
|
||||
font-size: @font-size-sm;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-active {
|
||||
background: @primary-color;
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
|
||||
&__more {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: @spacing-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
70
src/views/home/cpns/HomeQuickEntries.vue
Normal file
70
src/views/home/cpns/HomeQuickEntries.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
// 快捷入口为固定模块链接(纯 UI,静态数据)
|
||||
const entries = [
|
||||
{ label: '财务台账', path: '/finance/bills', icon: '💰' },
|
||||
{ label: '合同台账', path: '/contract', icon: '📄' },
|
||||
{ label: '客服工作台', path: '/service', icon: '💬' },
|
||||
{ label: '案例库管理', path: '/cases', icon: '📁' },
|
||||
{ label: '工单需求池', path: '/demand', icon: '📋' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-quick">
|
||||
<h3 class="home-quick__title">
|
||||
快捷入口
|
||||
</h3>
|
||||
<div class="home-quick__list">
|
||||
<RouterLink
|
||||
v-for="entry in entries"
|
||||
:key="entry.label"
|
||||
:to="entry.path"
|
||||
class="home-quick__item"
|
||||
>
|
||||
<span class="home-quick__icon">{{ entry.icon }}</span>
|
||||
<span class="home-quick__label">{{ entry.label }}</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-quick {
|
||||
&__title {
|
||||
margin-bottom: @spacing-base;
|
||||
font-size: @font-size-lg;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__list {
|
||||
.flex(row, space-between);
|
||||
gap: @spacing-base;
|
||||
}
|
||||
|
||||
&__item {
|
||||
.flex(column, center);
|
||||
gap: @spacing-sm;
|
||||
flex: 1;
|
||||
padding: @spacing-base;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: @shadow-lg;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: @font-size-base;
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
src/views/home/cpns/HomeServiceTabs.vue
Normal file
129
src/views/home/cpns/HomeServiceTabs.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { ServiceType } from '@/types/business/home'
|
||||
|
||||
interface Props {
|
||||
serviceTypes: ServiceType[]
|
||||
serviceContent: string
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const activeType = ref(0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-service">
|
||||
<div class="home-service__head">
|
||||
<h3 class="home-service__title">
|
||||
服务内容
|
||||
</h3>
|
||||
<div class="home-service__types">
|
||||
<button
|
||||
v-for="(type, index) in serviceTypes"
|
||||
:key="type.label"
|
||||
class="home-service__type"
|
||||
:class="{ 'is-active': activeType === index }"
|
||||
@click="activeType = index"
|
||||
>
|
||||
{{ type.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="home-service__type-desc text-secondary">
|
||||
{{ serviceTypes[activeType]?.desc }}
|
||||
</p>
|
||||
|
||||
<div class="home-service__content">
|
||||
<pre class="home-service__text">{{ serviceContent }}</pre>
|
||||
<div class="home-service__video">
|
||||
<!-- TODO(蓝湖): 接入真实视频源 -->
|
||||
<span class="home-service__video-tip">视频将在预览时播放</span>
|
||||
<span class="home-service__video-time">0:00 / 0:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-service {
|
||||
padding: @spacing-lg @spacing-xl;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
|
||||
&__head {
|
||||
.flex(row, space-between);
|
||||
margin-bottom: @spacing-sm;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: @font-size-xl;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__types {
|
||||
.flex(row, center);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
&__type {
|
||||
height: 30px;
|
||||
padding: 0 @spacing-base;
|
||||
border-radius: @radius-round;
|
||||
background: @bg-color;
|
||||
color: @text-color;
|
||||
font-size: @font-size-sm;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-active {
|
||||
background: @primary-color;
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
|
||||
&__type-desc {
|
||||
margin-bottom: @spacing-base;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&__content {
|
||||
.flex(row, flex-start);
|
||||
gap: @spacing-lg;
|
||||
}
|
||||
|
||||
&__text {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
padding: @spacing-base;
|
||||
border-radius: @radius-base;
|
||||
background: @bg-color-light;
|
||||
font-family: inherit;
|
||||
font-size: @font-size-sm;
|
||||
line-height: 1.8;
|
||||
color: @text-color;
|
||||
white-space: pre-wrap;
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
.scrollbar();
|
||||
}
|
||||
|
||||
&__video {
|
||||
.flex(column, center);
|
||||
gap: @spacing-sm;
|
||||
width: 320px;
|
||||
height: 200px;
|
||||
border-radius: @radius-base;
|
||||
background: @heading-color;
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&__video-time {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-disabled;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
55
src/views/home/cpns/HomeStats.vue
Normal file
55
src/views/home/cpns/HomeStats.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import type { HomeStats } from '@/types/business/home'
|
||||
|
||||
interface Props {
|
||||
stats: HomeStats
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const items = [
|
||||
{ key: 'pending', label: '待您处理' },
|
||||
{ key: 'inProgress', label: '进行中' },
|
||||
{ key: 'total', label: '累计项目' },
|
||||
] as const
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-stats">
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.key"
|
||||
class="home-stats__item"
|
||||
>
|
||||
<span class="home-stats__value">{{ stats[item.key] }}</span>
|
||||
<span class="home-stats__label text-secondary">{{ item.label }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-stats {
|
||||
.flex(row, space-between);
|
||||
gap: @spacing-base;
|
||||
|
||||
&__item {
|
||||
.flex(column, center);
|
||||
flex: 1;
|
||||
gap: @spacing-xs;
|
||||
padding: @spacing-base @spacing-lg;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
}
|
||||
|
||||
&__value {
|
||||
font-size: @font-size-xxl;
|
||||
font-weight: 600;
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
74
src/views/home/cpns/HomeWelcome.vue
Normal file
74
src/views/home/cpns/HomeWelcome.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
summary: string
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const greeting = computed(() => {
|
||||
const hour = new Date().getHours()
|
||||
if (hour < 6) return '夜深了'
|
||||
if (hour < 11) return '早上好'
|
||||
if (hour < 14) return '中午好'
|
||||
if (hour < 18) return '下午好'
|
||||
return '晚上好'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="home-welcome">
|
||||
<div class="home-welcome__info">
|
||||
<h2 class="home-welcome__greeting">
|
||||
{{ greeting }}
|
||||
</h2>
|
||||
<p class="home-welcome__summary text-secondary">
|
||||
{{ summary }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="home-welcome__brand">
|
||||
<!-- TODO(蓝湖): 替换头像切图 -->
|
||||
<span class="home-welcome__avatar">王</span>
|
||||
<span class="home-welcome__appName">虫子智造</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home-welcome {
|
||||
.flex(row, space-between);
|
||||
padding: @spacing-lg @spacing-xl;
|
||||
border-radius: @radius-lg;
|
||||
background: linear-gradient(120deg, @primary-color, @primary-hover);
|
||||
color: @white;
|
||||
|
||||
&__greeting {
|
||||
font-size: @font-size-xxl;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__summary {
|
||||
margin-top: @spacing-xs;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
&__brand {
|
||||
.flex(row, center);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
.flex(row, center);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: @radius-round;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
font-size: @font-size-lg;
|
||||
}
|
||||
|
||||
&__appName {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
108
src/views/home/detail.vue
Normal file
108
src/views/home/detail.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
// 业务详情页:数据只经 useHomeStore,不直接 import api
|
||||
import { useHomeStore } from '@/stores/modules/home'
|
||||
import type { BusinessType } from '@/types/api'
|
||||
import HomeServiceTabs from './cpns/HomeServiceTabs.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const homeStore = useHomeStore()
|
||||
|
||||
const line = computed(() => homeStore.currentBusiness)
|
||||
const businessType = computed(() => route.params.type as BusinessType)
|
||||
|
||||
function load(): void {
|
||||
void homeStore.fetchBusinessDetail(businessType.value)
|
||||
}
|
||||
|
||||
watch(businessType, load)
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="business-detail">
|
||||
<nav class="business-detail__breadcrumb text-secondary">
|
||||
<RouterLink to="/" class="link">
|
||||
首页
|
||||
</RouterLink>
|
||||
<span> > </span>
|
||||
<span>业务详情</span>
|
||||
</nav>
|
||||
|
||||
<template v-if="line">
|
||||
<header class="business-detail__hero">
|
||||
<span class="business-detail__logo">
|
||||
<!-- TODO(蓝湖): 替换业务图标切图 -->
|
||||
{{ line.name.slice(0, 2) }}
|
||||
</span>
|
||||
<div class="business-detail__intro">
|
||||
<h1 class="business-detail__name">
|
||||
{{ line.name }}
|
||||
</h1>
|
||||
<p class="business-detail__slogan text-secondary">
|
||||
{{ line.slogan }}
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<HomeServiceTabs
|
||||
:service-types="line.serviceTypes"
|
||||
:service-content="line.serviceContent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<p v-else class="text-secondary">
|
||||
正在加载业务详情...
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.business-detail {
|
||||
padding-top: @spacing-lg;
|
||||
padding-bottom: @spacing-xxl;
|
||||
|
||||
&__breadcrumb {
|
||||
margin-bottom: @spacing-base;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
&__hero {
|
||||
.flex(row, flex-start);
|
||||
gap: @spacing-base;
|
||||
margin-bottom: @spacing-xl;
|
||||
padding: @spacing-xl;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
.flex(row, center);
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: @radius-lg;
|
||||
background: @primary-light;
|
||||
color: @primary-color;
|
||||
font-size: @font-size-xl;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__intro {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-xs;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: @font-size-xxl;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__slogan {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
7
src/views/home/index.ts
Normal file
7
src/views/home/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export { default } from './index.vue'
|
||||
export { default as HomeWelcome } from './cpns/HomeWelcome.vue'
|
||||
export { default as HomeStats } from './cpns/HomeStats.vue'
|
||||
export { default as HomeQuickEntries } from './cpns/HomeQuickEntries.vue'
|
||||
export { default as HomeBusinessCards } from './cpns/HomeBusinessCards.vue'
|
||||
export { default as HomeCaseShowcase } from './cpns/HomeCaseShowcase.vue'
|
||||
export { default as HomeServiceTabs } from './cpns/HomeServiceTabs.vue'
|
||||
58
src/views/home/index.vue
Normal file
58
src/views/home/index.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
// 页面容器:只做组件引入、props 分发、事件中转,数据只经 store
|
||||
import { useHomeStore } from '@/stores/modules/home'
|
||||
import type { BusinessType } from '@/types/api'
|
||||
import HomeWelcome from './cpns/HomeWelcome.vue'
|
||||
import HomeStats from './cpns/HomeStats.vue'
|
||||
import HomeQuickEntries from './cpns/HomeQuickEntries.vue'
|
||||
import HomeBusinessCards from './cpns/HomeBusinessCards.vue'
|
||||
import HomeCaseShowcase from './cpns/HomeCaseShowcase.vue'
|
||||
import HomeServiceTabs from './cpns/HomeServiceTabs.vue'
|
||||
|
||||
const homeStore = useHomeStore()
|
||||
const { stats, businessLines, featuredCases } = storeToRefs(homeStore)
|
||||
|
||||
const todaySummary = computed(() => `今天有${stats.value.inProgress}个项目正在进行`)
|
||||
|
||||
// 服务 Tab 展示互联网软件线内容(服务内容区默认锚点)
|
||||
const serviceLine = computed(
|
||||
() => businessLines.value.find((line) => line.id === 'internet') ?? businessLines.value[0],
|
||||
)
|
||||
|
||||
function onCategoryChange(category: BusinessType | 'all'): void {
|
||||
void homeStore.fetchFeaturedCases(category)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void homeStore.fetchHomeData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="home">
|
||||
<HomeWelcome :summary="todaySummary" />
|
||||
<HomeStats :stats="stats" />
|
||||
<HomeQuickEntries />
|
||||
<HomeBusinessCards :lines="businessLines" />
|
||||
<HomeCaseShowcase
|
||||
:cases="featuredCases"
|
||||
@category-change="onCategoryChange"
|
||||
/>
|
||||
<HomeServiceTabs
|
||||
v-if="serviceLine"
|
||||
:service-types="serviceLine.serviceTypes"
|
||||
:service-content="serviceLine.serviceContent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.home {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-xl;
|
||||
padding-top: @spacing-xl;
|
||||
padding-bottom: @spacing-xxl;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user