feat:首页部分页面

This commit is contained in:
李伊帆
2026-09-09 17:48:56 +08:00
parent f44e6ce1a1
commit 5b31eac508
32 changed files with 1084 additions and 3 deletions

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { ref } from 'vue'
import { navigateToResultPage } from '@/utils/navigate-result'
import LoginInput from './components/LoginInput.vue'
const phone = ref('')
@@ -21,8 +20,8 @@ function handleLogin() {
return
}
// TODO: 接入登录接口后,在接口返回失败时调用
navigateToResultPage('loginFailed')
// TODO: 接入登录接口,失败时调用 navigateToResultPage('loginFailed')
uni.redirectTo({ url: '/pages/home-index/index' })
}
function handleForgotPassword() {

View File

@@ -20,6 +20,9 @@ function handleLogin() {
uni.showToast({ title: '请输入手机号和验证码', icon: 'none' })
return
}
// TODO: 接入登录接口
uni.redirectTo({ url: '/pages/home-index/index' })
}
function handlePasswordLogin() {

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import AppTabBar from '@/components/AppTabBar.vue'
</script>
<template>
<view class="placeholder-page">
<text class="placeholder-page__title">
案例库
</text>
<text class="placeholder-page__desc">
功能开发中
</text>
<AppTabBar active="case" />
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.placeholder-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
background: $color-bg-page;
}
.placeholder-page__title {
font-size: 36rpx;
font-weight: 600;
color: $color-text-primary;
}
.placeholder-page__desc {
margin-top: 16rpx;
font-size: 28rpx;
color: $color-text-secondary;
}
</style>

View File

@@ -0,0 +1,162 @@
<script setup lang="ts">
import type { ProjectItem } from '@/types/home'
defineProps<{
item: ProjectItem
}>()
</script>
<template>
<view class="project-card">
<view class="project-card__header">
<text class="project-card__title">
{{ item.title }}
</text>
<text class="project-card__status">
{{ item.status }}
</text>
</view>
<view class="project-card__meta">
<text
class="project-card__tag"
:class="`project-card__tag--${item.tagTheme || 'orange'}`"
>
{{ item.category }}
</text>
<text class="project-card__no">
项目编号:{{ item.projectNo }}
</text>
</view>
<view class="project-card__progress-row">
<text class="project-card__progress-label">
进行中
</text>
<text class="project-card__progress-value">
{{ item.progress }}%
</text>
</view>
<view class="project-card__progress-bar">
<view
class="project-card__progress-fill"
:style="{ width: `${item.progress}%` }"
/>
</view>
<view class="project-card__footer">
<text class="project-card__time">
更新时间:{{ item.updateTime }}
</text>
<text class="project-card__detail">
查看详情 >
</text>
</view>
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.project-card {
padding: 28rpx;
margin-top: 20rpx;
background: $color-bg-page;
border-radius: 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.project-card__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.project-card__title {
flex: 1;
padding-right: 16rpx;
font-size: 30rpx;
font-weight: 600;
color: $color-text-primary;
}
.project-card__status {
flex-shrink: 0;
font-size: 24rpx;
color: $color-text-secondary;
}
.project-card__meta {
display: flex;
align-items: center;
margin-top: 16rpx;
}
.project-card__tag {
flex-shrink: 0;
padding: 4rpx 12rpx;
font-size: 20rpx;
border-radius: 6rpx;
&--orange {
color: $color-tag-orange;
background: $color-tag-orange-bg;
}
&--peach {
color: #e07b4a;
background: #fff0e8;
}
}
.project-card__no {
margin-left: 12rpx;
font-size: 22rpx;
color: $color-text-secondary;
}
.project-card__progress-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 24rpx;
}
.project-card__progress-label,
.project-card__progress-value {
font-size: 24rpx;
color: $color-text-secondary;
}
.project-card__progress-bar {
height: 12rpx;
margin-top: 12rpx;
overflow: hidden;
background: #eef2ff;
border-radius: 6rpx;
}
.project-card__progress-fill {
height: 100%;
background: $color-primary;
border-radius: 6rpx;
}
.project-card__footer {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
}
.project-card__time {
font-size: 22rpx;
color: $color-text-secondary;
}
.project-card__detail {
font-size: 24rpx;
color: $color-text-link;
}
</style>

View File

@@ -0,0 +1,109 @@
<script setup lang="ts">
import type { ServiceItem } from '@/types/home'
defineProps<{
item: ServiceItem
}>()
</script>
<template>
<view
class="service-card"
:class="[
`service-card--${item.theme}`,
{ 'service-card--with-illus': item.illus },
]"
>
<image
v-if="item.illus"
class="service-card__illus"
:src="item.illus"
mode="aspectFit"
/>
<view class="service-card__content">
<text class="service-card__title">
{{ item.title }}
</text>
<text class="service-card__desc">
{{ item.desc }}
</text>
<text class="service-card__link">
了解详细 >
</text>
</view>
</view>
</template>
<style scoped lang="scss">
.service-card {
position: relative;
display: flex;
height: 240rpx;
padding: 28rpx 24rpx 24rpx;
overflow: hidden;
border-radius: 20rpx;
box-sizing: border-box;
&--with-illus {
overflow: visible;
}
&--blue {
background: linear-gradient(180deg, #D3E1FC 0%, #FFFFFF 100%);
}
&--green {
background: linear-gradient( 180deg, #B7EDEA 0%, #FFFFFF 100%);
}
&--pink {
background: linear-gradient( 180deg, #FFECE1 0%, #FFFFFF 100%);
}
&--orange {
background: linear-gradient( 180deg, #F7D3C6 0%, #FFFFFF 100%);
}
}
.service-card__illus {
position: absolute;
top: -36rpx;
right: -10rpx;
z-index: 2;
width: 152rpx;
height: 152rpx;
pointer-events: none;
}
.service-card__content {
position: relative;
z-index: 1;
display: flex;
flex: 1;
flex-direction: column;
width: 100%;
}
.service-card__title {
font-size: 30rpx;
font-weight: 600;
color: #1a1a1a;
}
.service-card__desc {
margin-top: 12rpx;
font-size: 22rpx;
line-height: 1.45;
color: #666666;
}
.service-card--with-illus .service-card__desc {
margin-top: 28rpx;
}
.service-card__link {
margin-top: auto;
font-size: 22rpx;
color: #2563EB;
}
</style>

View File

@@ -0,0 +1,462 @@
<script setup lang="ts">
import AppTabBar from '@/components/AppTabBar.vue'
import { useGreeting } from '@/hooks/use-greeting'
import type { ProjectItem, QuickEntryItem, ServiceItem } from '@/types/home'
import headerBg from '@/static/icons/1.png'
import softwareIllus from '@/static/icons/software.png'
import hardwareIllus from '@/static/icons/hardware.png'
import iotIllus from '@/static/icons/iot.png'
import productionIllus from '@/static/icons/production.png'
import ProjectCard from './components/ProjectCard.vue'
import ServiceCard from './components/ServiceCard.vue'
const greeting = useGreeting()
const services: ServiceItem[] = [
{
id: '1',
title: '互联网软件',
desc: 'Web/小程序/APP/二次开发/桌面工具等',
theme: 'blue',
illus: softwareIllus,
},
{
id: '2',
title: '硬件电路',
desc: '原理图设计/PCB设计/电气校验等',
theme: 'green',
illus: hardwareIllus,
},
{
id: '3',
title: '物联网全案',
desc: '软硬件开发+云端一体化/定制化开发等',
theme: 'pink',
illus: iotIllus,
},
{
id: '4',
title: '生产制造',
desc: 'PCB制版/SMT/整机装配/定制生产等',
theme: 'orange',
illus: productionIllus,
},
]
const quickEntries: QuickEntryItem[] = [
{ id: '1', label: '项目中心', icon: '/static/icons/quick-project.png', bgColor: '#E8F0FF' },
{ id: '2', label: '快捷提报', icon: '/static/icons/quick-report.png', bgColor: '#E8FAF4' },
{ id: '3', label: '在线客服', icon: '/static/icons/quick-service.png', bgColor: '#F3E8FF' },
{ id: '4', label: '合同管理', icon: '/static/icons/quick-contract.png', bgColor: '#FEE2E2' },
{ id: '5', label: '财务管理', icon: '/static/icons/quick-finance.png', bgColor: '#E0F2FE' },
]
const projects: ProjectItem[] = [
{
id: '1',
title: '社区康养智能服务系统',
category: '互联网软件',
projectNo: '20260813RJ251545',
progress: 65,
status: '进行中',
updateTime: '2026-8-13 11:04:12',
tagTheme: 'orange',
},
{
id: '2',
title: '社区康养智能服务系统',
category: '生产制造',
projectNo: '20260813RJ251545',
progress: 65,
status: '进行中',
updateTime: '2026-8-13 11:04:12',
tagTheme: 'peach',
},
]
</script>
<template>
<view class="home">
<view class="home__header">
<image
class="home__header-bg"
:src="headerBg"
mode="aspectFill"
/>
<view class="home__header-inner">
<view class="home__header-top">
<view class="home__brand">
<image
class="home__logo"
src="/static/icons/logos.png"
mode="aspectFit"
/>
<text class="home__brand-name">
虫子智造研发一体化平台
</text>
</view>
<view class="home__message-btn">
<image
class="home__message-icon"
src="/static/icons/icon-message.png"
mode="aspectFit"
/>
</view>
</view>
<view class="home__greeting-row">
<text class="home__greeting">
{{ greeting }}
</text>
<view class="home__hi-badge">
<image
class="home__hi-icon"
src="/static/icons/hi.png"
mode="aspectFit"
/>
</view>
</view>
<text class="home__subtitle">
今天有2个项目正在进行
</text>
</view>
</view>
<scroll-view
class="home__body"
scroll-y
:show-scrollbar="false"
>
<view class="home__content">
<view class="home__section">
<text class="home__section-title">
业务服务
</text>
<view class="home__service-grid">
<ServiceCard
v-for="item in services"
:key="item.id"
:item="item"
/>
</view>
</view>
<view class="home__sections">
<view class="home__section-header">
<text class="home__section-title">
快捷入口
</text>
<text class="home__section-action">
编辑
</text>
</view>
<view class="home__quick-row">
<view
v-for="entry in quickEntries"
:key="entry.id"
class="home__quick-item"
>
<image
class="home__quick-icon"
:src="entry.icon"
mode="aspectFit"
/>
<text class="home__quick-label">
{{ entry.label }}
</text>
</view>
</view>
</view>
<view class="home__section home__section--last">
<view class="home__section-header">
<text class="home__section-title">
在办项目
</text>
<text class="home__section-action">
查看全部
</text>
</view>
<view class="home__stats-row">
<view class="home__stat-card home__stat-card--blue">
<text class="home__stat-value">
3 个项目
</text>
<text class="home__stat-label">
进行中
</text>
</view>
<view class="home__stat-card home__stat-card--orange">
<text class="home__stat-value">
3 项待办
</text>
<text class="home__stat-label">
待您处理
</text>
</view>
</view>
<text class="home__recent-title">
最近更新
</text>
<ProjectCard
v-for="item in projects"
:key="item.id"
:item="item"
/>
</view>
</view>
</scroll-view>
<AppTabBar active="home" />
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.home {
display: flex;
flex-direction: column;
min-height: 100vh;
background: $color-bg-section;
}
.home__header {
position: relative;
flex-shrink: 0;
overflow: hidden;
background: $color-home-header;
height: 360rpx;
}
.home__header-bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
}
.home__header-inner {
position: relative;
z-index: 1;
padding: calc(var(--status-bar-height, 44px) + 16rpx) 32rpx 48rpx;
}
.home__header-top {
display: flex;
align-items: center;
justify-content: space-between;
margin-top:85rpx
}
.home__brand {
display: flex;
flex: 1;
align-items: center;
min-width: 0;
}
.home__logo {
flex-shrink: 0;
width: 76.34rpx;
height: 76.34rpx;
padding: 8rpx;
border-radius: 12rpx;
box-sizing: border-box;
}
.home__brand-name {
margin-left: 16rpx;
font-size: 26rpx;
font-weight: 500;
color: #ffffff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.home__message-btn {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
margin-left: 16rpx;
border-radius: 16rpx;
}
.home__message-icon {
width: 57.25rpx;
height: 57.25rpx;
}
.home__greeting-row {
display: flex;
align-items: center;
margin-top: 30rpx;
}
.home__greeting {
font-size: 52rpx;
font-weight: 700;
color: #ffffff;
}
.home__hi-badge {
display: flex;
align-items: center;
justify-content: center;
width: 45.8rpx;
height: 45.8rpx;
margin-left: 16rpx;
border-radius: 50%;
}
.home__hi-text {
font-size: 22rpx;
font-weight: 600;
color: #ffffff;
text-transform: lowercase;
}
.home__subtitle {
display: block;
margin-top: 12rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.85);
}
.home__body {
flex: 1;
background: transparent;
}
.home__content {
min-height: 100%;
margin-top: 24rpx;
padding: 20rpx 20rpx calc(140rpx + env(safe-area-inset-bottom));
}
.home__section {
margin-bottom: 20rpx;
height: 600rpx;
width: 711.83rpx;
background: $color-bg-page;
border-radius: 20rpx;
padding-top: 20rpx
}
.home__sections {
margin-bottom: 20rpx;
height: 210rpx;
width: 711.83rpx;
background: $color-bg-page;
border-radius: 20rpx;
padding-top: 20rpx
}
.home__section--last {
margin-bottom: 0;
}
.home__section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
.home__section-title {
font-size: 32rpx;
font-weight: 500;
color: $color-text-primary;
margin-left: 30rpx;
// margin-top: 20rpx;
}
.home__section-action {
font-size: 26rpx;
color: #666666 ;
margin-right: 20rpx;
}
.home__service-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
margin-top: 24rpx;
padding: 24rpx 20rpx 0;
overflow: visible;
}
.home__quick-row {
display: flex;
justify-content: space-between;
}
.home__quick-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
}
.home__quick-icon {
width: 60rpx;
height: 60rpx;
}
.home__quick-label {
margin-top: 12rpx;
font-size: 22rpx;
color: $color-text-primary;
text-align: center;
}
.home__stats-row {
display: flex;
gap: 20rpx;
}
.home__stat-card {
display: flex;
flex: 1;
flex-direction: column;
padding: 28rpx 24rpx;
border-radius: 16rpx;
&--blue {
background: $color-primary-light;
}
&--orange {
background: $color-stat-orange-bg;
}
}
.home__stat-value {
font-size: 32rpx;
font-weight: 700;
color: $color-text-primary;
}
.home__stat-label {
margin-top: 8rpx;
font-size: 24rpx;
color: $color-text-secondary;
}
.home__recent-title {
display: block;
margin-top: 32rpx;
font-size: 28rpx;
font-weight: 600;
color: $color-text-primary;
}
</style>

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import AppTabBar from '@/components/AppTabBar.vue'
</script>
<template>
<view class="placeholder-page">
<text class="placeholder-page__title">
消息中心
</text>
<text class="placeholder-page__desc">
功能开发中
</text>
<AppTabBar active="message" />
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.placeholder-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
background: $color-bg-page;
}
.placeholder-page__title {
font-size: 36rpx;
font-weight: 600;
color: $color-text-primary;
}
.placeholder-page__desc {
margin-top: 16rpx;
font-size: 28rpx;
color: $color-text-secondary;
}
</style>

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import AppTabBar from '@/components/AppTabBar.vue'
</script>
<template>
<view class="placeholder-page">
<text class="placeholder-page__title">
个人中心
</text>
<text class="placeholder-page__desc">
功能开发中
</text>
<AppTabBar active="personal" />
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.placeholder-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
background: $color-bg-page;
}
.placeholder-page__title {
font-size: 36rpx;
font-weight: 600;
color: $color-text-primary;
}
.placeholder-page__desc {
margin-top: 16rpx;
font-size: 28rpx;
color: $color-text-secondary;
}
</style>

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import AppTabBar from '@/components/AppTabBar.vue'
</script>
<template>
<view class="placeholder-page">
<text class="placeholder-page__title">
项目中心
</text>
<text class="placeholder-page__desc">
功能开发中
</text>
<AppTabBar active="project" />
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.placeholder-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
background: $color-bg-page;
}
.placeholder-page__title {
font-size: 36rpx;
font-weight: 600;
color: $color-text-primary;
}
.placeholder-page__desc {
margin-top: 16rpx;
font-size: 28rpx;
color: $color-text-secondary;
}
</style>