feat: UI rewrite R1-R3 (30 pages redesigned)

- R1: inspection + problem pages (9)
- R2: maintenance + check + yxkjzy (7)
- R3: report forms + supervisor + menuEdit (13)
All pages: #1E74FF NavBar, warm white bg, cards 10px radius
This commit is contained in:
Ubuntu
2026-06-15 22:52:44 +08:00
parent 67d5bb93a4
commit ce76462a82
30 changed files with 5210 additions and 1564 deletions

View File

@@ -4,6 +4,7 @@
*
* 展示有限空间作业的详细信息,包含基本信息、
* 安全条件确认清单、作业审批和参与人员。
* Design: #1E74FF NavBar, #F4F7F8 bg, white cards border-radius 10px, panel accent bars.
*/
import { ref, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
@@ -49,16 +50,9 @@ const record = ref({
],
})
const statusMap: Record<string, string> = {
pending: '待开始',
in_progress: '进行中',
completed: '已完成',
}
const statusColorMap: Record<string, string> = {
pending: 'warning',
in_progress: 'primary',
completed: 'success',
const statusMap: Record<string, string> = { pending: '待开始', in_progress: '进行中', completed: '已完成' }
const statusColorMap: Record<string, 'warning' | 'primary' | 'success'> = {
pending: 'warning', in_progress: 'primary', completed: 'success',
}
/** 安全清单统计 */
@@ -73,70 +67,153 @@ const checklistStats = computed(() => {
<template>
<div class="yxkjzy-detail-page">
<van-nav-bar title="作业记录详情" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
<!-- NavBar brand blue -->
<van-nav-bar
title="作业记录详情"
left-text="返回"
left-arrow
fixed
placeholder
@click-left="router.back()"
/>
<!-- 状态标签 -->
<!-- Status Bar -->
<div class="status-bar">
<van-tag :type="statusColorMap[record.status] as never" size="large">
<van-tag :type="statusColorMap[record.status]" size="large" round>
{{ statusMap[record.status] }}
</van-tag>
</div>
<!-- 基本信息 -->
<van-cell-group title="基本信息" class="info-group">
<van-cell title="作业编号" :value="record.title" />
<van-cell title="作业地点" :value="record.location" />
<van-cell title="空间类型" :value="record.spaceType" />
<van-cell title="作业员" :value="record.operator" />
<van-cell title="监督员" :value="record.supervisor" />
<van-cell title="监护人" :value="record.guardian" />
<van-cell title="开始时间" :value="record.startTime" />
<van-cell title="结束时间" :value="record.endTime || '-'" />
<van-cell title="作业时长" :value="record.duration" />
</van-cell-group>
<!-- 基本信息 Card -->
<div class="info-card">
<div class="card-header">
<span class="card-header__accent"></span>
<h5 class="card-header__title">基本信息</h5>
</div>
<div class="card-body">
<div class="info-row">
<span class="info-row__label">作业编号</span>
<span class="info-row__value">{{ record.title }}</span>
</div>
<div class="info-row">
<span class="info-row__label">作业地点</span>
<span class="info-row__value">{{ record.location }}</span>
</div>
<div class="info-row">
<span class="info-row__label">空间类型</span>
<span class="info-row__value">{{ record.spaceType }}</span>
</div>
<div class="info-row">
<span class="info-row__label">作业员</span>
<span class="info-row__value">{{ record.operator }}</span>
</div>
<div class="info-row">
<span class="info-row__label">监督员</span>
<span class="info-row__value">{{ record.supervisor }}</span>
</div>
<div class="info-row">
<span class="info-row__label">监护人</span>
<span class="info-row__value">{{ record.guardian }}</span>
</div>
<div class="info-row">
<span class="info-row__label">开始时间</span>
<span class="info-row__value">{{ record.startTime }}</span>
</div>
<div class="info-row">
<span class="info-row__label">结束时间</span>
<span class="info-row__value">{{ record.endTime || '-' }}</span>
</div>
<div class="info-row">
<span class="info-row__label">作业时长</span>
<span class="info-row__value">{{ record.duration }}</span>
</div>
</div>
</div>
<!-- 空间参数 -->
<van-cell-group title="空间参数" class="info-group">
<van-cell title="深度" :value="record.depth" />
<van-cell title="直径" :value="record.diameter" />
</van-cell-group>
<!-- 空间参数 Card -->
<div class="info-card">
<div class="card-header">
<span class="card-header__accent"></span>
<h5 class="card-header__title">空间参数</h5>
</div>
<div class="card-body">
<div class="info-row">
<span class="info-row__label">深度</span>
<span class="info-row__value">{{ record.depth }}</span>
</div>
<div class="info-row">
<span class="info-row__label">直径</span>
<span class="info-row__value">{{ record.diameter }}</span>
</div>
</div>
</div>
<!-- 环境监测 -->
<van-cell-group title="环境监测" class="info-group">
<van-cell title="氧气含量" :value="record.oxygenContent" />
<van-cell title="有害气体" :value="record.hazardousGas" />
<van-cell title="温度" :value="record.temperature" />
<van-cell title="湿度" :value="record.humidity" />
<van-cell title="通风状态" :value="record.ventilation" />
</van-cell-group>
<!-- 环境监测 Card -->
<div class="info-card">
<div class="card-header">
<span class="card-header__accent"></span>
<h5 class="card-header__title">环境监测</h5>
</div>
<div class="card-body">
<div class="info-row">
<span class="info-row__label">氧气含量</span>
<span class="info-row__value env-ok">{{ record.oxygenContent }}</span>
</div>
<div class="info-row">
<span class="info-row__label">有害气体</span>
<span class="info-row__value env-ok">{{ record.hazardousGas }}</span>
</div>
<div class="info-row">
<span class="info-row__label">温度</span>
<span class="info-row__value">{{ record.temperature }}</span>
</div>
<div class="info-row">
<span class="info-row__label">湿度</span>
<span class="info-row__value">{{ record.humidity }}</span>
</div>
<div class="info-row">
<span class="info-row__label">通风状态</span>
<span class="info-row__value env-ok">{{ record.ventilation }}</span>
</div>
</div>
</div>
<!-- 安全条件确认清单 -->
<van-cell-group :title="`安全条件确认清单 (${checklistStats.requiredChecked}/${checklistStats.required} 必检项)`" class="info-group">
<van-cell v-for="item in record.safetyChecklist" :key="item.id">
<template #title>
<div class="checklist-item">
<van-icon
:name="item.checked ? 'success' : 'close'"
:color="item.checked ? '#4CAF50' : '#F44336'"
size="18"
/>
<span :class="{ 'required-tag': item.required }">{{ item.required ? '【必检】' : '' }}{{ item.item }}</span>
</div>
</template>
<template #value>
<van-tag :type="item.checked ? 'success' : 'danger'" size="medium">
<!-- 安全条件确认清单 Card -->
<div class="info-card">
<div class="card-header">
<span class="card-header__accent"></span>
<h5 class="card-header__title">
安全条件确认清单
<span class="checklist-summary">{{ checklistStats.requiredChecked }}/{{ checklistStats.required }} 必检项</span>
</h5>
</div>
<div class="card-body">
<div v-for="item in record.safetyChecklist" :key="item.id" class="checklist-row">
<van-icon
:name="item.checked ? 'success' : 'close'"
:color="item.checked ? '#4CAF50' : '#F44336'"
size="18"
/>
<span :class="['checklist-text', { 'required': item.required }]">
{{ item.required ? '【必检】' : '' }}{{ item.item }}
</span>
<van-tag :type="item.checked ? 'success' : 'danger'" size="medium" class="checklist-tag">
{{ item.checked ? '已确认' : '未确认' }}
</van-tag>
</template>
</van-cell>
</van-cell-group>
</div>
</div>
</div>
<!-- 作业描述 -->
<van-cell-group title="作业描述" class="info-group">
<van-cell>
<!-- 作业描述 Card -->
<div class="info-card">
<div class="card-header">
<span class="card-header__accent"></span>
<h5 class="card-header__title">作业描述</h5>
</div>
<div class="card-body">
<p class="desc-text">{{ record.description }}</p>
</van-cell>
</van-cell-group>
</div>
</div>
<!-- 安全提示 -->
<div class="safety-tips">
@@ -155,46 +232,93 @@ const checklistStats = computed(() => {
<style lang="scss" scoped>
.yxkjzy-detail-page {
min-height: 100vh;
background: var(--color-bg-page);
background: #F4F7F8;
padding-bottom: 24px;
:deep(.van-nav-bar) {
background: var(--color-primary);
--van-nav-bar-title-text-color: #fff;
--van-nav-bar-text-color: #fff;
--van-nav-bar-icon-color: #fff;
}
:deep(.van-nav-bar) { background: #1E74FF; }
:deep(.van-nav-bar__title) { color: #fff; font-size: 18px; font-weight: 600; }
:deep(.van-nav-bar__text),
:deep(.van-nav-bar__arrow) { color: #fff; }
:deep(.van-nav-bar .van-icon) { color: #fff; }
}
// Status Bar
.status-bar {
padding: 12px 16px;
background: var(--color-bg-card);
padding: 14px 16px;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
text-align: center;
}
.info-group {
margin-top: 8px;
// Info Card
.info-card {
background: #fff;
border-radius: 10px;
margin: 10px 12px 0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
overflow: hidden;
}
.checklist-item {
.card-header {
display: flex;
align-items: center;
gap: 8px;
padding: 14px 16px 10px;
&__accent { width: 3px; height: 16px; border-radius: 2px; background: #1E74FF; flex-shrink: 0; }
&__title { font-size: 15px; font-weight: 600; color: var(--color-text-primary); }
}
.checklist-summary {
font-size: 12px;
font-weight: 400;
color: var(--color-text-secondary);
}
.card-body { padding: 0 16px 14px; }
.required-tag {
color: var(--color-text-regular);
}
// Info Rows
.info-row {
display: flex;
align-items: flex-start;
padding: 8px 0;
& + & { border-top: 1px solid var(--color-border-light); }
&__label { width: 72px; flex-shrink: 0; font-size: 13px; color: var(--color-text-secondary); }
&__value { flex: 1; font-size: 14px; color: var(--color-text-primary); word-break: break-all; }
}
.env-ok {
color: #4CAF50 !important;
font-weight: 500;
}
// Checklist Rows
.checklist-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 0;
& + & { border-top: 1px solid var(--color-border-light); }
}
.checklist-text {
flex: 1;
font-size: 13px;
color: var(--color-text-regular);
&.required { font-weight: 500; }
}
.checklist-tag {
flex-shrink: 0;
}
// Description
.desc-text {
font-size: 14px;
line-height: 1.8;
line-height: 1.7;
color: var(--color-text-regular);
padding: 4px 0;
text-indent: 2em;
}
// Safety Tips
.safety-tips {
margin: 12px 0;
margin: 12px 12px 0;
}
</style>

View File

@@ -4,6 +4,7 @@
*
* 展示有限空间作业记录,支持搜索和状态筛选(全部/进行中/已完成),
* 点击卡片跳转作业记录详情。
* Design: #1E74FF NavBar, #F4F7F8 bg, white cards border-radius 10px, styled tabs.
*/
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
@@ -27,19 +28,12 @@ const mockRecords = [
]
/** 状态映射 */
const statusMap: Record<string, string> = {
pending: '待开始',
in_progress: '进行中',
completed: '已完成',
const statusMap: Record<string, string> = { pending: '待开始', in_progress: '进行中', completed: '已完成' }
const statusColorMap: Record<string, 'warning' | 'primary' | 'success'> = {
pending: 'warning', in_progress: 'primary', completed: 'success',
}
const statusColorMap: Record<string, string> = {
pending: 'warning',
in_progress: 'primary',
completed: 'success',
}
/** 空间类型图标映射 */
/** 空间类型图标 */
const spaceIconMap: Record<string, string> = {
'污水井': 'orders-o',
'阀门井': 'setting-o',
@@ -73,41 +67,86 @@ function goDetail(id: number) {
<template>
<div class="yxkjzy-records-page">
<van-nav-bar title="有限空间作业记录" left-arrow fixed placeholder @click-left="router.back()" />
<!-- NavBar brand blue -->
<van-nav-bar
title="有限空间作业记录"
left-arrow
fixed
placeholder
@click-left="router.back()"
/>
<van-search v-model="searchText" placeholder="搜索作业标题、位置、作业员" shape="round" />
<!-- Search -->
<div class="search-wrapper">
<van-search
v-model="searchText"
placeholder="搜索作业标题、位置、作业员"
shape="round"
background="transparent"
/>
</div>
<van-tabs v-model:active="activeTab" sticky>
<!-- Tabs -->
<van-tabs
v-model:active="activeTab"
sticky
:duration="0.3"
swipeable
color="#1E74FF"
title-active-color="#1E74FF"
title-inactive-color="#646566"
line-width="20"
line-height="3"
>
<van-tab title="全部" />
<van-tab title="进行中" />
<van-tab title="已完成" />
</van-tabs>
<!-- Record List -->
<div class="record-list">
<van-empty v-if="filteredRecords.length === 0" description="暂无作业记录" />
<van-card
<van-empty
v-if="filteredRecords.length === 0"
image="search"
description="暂无作业记录"
/>
<div
v-for="record in filteredRecords"
:key="record.id"
:title="record.title"
:desc="`位置: ${record.location}`"
class="record-card"
@click="goDetail(record.id)"
>
<template #tags>
<van-tag :type="statusColorMap[record.status] as never" size="medium">
<!-- Card Header -->
<div class="record-card__header">
<van-icon :name="spaceIconMap[record.spaceType] || 'label-o'" size="22" color="#969799" class="space-icon" />
<h4 class="record-card__title">{{ record.title }}</h4>
<van-tag :type="statusColorMap[record.status]" size="medium" round class="status-badge">
{{ statusMap[record.status] }}
</van-tag>
</template>
<template #thumb>
<van-icon :name="spaceIconMap[record.spaceType] || 'label-o'" size="32" color="#999" />
</template>
<template #footer>
<div class="record-meta">
<span class="meta-type">空间类型: {{ record.spaceType }}</span>
<span>作业员: {{ record.operator }}</span>
<span>开始时间: {{ record.startTime }}</span>
</div>
<!-- Card Body -->
<div class="record-card__body">
<div class="record-info">
<span class="info-item">
<van-icon name="location-o" size="13" />
{{ record.location }}
</span>
</div>
</template>
</van-card>
</div>
<!-- Card Footer -->
<div class="record-card__footer">
<span class="meta-text">
<van-icon name="user-o" size="12" color="#969799" />
{{ record.operator }}
</span>
<span class="meta-text">
<van-icon name="clock-o" size="12" color="#969799" />
{{ record.startTime }}
</span>
</div>
</div>
</div>
</div>
</template>
@@ -115,39 +154,101 @@ function goDetail(id: number) {
<style lang="scss" scoped>
.yxkjzy-records-page {
min-height: 100vh;
background: var(--color-bg-page);
background: #F4F7F8;
:deep(.van-nav-bar) {
background: var(--color-primary);
--van-nav-bar-title-text-color: #fff;
--van-nav-bar-text-color: #fff;
--van-nav-bar-icon-color: #fff;
}
:deep(.van-nav-bar) { background: #1E74FF; }
:deep(.van-nav-bar__title) { color: #fff; font-size: 18px; font-weight: 600; }
:deep(.van-nav-bar__text),
:deep(.van-nav-bar__arrow) { color: #fff; }
:deep(.van-nav-bar .van-icon) { color: #fff; }
}
.record-list {
padding: 0 8px;
:deep(.van-card) {
margin: 8px;
// Search
.search-wrapper {
padding: 8px 12px 0;
background: #F4F7F8;
:deep(.van-search__content) {
border-radius: 10px;
background: var(--color-bg-card);
}
:deep(.van-tag) {
margin-right: 4px;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
}
.record-meta {
display: flex;
flex-direction: column;
gap: 2px;
font-size: 12px;
color: var(--color-text-secondary);
// Tabs
:deep(.van-tabs) { background: #fff; }
:deep(.van-tabs__wrap) { padding: 0 8px; }
:deep(.van-tab) { font-size: 14px; }
.meta-type {
color: var(--color-text-regular);
}
// Record List
.record-list { padding: 8px 12px 16px; }
.record-card {
background: #fff;
border-radius: 10px;
padding: 14px 16px;
margin-bottom: 10px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
cursor: pointer;
transition: box-shadow 0.15s ease;
&:active { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
}
.record-card__header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.space-icon {
flex-shrink: 0;
}
.record-card__title {
font-size: 15px;
font-weight: 600;
color: var(--color-text-primary);
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status-badge {
flex-shrink: 0;
}
.record-card__body {
margin-bottom: 6px;
}
.record-info {
font-size: 13px;
color: var(--color-text-regular);
}
.info-item {
display: flex;
align-items: center;
gap: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.record-card__footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 8px;
border-top: 1px solid var(--color-border-light);
}
.meta-text {
font-size: 12px;
color: var(--color-text-placeholder);
display: flex;
align-items: center;
gap: 4px;
}
</style>