feat: Batch 4 - remaining pages (23 pages)
Agent Loop: 3 agents, all passed - 8 pshgl pages (排水户管理) - 8 fxgl+xjgl pages (防汛+工程) - 7 remaining (map/project/QR)
This commit is contained in:
@@ -366,6 +366,180 @@ const routes: RouteRecordRaw[] = [
|
|||||||
title: '施工问题上报',
|
title: '施工问题上报',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// ── 防汛管理模块 ──
|
||||||
|
{
|
||||||
|
path: '/groupsClockList/:id?/:detail?',
|
||||||
|
name: 'GroupsClockList',
|
||||||
|
component: () => import('@/views/fxgl/groupsClockList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '打卡记录',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/teamList/:id?',
|
||||||
|
name: 'TeamList',
|
||||||
|
component: () => import('@/views/fxgl/teamList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '选择成员',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/instructionList',
|
||||||
|
name: 'InstructionList',
|
||||||
|
component: () => import('@/views/fxgl/instructionList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '防汛指令',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/instructionReceive',
|
||||||
|
name: 'InstructionReceive',
|
||||||
|
component: () => import('@/views/fxgl/instructionReceive.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '指令详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/materialList',
|
||||||
|
name: 'MaterialList',
|
||||||
|
component: () => import('@/views/fxgl/materialList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '物资管理',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/managementInventory/:id?',
|
||||||
|
name: 'ManagementInventory',
|
||||||
|
component: () => import('@/views/fxgl/managementInventory.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '出入库',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ── 工程管理模块 ──
|
||||||
|
{
|
||||||
|
path: '/constructionTracking',
|
||||||
|
name: 'ConstructionTracking',
|
||||||
|
component: () => import('@/views/xjgl/constructionList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '工程项目',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/constructionDetail/:id?',
|
||||||
|
name: 'ConstructionDetail',
|
||||||
|
component: () => import('@/views/xjgl/constructionDetail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '项目详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ── 排水户管理模块 ──
|
||||||
|
{
|
||||||
|
path: '/pshList',
|
||||||
|
name: 'PshList',
|
||||||
|
component: () => import('@/views/pshgl/pshList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '排水户管理',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshglDetail/:detail?',
|
||||||
|
name: 'PshglDetail',
|
||||||
|
component: () => import('@/views/pshgl/pshglDetail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '排水户详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshProblemList/:id?',
|
||||||
|
name: 'PshProblemList',
|
||||||
|
component: () => import('@/views/pshgl/pshProblemList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '问题列表',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshProblemDetail/:detail?/:obj?',
|
||||||
|
name: 'PshProblemDetail',
|
||||||
|
component: () => import('@/views/pshgl/pshProblemDetail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '问题详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshTaskList/:detail?/:obj?',
|
||||||
|
name: 'PshTaskList',
|
||||||
|
component: () => import('@/views/pshgl/pshTaskList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '任务管理',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/checkList',
|
||||||
|
name: 'CheckList',
|
||||||
|
component: () => import('@/views/pshgl/checkList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '检查记录',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshCheckList/:id?/:obj?',
|
||||||
|
name: 'PshCheckList',
|
||||||
|
component: () => import('@/views/pshgl/pshCheckList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '选择排水户',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pshCheck/:id?/:detail?',
|
||||||
|
name: 'PshCheck',
|
||||||
|
component: () => import('@/views/pshgl/pshCheck.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '检查报告',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ── 地图模块 ──
|
||||||
|
{
|
||||||
|
path: '/map',
|
||||||
|
name: 'Map',
|
||||||
|
component: () => import('@/views/map/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '地图',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ── 项目管理模块 ──
|
||||||
|
{
|
||||||
|
path: '/projectManagement',
|
||||||
|
name: 'ProjectManagement',
|
||||||
|
component: () => import('@/views/projectManagement/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '项目管理',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/projectManagementDetail/:detail?',
|
||||||
|
name: 'ProjectManagementDetail',
|
||||||
|
component: () => import('@/views/projectManagement/detail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '项目详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ── 扫码入口模块 ──
|
||||||
|
{
|
||||||
|
path: '/pshDetail/:id?',
|
||||||
|
name: 'PshDetail',
|
||||||
|
component: () => import('@/views/clientQR/pshDetail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '排水户详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/deviceDetails/:id?',
|
||||||
|
name: 'DeviceDetails',
|
||||||
|
component: () => import('@/views/clientQR/deviceDetails.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '设备详情',
|
||||||
|
},
|
||||||
|
},
|
||||||
// 404 兜底
|
// 404 兜底
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
|
|||||||
136
src/views/clientQR/deviceDetails.vue
Normal file
136
src/views/clientQR/deviceDetails.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 设备详情(二维码扫码入口)
|
||||||
|
*
|
||||||
|
* 通过扫码获取设备 ID,展示设备信息及养护记录入口。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const deviceId = computed(() => route.params.id as string | undefined)
|
||||||
|
|
||||||
|
/** 模拟设备详情 */
|
||||||
|
const device = ref({
|
||||||
|
id: deviceId.value || 'DEV-001',
|
||||||
|
name: '流量监测仪 A-01',
|
||||||
|
type: '流量监测',
|
||||||
|
model: 'FLOW-M200',
|
||||||
|
location: '城北区东风路雨水管网检查井 J-12',
|
||||||
|
status: 'normal',
|
||||||
|
installDate: '2024-06-15',
|
||||||
|
lastMaintain: '2025-05-20',
|
||||||
|
protocol: 'MQTT',
|
||||||
|
battery: '85%',
|
||||||
|
})
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
normal: '正常',
|
||||||
|
alarm: '告警',
|
||||||
|
offline: '离线',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, string> = {
|
||||||
|
normal: '#07c160',
|
||||||
|
alarm: '#ee0a24',
|
||||||
|
offline: '#999',
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
function goMaintenance() {
|
||||||
|
// 跳转到养护记录
|
||||||
|
router.push('/maintenanceRecords')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="device-detail-page">
|
||||||
|
<van-nav-bar title="设备详情" left-arrow fixed placeholder @click-left="goBack" />
|
||||||
|
|
||||||
|
<!-- 状态卡片 -->
|
||||||
|
<div class="status-card">
|
||||||
|
<span class="status-dot" :style="{ backgroundColor: statusColorMap[device.status] }" />
|
||||||
|
<span class="status-text" :style="{ color: statusColorMap[device.status] }">
|
||||||
|
{{ statusMap[device.status] }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<van-cell-group title="基本信息" inset>
|
||||||
|
<van-cell title="设备编号" :value="device.id" />
|
||||||
|
<van-cell title="设备名称" :value="device.name" />
|
||||||
|
<van-cell title="设备类型" :value="device.type" />
|
||||||
|
<van-cell title="设备型号" :value="device.model" />
|
||||||
|
<van-cell title="安装位置" :label="device.location" />
|
||||||
|
<van-cell title="安装日期" :value="device.installDate" />
|
||||||
|
<van-cell title="通信协议" :value="device.protocol" />
|
||||||
|
<van-cell title="电池电量" :value="device.battery" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 最近养护 -->
|
||||||
|
<van-cell-group title="最近养护" inset>
|
||||||
|
<van-cell title="上次养护日期" :value="device.lastMaintain" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="action-section">
|
||||||
|
<van-button type="primary" block round @click="goMaintenance">
|
||||||
|
查看养护记录
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.device-detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
padding-bottom: 20px;
|
||||||
|
|
||||||
|
: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-cell-group) {
|
||||||
|
margin: 12px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-cell-group__title) {
|
||||||
|
padding: 12px 16px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 12px 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-section {
|
||||||
|
padding: 20px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
115
src/views/clientQR/pshDetail.vue
Normal file
115
src/views/clientQR/pshDetail.vue
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户详情(二维码扫码入口)
|
||||||
|
*
|
||||||
|
* 通过扫码获取排水户 ID,展示详细信息及二维码。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const pshId = computed(() => route.params.id as string | undefined)
|
||||||
|
|
||||||
|
/** 模拟排水户详情 */
|
||||||
|
const detail = ref({
|
||||||
|
id: pshId.value || 'PSH-001',
|
||||||
|
name: '万达广场(城北店)',
|
||||||
|
type: '商业',
|
||||||
|
address: '城北区东风路 128 号',
|
||||||
|
contact: '张经理',
|
||||||
|
phone: '138****5678',
|
||||||
|
licenseNo: '排许字第2024-0031号',
|
||||||
|
drainType: '雨污分流',
|
||||||
|
qrCodeUrl: '', // 实际从接口获取
|
||||||
|
})
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="psh-detail-page">
|
||||||
|
<van-nav-bar title="排水户详情" left-arrow fixed placeholder @click-left="goBack" />
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<van-cell-group title="基本信息" inset>
|
||||||
|
<van-cell title="排水户编号" :value="detail.id" />
|
||||||
|
<van-cell title="排水户名称" :value="detail.name" />
|
||||||
|
<van-cell title="排水户类型" :value="detail.type" />
|
||||||
|
<van-cell title="地址" :value="detail.address" />
|
||||||
|
<van-cell title="联系人" :value="detail.contact" />
|
||||||
|
<van-cell title="联系电话" :value="detail.phone" />
|
||||||
|
<van-cell title="排水许可证" :value="detail.licenseNo" />
|
||||||
|
<van-cell title="排水方式" :value="detail.drainType" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 二维码 -->
|
||||||
|
<van-cell-group title="排水户二维码" inset>
|
||||||
|
<div class="qr-section">
|
||||||
|
<div class="qr-placeholder">
|
||||||
|
<van-image
|
||||||
|
v-if="detail.qrCodeUrl"
|
||||||
|
:src="detail.qrCodeUrl"
|
||||||
|
width="160"
|
||||||
|
height="160"
|
||||||
|
fit="contain"
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<van-icon name="qr" size="64" color="#ccc" />
|
||||||
|
<p class="qr-hint">扫码查看排水户信息</p>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-cell-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.psh-detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
padding-bottom: 20px;
|
||||||
|
|
||||||
|
: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-cell-group) {
|
||||||
|
margin: 12px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-cell-group__title) {
|
||||||
|
padding: 12px 16px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
.qr-placeholder {
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 2px dashed #ddd;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #fafafa;
|
||||||
|
|
||||||
|
.qr-hint {
|
||||||
|
margin: 8px 0 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
117
src/views/fxgl/groupsClockList.vue
Normal file
117
src/views/fxgl/groupsClockList.vue
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 班组人员打卡列表
|
||||||
|
*
|
||||||
|
* 展示防汛值班人员的打卡记录,
|
||||||
|
* 支持按班组切换和日期筛选。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const activeTab = ref(0)
|
||||||
|
const dateFilter = ref('')
|
||||||
|
|
||||||
|
/** 打卡状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
clocked: '已打卡',
|
||||||
|
late: '迟到',
|
||||||
|
missing: '缺卡',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'success' | 'warning' | 'danger'> = {
|
||||||
|
clocked: 'success',
|
||||||
|
late: 'warning',
|
||||||
|
missing: 'danger',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟打卡数据 */
|
||||||
|
const mockRecords = [
|
||||||
|
{ id: 1, name: '张建国', team: 'A组', time: '08:25', status: 'clocked', location: '泵站1号' },
|
||||||
|
{ id: 2, name: '李明辉', team: 'A组', time: '08:32', status: 'late', location: '泵站1号' },
|
||||||
|
{ id: 3, name: '王强', team: 'B组', time: '08:15', status: 'clocked', location: '闸门3号' },
|
||||||
|
{ id: 4, name: '赵勇', team: 'B组', time: '--:--', status: 'missing', location: '闸门3号' },
|
||||||
|
{ id: 5, name: '陈志远', team: 'A组', time: '08:20', status: 'clocked', location: '河道巡查点' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockRecords
|
||||||
|
if (activeTab.value === 1) list = list.filter(r => r.team === 'A组')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(r => r.team === 'B组')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
function goTeamList() {
|
||||||
|
router.push('/teamList')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="打卡记录" left-arrow fixed placeholder @click-left="router.back()">
|
||||||
|
<template #right>
|
||||||
|
<van-icon name="user-o" size="20" @click="goTeamList" />
|
||||||
|
</template>
|
||||||
|
</van-nav-bar>
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="A组" />
|
||||||
|
<van-tab title="B组" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无打卡记录" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:desc="`点位: ${item.location}`"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>打卡时间: {{ item.time }}</span>
|
||||||
|
<span>{{ item.team }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
139
src/views/fxgl/instructionList.vue
Normal file
139
src/views/fxgl/instructionList.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 防汛指令列表
|
||||||
|
*
|
||||||
|
* 展示下发的防汛指令,支持按状态筛选和搜索,
|
||||||
|
* 点击可查看指令详情并处理。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const searchText = ref('')
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '待接收',
|
||||||
|
accepted: '已接收',
|
||||||
|
completed: '已完成',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'warning' | 'primary' | 'success'> = {
|
||||||
|
pending: 'warning',
|
||||||
|
accepted: 'primary',
|
||||||
|
completed: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 级别映射 */
|
||||||
|
const levelMap: Record<string, string> = {
|
||||||
|
urgent: '紧急',
|
||||||
|
normal: '普通',
|
||||||
|
}
|
||||||
|
|
||||||
|
const levelColorMap: Record<string, string> = {
|
||||||
|
urgent: '#ee0a24',
|
||||||
|
normal: '#1989fa',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟指令数据 */
|
||||||
|
const mockInstructions = [
|
||||||
|
{ id: 1, title: '启动III级防汛应急响应', level: 'urgent', from: '市防汛指挥部', time: '2025-06-15 08:00', status: 'pending' },
|
||||||
|
{ id: 2, title: '河道巡查任务通知', level: 'normal', from: '水务局', time: '2025-06-14 14:30', status: 'accepted' },
|
||||||
|
{ id: 3, title: '泵站设备检修通知', level: 'normal', from: '运维中心', time: '2025-06-13 09:00', status: 'completed' },
|
||||||
|
{ id: 4, title: '重点积水路段值守', level: 'urgent', from: '市政管理处', time: '2025-06-15 07:30', status: 'pending' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockInstructions
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(i =>
|
||||||
|
i.title.toLowerCase().includes(kw) ||
|
||||||
|
i.from.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(i => i.status === 'pending')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(i => i.status === 'accepted')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(i => i.status === 'completed')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
function goReceive(id: number) {
|
||||||
|
router.push('/instructionReceive')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="防汛指令" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索指令标题、来源" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="待接收" />
|
||||||
|
<van-tab title="已接收" />
|
||||||
|
<van-tab title="已完成" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无指令" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.title"
|
||||||
|
:desc="`来自: ${item.from}`"
|
||||||
|
@click="goReceive(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :color="levelColorMap[item.level]" size="medium" text-color="#fff">
|
||||||
|
{{ levelMap[item.level] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>{{ item.time }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
142
src/views/fxgl/instructionReceive.vue
Normal file
142
src/views/fxgl/instructionReceive.vue
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 指令接收详情
|
||||||
|
*
|
||||||
|
* 展示防汛指令的详细内容和操作按钮,
|
||||||
|
* 支持接收确认和退回操作。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showSuccessToast, showConfirmDialog } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
/** 接收状态 */
|
||||||
|
const accepted = ref(false)
|
||||||
|
const remark = ref('')
|
||||||
|
|
||||||
|
/** 模拟指令详情 */
|
||||||
|
const instruction = {
|
||||||
|
id: 1,
|
||||||
|
title: '启动III级防汛应急响应',
|
||||||
|
level: 'urgent',
|
||||||
|
from: '市防汛指挥部',
|
||||||
|
time: '2025-06-15 08:00',
|
||||||
|
content: '根据市气象台发布的暴雨橙色预警,预计未来6小时内我市将出现大范围强降雨,累计雨量可达80-120毫米。经研究决定,自2025年6月15日08时起启动III级防汛应急响应。请各相关单位按要求落实防汛措施。',
|
||||||
|
contact: '张主任',
|
||||||
|
phone: '010-88886666',
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAccept() {
|
||||||
|
accepted.value = true
|
||||||
|
showSuccessToast('已接收指令')
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDecline() {
|
||||||
|
showConfirmDialog({
|
||||||
|
title: '退回指令',
|
||||||
|
message: '确定要退回该指令吗?请填写退回原因。',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
showSuccessToast('已退回')
|
||||||
|
router.back()
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar
|
||||||
|
title="指令详情"
|
||||||
|
left-arrow
|
||||||
|
fixed
|
||||||
|
placeholder
|
||||||
|
@click-left="router.back()"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-cell-group inset>
|
||||||
|
<van-cell title="指令标题" :value="instruction.title" />
|
||||||
|
<van-cell title="来源单位" :value="instruction.from" />
|
||||||
|
<van-cell title="发布时间" :value="instruction.time" />
|
||||||
|
<van-cell title="联 系 人" :value="instruction.contact" />
|
||||||
|
<van-cell title="联系电话" :value="instruction.phone" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group inset style="margin-top: 12px">
|
||||||
|
<van-cell title="指令内容" />
|
||||||
|
<div class="content-block">{{ instruction.content }}</div>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group v-if="accepted" inset style="margin-top: 12px">
|
||||||
|
<van-field
|
||||||
|
v-model="remark"
|
||||||
|
label="备注"
|
||||||
|
placeholder="可选填写接收备注"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<div class="action-bar">
|
||||||
|
<van-button
|
||||||
|
v-if="!accepted"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
round
|
||||||
|
@click="onAccept"
|
||||||
|
>
|
||||||
|
接收指令
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
v-else
|
||||||
|
type="success"
|
||||||
|
block
|
||||||
|
round
|
||||||
|
@click="router.back()"
|
||||||
|
>
|
||||||
|
确认完成
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
v-if="!accepted"
|
||||||
|
type="default"
|
||||||
|
block
|
||||||
|
round
|
||||||
|
style="margin-top: 10px"
|
||||||
|
@click="onDecline"
|
||||||
|
>
|
||||||
|
退回
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-block {
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-bar {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
141
src/views/fxgl/managementInventory.vue
Normal file
141
src/views/fxgl/managementInventory.vue
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 物资出入库
|
||||||
|
*
|
||||||
|
* 对防汛物资进行入库或出库操作,
|
||||||
|
* 记录数量、类型和操作说明。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showSuccessToast } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
/** 操作类型 */
|
||||||
|
const opType = ref<'in' | 'out'>('in')
|
||||||
|
const quantity = ref('')
|
||||||
|
const batchNo = ref('')
|
||||||
|
const operator = ref('')
|
||||||
|
const remark = ref('')
|
||||||
|
|
||||||
|
/** 模拟物资信息 */
|
||||||
|
const material = {
|
||||||
|
id: route.params.id,
|
||||||
|
name: '柴油水泵',
|
||||||
|
stock: 12,
|
||||||
|
unit: '台',
|
||||||
|
location: '1号仓库',
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (!quantity.value) {
|
||||||
|
showSuccessToast('请填写数量')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!operator.value) {
|
||||||
|
showSuccessToast('请填写操作人')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const action = opType.value === 'in' ? '入库' : '出库'
|
||||||
|
showSuccessToast(`${action}成功`)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar
|
||||||
|
title="出入库"
|
||||||
|
left-arrow
|
||||||
|
fixed
|
||||||
|
placeholder
|
||||||
|
@click-left="router.back()"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-cell-group inset>
|
||||||
|
<van-cell title="物资名称" :value="material.name" />
|
||||||
|
<van-cell title="当前库存" :value="`${material.stock} ${material.unit}`" />
|
||||||
|
<van-cell title="存放位置" :value="material.location" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-form @submit="onSubmit" style="margin-top: 12px">
|
||||||
|
<van-cell-group inset>
|
||||||
|
<van-field
|
||||||
|
name="opType"
|
||||||
|
label="操作类型"
|
||||||
|
>
|
||||||
|
<template #input>
|
||||||
|
<van-radio-group v-model="opType" direction="horizontal">
|
||||||
|
<van-radio name="in">入库</van-radio>
|
||||||
|
<van-radio name="out">出库</van-radio>
|
||||||
|
</van-radio-group>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field
|
||||||
|
v-model="quantity"
|
||||||
|
name="quantity"
|
||||||
|
label="数量"
|
||||||
|
:placeholder="`请输入${opType === 'in' ? '入库' : '出库'}数量`"
|
||||||
|
type="digit"
|
||||||
|
:rules="[{ required: true, message: '请填写数量' }]"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<span class="unit-text">{{ material.unit }}</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field
|
||||||
|
v-model="batchNo"
|
||||||
|
name="batchNo"
|
||||||
|
label="批次号"
|
||||||
|
placeholder="可选填写批次号"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="operator"
|
||||||
|
name="operator"
|
||||||
|
label="操作人"
|
||||||
|
placeholder="请输入操作人姓名"
|
||||||
|
:rules="[{ required: true, message: '请填写操作人' }]"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="remark"
|
||||||
|
name="remark"
|
||||||
|
label="备注"
|
||||||
|
placeholder="可选填写备注说明"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<div class="submit-wrap">
|
||||||
|
<van-button type="primary" block round native-type="submit">
|
||||||
|
确认{{ opType === 'in' ? '入库' : '出库' }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</van-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-text {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-wrap {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
152
src/views/fxgl/materialList.vue
Normal file
152
src/views/fxgl/materialList.vue
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 防汛物资管理
|
||||||
|
*
|
||||||
|
* 展示防汛物资库存列表,支持按类型筛选和搜索,
|
||||||
|
* 显示各物资的库存数量。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const searchText = ref('')
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 物资类型映射 */
|
||||||
|
const typeMap: Record<string, string> = {
|
||||||
|
pump: '水泵类',
|
||||||
|
sandbag: '沙袋类',
|
||||||
|
tool: '工具类',
|
||||||
|
rescue: '救援类',
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeColorMap: Record<string, string> = {
|
||||||
|
pump: '#1989fa',
|
||||||
|
sandbag: '#ff976a',
|
||||||
|
tool: '#07c160',
|
||||||
|
rescue: '#ee0a24',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 库存状态 */
|
||||||
|
const stockStatusMap: Record<string, { label: string; type: 'success' | 'warning' | 'danger' }> = {
|
||||||
|
sufficient: { label: '充足', type: 'success' },
|
||||||
|
normal: { label: '正常', type: '' as 'success' },
|
||||||
|
low: { label: '偏低', type: 'warning' },
|
||||||
|
shortage: { label: '紧缺', type: 'danger' },
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟物资数据 */
|
||||||
|
const mockMaterials = [
|
||||||
|
{ id: 1, name: '柴油水泵', type: 'pump', stock: 12, unit: '台', minStock: 5, status: 'sufficient', location: '1号仓库' },
|
||||||
|
{ id: 2, name: '防洪沙袋', type: 'sandbag', stock: 500, unit: '个', minStock: 200, status: 'sufficient', location: '2号仓库' },
|
||||||
|
{ id: 3, name: '救生衣', type: 'rescue', stock: 30, unit: '件', minStock: 50, status: 'low', location: '1号仓库' },
|
||||||
|
{ id: 4, name: '铁锹', type: 'tool', stock: 8, unit: '把', minStock: 20, status: 'shortage', location: '2号仓库' },
|
||||||
|
{ id: 5, name: '发电机', type: 'pump', stock: 6, unit: '台', minStock: 3, status: 'normal', location: '1号仓库' },
|
||||||
|
{ id: 6, name: '应急照明灯', type: 'tool', stock: 15, unit: '个', minStock: 10, status: 'normal', location: '3号仓库' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const typeTabs = ['all', 'pump', 'sandbag', 'tool', 'rescue']
|
||||||
|
const typeTabNames = ['全部', '水泵类', '沙袋类', '工具类', '救援类']
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockMaterials
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(m =>
|
||||||
|
m.name.toLowerCase().includes(kw) ||
|
||||||
|
m.location.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value > 0) {
|
||||||
|
list = list.filter(m => m.type === typeTabs[activeTab.value])
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
function goInventory(id: number) {
|
||||||
|
router.push(`/managementInventory/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="物资管理" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索物资名称、存放位置" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab v-for="(name, i) in typeTabNames" :key="i" :title="name" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无物资" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:desc="`存放位置: ${item.location}`"
|
||||||
|
@click="goInventory(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :color="typeColorMap[item.type]" size="medium" text-color="#fff">
|
||||||
|
{{ typeMap[item.type] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="stockStatusMap[item.status].type" size="medium">
|
||||||
|
{{ stockStatusMap[item.status].label }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span class="stock-count">库存: {{ item.stock }} {{ item.unit }}</span>
|
||||||
|
<span class="stock-min">最低库存: {{ item.minStock }} {{ item.unit }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
|
||||||
|
.stock-count {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-min {
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
129
src/views/fxgl/teamList.vue
Normal file
129
src/views/fxgl/teamList.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 选择班组成员
|
||||||
|
*
|
||||||
|
* 展示班组成员列表,支持搜索和多选,
|
||||||
|
* 用于分配防汛任务时的成员勾选。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showSuccessToast } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const searchText = ref('')
|
||||||
|
const checkedIds = ref<number[]>([])
|
||||||
|
|
||||||
|
/** 模拟成员数据 */
|
||||||
|
const mockMembers = [
|
||||||
|
{ id: 1, name: '张建国', phone: '13800001001', team: 'A组', role: '组长' },
|
||||||
|
{ id: 2, name: '李明辉', phone: '13800001002', team: 'A组', role: '组员' },
|
||||||
|
{ id: 3, name: '陈志远', phone: '13800001003', team: 'A组', role: '组员' },
|
||||||
|
{ id: 4, name: '王强', phone: '13800001004', team: 'B组', role: '组长' },
|
||||||
|
{ id: 5, name: '赵勇', phone: '13800001005', team: 'B组', role: '组员' },
|
||||||
|
{ id: 6, name: '周文博', phone: '13800001006', team: 'B组', role: '组员' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
if (!searchText.value) return mockMembers
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
return mockMembers.filter(m =>
|
||||||
|
m.name.toLowerCase().includes(kw) ||
|
||||||
|
m.phone.includes(kw)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
function toggleAll() {
|
||||||
|
if (checkedIds.value.length === filteredList.value.length) {
|
||||||
|
checkedIds.value = []
|
||||||
|
} else {
|
||||||
|
checkedIds.value = filteredList.value.map(m => m.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onConfirm() {
|
||||||
|
showSuccessToast(`已选择 ${checkedIds.value.length} 人`)
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="选择班组成员" left-arrow fixed placeholder @click-left="router.back()">
|
||||||
|
<template #right>
|
||||||
|
<span class="nav-action" @click="toggleAll">
|
||||||
|
{{ checkedIds.length === filteredList.length && filteredList.length > 0 ? '取消全选' : '全选' }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</van-nav-bar>
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索姓名、手机号" shape="round" />
|
||||||
|
|
||||||
|
<van-checkbox-group v-model="checkedIds">
|
||||||
|
<van-cell-group inset>
|
||||||
|
<van-cell
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:label="`${item.team} · ${item.role}`"
|
||||||
|
clickable
|
||||||
|
@click="() => {
|
||||||
|
const idx = checkedIds.indexOf(item.id)
|
||||||
|
if (idx >= 0) checkedIds.splice(idx, 1)
|
||||||
|
else checkedIds.push(item.id)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #value>
|
||||||
|
<van-tag :type="item.role === '组长' ? 'primary' : undefined" size="medium">
|
||||||
|
{{ item.role }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #right-icon>
|
||||||
|
<van-checkbox :name="item.id" />
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
</van-checkbox-group>
|
||||||
|
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂未找到成员" />
|
||||||
|
|
||||||
|
<div class="footer-bar">
|
||||||
|
<van-button type="primary" block round @click="onConfirm">
|
||||||
|
确认选择 ({{ checkedIds.length }})
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
padding-bottom: 80px;
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-action {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 12px 16px;
|
||||||
|
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
135
src/views/map/index.vue
Normal file
135
src/views/map/index.vue
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 全屏地图页面
|
||||||
|
*
|
||||||
|
* MapLibre 地图容器,底部工具栏可切换图层、
|
||||||
|
* 打开弹出窗口等操作。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import TckzPop from './tckzPop.vue'
|
||||||
|
import YbPop from './ybPop.vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
/** 底部工具栏状态 */
|
||||||
|
const tools = [
|
||||||
|
{ icon: 'location-o', label: '定位' },
|
||||||
|
{ icon: 'eye-o', label: '图层' },
|
||||||
|
{ icon: 'search', label: '搜索' },
|
||||||
|
{ icon: 'records', label: '台账' },
|
||||||
|
{ icon: 'data-o', label: '仪表' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 弹窗显示控制 */
|
||||||
|
const showTckz = ref(false)
|
||||||
|
const showYb = ref(false)
|
||||||
|
|
||||||
|
function handleToolClick(label: string) {
|
||||||
|
if (label === '台账') {
|
||||||
|
showTckz.value = true
|
||||||
|
} else if (label === '仪表') {
|
||||||
|
showYb.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="map-page">
|
||||||
|
<van-nav-bar title="地图" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<!-- MapLibre 地图容器占位 -->
|
||||||
|
<div id="ytmap-container" class="map-container">
|
||||||
|
<div class="map-placeholder">
|
||||||
|
<van-icon name="map-marked" size="64" color="#ccc" />
|
||||||
|
<p class="placeholder-title">智慧水务地图</p>
|
||||||
|
<p class="placeholder-hint">MapLibre 地图将在此处加载</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部工具栏 -->
|
||||||
|
<div class="bottom-tools">
|
||||||
|
<div
|
||||||
|
v-for="tool in tools"
|
||||||
|
:key="tool.label"
|
||||||
|
class="tool-item"
|
||||||
|
@click="handleToolClick(tool.label)"
|
||||||
|
>
|
||||||
|
<van-icon :name="tool.icon" size="20" />
|
||||||
|
<span class="tool-label">{{ tool.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 弹窗组件 -->
|
||||||
|
<TckzPop v-model:show="showTckz" />
|
||||||
|
<YbPop v-model:show="showYb" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.map-page {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-container {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-placeholder {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f0f3f7;
|
||||||
|
|
||||||
|
.placeholder-title {
|
||||||
|
margin: 12px 0 4px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-hint {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-tools {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
padding: 8px 16px;
|
||||||
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.tool-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px 8px;
|
||||||
|
|
||||||
|
.tool-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
119
src/views/map/tckzPop.vue
Normal file
119
src/views/map/tckzPop.vue
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 台账控制弹窗
|
||||||
|
*
|
||||||
|
* 从地图底部弹出的台账列表,展示管网/设施信息。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
show: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:show': [val: boolean]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
/** 模拟台账数据 */
|
||||||
|
const records = ref([
|
||||||
|
{ id: 1, name: 'DN300 雨水管-城北段', type: '雨水管网', length: '2.3km' },
|
||||||
|
{ id: 2, name: 'DN400 污水管-高新区', type: '污水管网', length: '1.8km' },
|
||||||
|
{ id: 3, name: '1# 提升泵站', type: '泵站', length: '-' },
|
||||||
|
{ id: 4, name: '中山河节制闸', type: '水闸', length: '-' },
|
||||||
|
])
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
emit('update:show', false)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<van-popup
|
||||||
|
:show="show"
|
||||||
|
position="bottom"
|
||||||
|
round
|
||||||
|
:style="{ height: '50%' }"
|
||||||
|
@update:show="emit('update:show', $event)"
|
||||||
|
>
|
||||||
|
<div class="tckz-pop">
|
||||||
|
<div class="pop-header">
|
||||||
|
<span class="pop-title">台账信息</span>
|
||||||
|
<van-icon name="cross" size="20" color="#999" @click="onClose" />
|
||||||
|
</div>
|
||||||
|
<div class="pop-body">
|
||||||
|
<div
|
||||||
|
v-for="item in records"
|
||||||
|
:key="item.id"
|
||||||
|
class="record-item"
|
||||||
|
>
|
||||||
|
<div class="record-icon">
|
||||||
|
<van-icon name="notes-o" size="20" color="#1989fa" />
|
||||||
|
</div>
|
||||||
|
<div class="record-info">
|
||||||
|
<span class="record-name">{{ item.name }}</span>
|
||||||
|
<span class="record-meta">{{ item.type }} · {{ item.length }}</span>
|
||||||
|
</div>
|
||||||
|
<van-icon name="arrow" color="#ccc" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tckz-pop {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.pop-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
|
||||||
|
.pop-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pop-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.record-icon {
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-info {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.record-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
137
src/views/map/ybPop.vue
Normal file
137
src/views/map/ybPop.vue
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 仪表弹窗
|
||||||
|
*
|
||||||
|
* 从地图底部弹出的仪表/监测数据面板。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
show: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:show': [val: boolean]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
/** 模拟仪表数据 */
|
||||||
|
const gauges = ref([
|
||||||
|
{ id: 1, name: '流量', value: '12.5', unit: 'm³/h', status: 'normal' },
|
||||||
|
{ id: 2, name: '压力', value: '0.35', unit: 'MPa', status: 'normal' },
|
||||||
|
{ id: 3, name: '液位', value: '2.8', unit: 'm', status: 'alarm' },
|
||||||
|
{ id: 4, name: '水质', value: '6.8', unit: 'pH', status: 'normal' },
|
||||||
|
])
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, string> = {
|
||||||
|
normal: '#07c160',
|
||||||
|
alarm: '#ee0a24',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<van-popup
|
||||||
|
:show="show"
|
||||||
|
position="bottom"
|
||||||
|
round
|
||||||
|
:style="{ height: '40%' }"
|
||||||
|
@update:show="emit('update:show', $event)"
|
||||||
|
>
|
||||||
|
<div class="yb-pop">
|
||||||
|
<div class="pop-header">
|
||||||
|
<span class="pop-title">实时仪表</span>
|
||||||
|
<van-icon name="cross" size="20" color="#999" @click="emit('update:show', false)" />
|
||||||
|
</div>
|
||||||
|
<div class="pop-body">
|
||||||
|
<div
|
||||||
|
v-for="gauge in gauges"
|
||||||
|
:key="gauge.id"
|
||||||
|
class="gauge-item"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="gauge-dot"
|
||||||
|
:style="{ backgroundColor: statusColorMap[gauge.status] }"
|
||||||
|
/>
|
||||||
|
<div class="gauge-info">
|
||||||
|
<span class="gauge-label">{{ gauge.name }}</span>
|
||||||
|
<span class="gauge-value">
|
||||||
|
{{ gauge.value }}
|
||||||
|
<small>{{ gauge.unit }}</small>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.yb-pop {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.pop-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
|
||||||
|
.pop-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pop-body {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 24px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gauge-item {
|
||||||
|
width: calc(50% - 8px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f7f8fa;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.gauge-dot {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gauge-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.gauge-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gauge-value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
173
src/views/projectManagement/detail.vue
Normal file
173
src/views/projectManagement/detail.vue
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 项目详情页
|
||||||
|
*
|
||||||
|
* 展示单个项目的详细信息、进度和里程碑。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const detailId = computed(() => route.params.detail as string | undefined)
|
||||||
|
|
||||||
|
/** 模拟项目详情 */
|
||||||
|
const project = ref({
|
||||||
|
id: detailId.value || 'XM-2025-001',
|
||||||
|
name: '城北雨水管网改造工程',
|
||||||
|
no: 'XM-2025-001',
|
||||||
|
company: '中建三局',
|
||||||
|
progress: 75,
|
||||||
|
status: 'building',
|
||||||
|
manager: '赵工',
|
||||||
|
startDate: '2025-03-01',
|
||||||
|
endDate: '2025-12-31',
|
||||||
|
budget: '3800万元',
|
||||||
|
description: '对城北片区老旧雨水管网进行全面改造,包括新建DN300-DN600雨水管12.5km,改造检查井280座,新建雨水泵站1座。',
|
||||||
|
})
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
building: '在建',
|
||||||
|
paused: '暂停',
|
||||||
|
completed: '竣工',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusTagType: Record<string, 'primary' | 'warning' | 'success'> = {
|
||||||
|
building: 'primary',
|
||||||
|
paused: 'warning',
|
||||||
|
completed: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
function progressColor(pct: number): string {
|
||||||
|
if (pct >= 80) return '#07c160'
|
||||||
|
if (pct >= 40) return '#1989fa'
|
||||||
|
return '#ff976a'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟里程碑 */
|
||||||
|
const milestones = ref([
|
||||||
|
{ text: '项目立项', time: '2025-02-15', done: true },
|
||||||
|
{ text: '施工设计', time: '2025-03-15', done: true },
|
||||||
|
{ text: '管网铺设', time: '2025-06-30', done: true },
|
||||||
|
{ text: '泵站建设', time: '2025-09-30', done: false },
|
||||||
|
{ text: '竣工验收', time: '2025-12-31', done: false },
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="detail-page">
|
||||||
|
<van-nav-bar title="项目详情" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<van-cell-group title="基本信息" inset>
|
||||||
|
<van-cell title="项目编号" :value="project.no" />
|
||||||
|
<van-cell title="项目名称" :value="project.name" />
|
||||||
|
<van-cell title="施工单位" :value="project.company" />
|
||||||
|
<van-cell title="负责人" :value="project.manager" />
|
||||||
|
<van-cell title="计划工期">
|
||||||
|
<span class="date-range">{{ project.startDate }} ~ {{ project.endDate }}</span>
|
||||||
|
</van-cell>
|
||||||
|
<van-cell title="预算金额" :value="project.budget" />
|
||||||
|
<van-cell title="当前状态">
|
||||||
|
<van-tag :type="statusTagType[project.status]" size="medium">
|
||||||
|
{{ statusMap[project.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 项目描述 -->
|
||||||
|
<van-cell-group title="项目描述" inset>
|
||||||
|
<van-cell>
|
||||||
|
<p class="project-desc">{{ project.description }}</p>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 进度 -->
|
||||||
|
<van-cell-group title="工程进度" inset>
|
||||||
|
<div class="progress-section">
|
||||||
|
<van-progress
|
||||||
|
:percentage="project.progress"
|
||||||
|
:color="progressColor(project.progress)"
|
||||||
|
:pivot-text="`${project.progress}%`"
|
||||||
|
stroke-width="10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 里程碑 -->
|
||||||
|
<van-cell-group title="项目里程碑" inset>
|
||||||
|
<div class="milestones-section">
|
||||||
|
<van-steps :active="milestones.filter(m => m.done).length - 1" direction="vertical" active-color="#1989fa">
|
||||||
|
<van-step v-for="(step, idx) in milestones" :key="idx">
|
||||||
|
<template #active-icon>
|
||||||
|
<van-icon name="checked" color="#1989fa" />
|
||||||
|
</template>
|
||||||
|
<template #inactive-icon>
|
||||||
|
<van-icon name="clock-o" color="#ccc" />
|
||||||
|
</template>
|
||||||
|
<h4>{{ step.text }}</h4>
|
||||||
|
<p>{{ step.time }}</p>
|
||||||
|
</van-step>
|
||||||
|
</van-steps>
|
||||||
|
</div>
|
||||||
|
</van-cell-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
padding-bottom: 20px;
|
||||||
|
|
||||||
|
: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-cell-group) {
|
||||||
|
margin: 12px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-cell-group__title) {
|
||||||
|
padding: 12px 16px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-range {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-section {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milestones-section {
|
||||||
|
padding: 12px 0;
|
||||||
|
|
||||||
|
:deep(.van-step__title) {
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
143
src/views/projectManagement/index.vue
Normal file
143
src/views/projectManagement/index.vue
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 项目管理列表页
|
||||||
|
*
|
||||||
|
* 展示所有工程项目,支持搜索和按状态筛选,
|
||||||
|
* 每项显示进度条。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const searchText = ref('')
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
building: '在建',
|
||||||
|
paused: '暂停',
|
||||||
|
completed: '竣工',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusTagType: Record<string, 'primary' | 'warning' | 'success'> = {
|
||||||
|
building: 'primary',
|
||||||
|
paused: 'warning',
|
||||||
|
completed: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
function progressColor(pct: number): string {
|
||||||
|
if (pct >= 80) return '#07c160'
|
||||||
|
if (pct >= 40) return '#1989fa'
|
||||||
|
return '#ff976a'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟项目数据 */
|
||||||
|
const projects = [
|
||||||
|
{ id: 1, name: '城北雨水管网改造工程', no: 'XM-2025-001', company: '中建三局', progress: 75, status: 'building', manager: '赵工' },
|
||||||
|
{ id: 2, name: '东风路排水泵站新建项目', no: 'XM-2025-002', company: '水务工程公司', progress: 30, status: 'building', manager: '钱工' },
|
||||||
|
{ id: 3, name: '中山河河道整治工程', no: 'XM-2025-003', company: '市政建设集团', progress: 90, status: 'building', manager: '孙工' },
|
||||||
|
{ id: 4, name: '开发区污水管网铺设', no: 'XM-2025-004', company: '中交一公局', progress: 0, status: 'paused', manager: '李工' },
|
||||||
|
{ id: 5, name: '老城区雨污分流改造', no: 'XM-2025-005', company: '中铁十二局', progress: 100, status: 'completed', manager: '周工' },
|
||||||
|
{ id: 6, name: '南湖片区海绵城市试点', no: 'XM-2025-006', company: '葛洲坝集团', progress: 55, status: 'building', manager: '吴工' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = projects
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(p =>
|
||||||
|
p.name.toLowerCase().includes(kw) ||
|
||||||
|
p.no.toLowerCase().includes(kw) ||
|
||||||
|
p.company.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(p => p.status === 'building')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(p => p.status === 'paused')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(p => p.status === 'completed')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
function goDetail(id: number) {
|
||||||
|
router.push(`/projectManagementDetail/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="项目管理" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索项目名称、编号、单位" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="在建" />
|
||||||
|
<van-tab title="暂停" />
|
||||||
|
<van-tab title="竣工" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无项目" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:desc="`施工单位: ${item.company}`"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :type="statusTagType[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="progress-wrap">
|
||||||
|
<van-progress
|
||||||
|
:percentage="item.progress"
|
||||||
|
:color="progressColor(item.progress)"
|
||||||
|
:pivot-text="`${item.progress}%`"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>{{ item.no }}</span>
|
||||||
|
<span>负责人: {{ item.manager }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-wrap {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
140
src/views/pshgl/checkList.vue
Normal file
140
src/views/pshgl/checkList.vue
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户检查列表页
|
||||||
|
*
|
||||||
|
* 展示检查记录列表,支持搜索和结果筛选,显示评分。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
/** 搜索关键词 */
|
||||||
|
const searchText = ref('')
|
||||||
|
|
||||||
|
/** 当前激活的 Tab */
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 模拟检查记录数据 */
|
||||||
|
const mockCheckList = [
|
||||||
|
{ id: 1, pshName: '华丰食品厂', checkDate: '2025-06-15', inspector: '张检查员', result: 'pass', score: 92, items: '排水设施、预处理设备' },
|
||||||
|
{ id: 2, pshName: '阳光花园小区', checkDate: '2025-06-14', inspector: '李检查员', result: 'pass', score: 85, items: '化粪池、雨污管道' },
|
||||||
|
{ id: 3, pshName: '万达商业广场', checkDate: '2025-06-13', inspector: '王检查员', result: 'fail', score: 55, items: '油脂分离器、排水口' },
|
||||||
|
{ id: 4, pshName: '东风化工厂', checkDate: '2025-06-12', inspector: '赵检查员', result: 'fail', score: 40, items: '污水处理设备、排放口' },
|
||||||
|
{ id: 5, pshName: '翠湖小区', checkDate: '2025-06-11', inspector: '孙检查员', result: 'pass', score: 88, items: '雨污分流、管道畅通' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 结果映射 */
|
||||||
|
const resultMap: Record<string, string> = {
|
||||||
|
pass: '合格',
|
||||||
|
fail: '不合格',
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultColorMap: Record<string, 'success' | 'danger'> = {
|
||||||
|
pass: 'success',
|
||||||
|
fail: 'danger',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分数颜色 */
|
||||||
|
function getScoreColor(score: number): string {
|
||||||
|
if (score >= 80) return '#07c160'
|
||||||
|
if (score >= 60) return '#ff976a'
|
||||||
|
return '#ee0a24'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选后的列表 */
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockCheckList
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(c =>
|
||||||
|
c.pshName.toLowerCase().includes(kw) ||
|
||||||
|
c.inspector.toLowerCase().includes(kw) ||
|
||||||
|
c.items.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(c => c.result === 'pass')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(c => c.result === 'fail')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 跳转详情 */
|
||||||
|
function goDetail(id: number) {
|
||||||
|
router.push(`/pshCheckList/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="check-page">
|
||||||
|
<van-nav-bar title="检查记录列表" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索排水户、检查员、检查项" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="合格" />
|
||||||
|
<van-tab title="不合格" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无检查记录" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.pshName"
|
||||||
|
:desc="`检查项: ${item.items}`"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :type="resultColorMap[item.result]" size="medium">
|
||||||
|
{{ resultMap[item.result] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :color="getScoreColor(item.score)" size="medium" text-color="#fff">
|
||||||
|
{{ item.score }} 分
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>检查员: {{ item.inspector }}</span>
|
||||||
|
<span>{{ item.checkDate }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.check-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
366
src/views/pshgl/pshCheck.vue
Normal file
366
src/views/pshgl/pshCheck.vue
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户检查报告表单页
|
||||||
|
*
|
||||||
|
* 提供检查报告填写表单,包含排水设施检查、预处理设备等各项目评分,
|
||||||
|
* 支持图片上传。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showToast } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const checkId = (route.params.id || route.query.id) as string
|
||||||
|
const detailId = (route.params.detail || route.query.detail) as string
|
||||||
|
|
||||||
|
/** 表单数据 */
|
||||||
|
const formData = ref({
|
||||||
|
pshName: '',
|
||||||
|
checkDate: '',
|
||||||
|
inspector: '',
|
||||||
|
drainPipe: '',
|
||||||
|
drainPipeScore: '',
|
||||||
|
preTreatment: '',
|
||||||
|
preTreatmentScore: '',
|
||||||
|
oilSeparator: '',
|
||||||
|
oilSeparatorScore: '',
|
||||||
|
rainSewage: '',
|
||||||
|
rainSewageScore: '',
|
||||||
|
overall: '',
|
||||||
|
overallScore: '',
|
||||||
|
suggestion: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 排水户选项 */
|
||||||
|
const pshOptions = [
|
||||||
|
{ text: '华丰食品厂', value: '华丰食品厂' },
|
||||||
|
{ text: '阳光花园小区', value: '阳光花园小区' },
|
||||||
|
{ text: '万达商业广场', value: '万达商业广场' },
|
||||||
|
{ text: '东风化工厂', value: '东风化工厂' },
|
||||||
|
{ text: '翠湖小区', value: '翠湖小区' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 评分选项 */
|
||||||
|
const scoreOptions = [
|
||||||
|
{ text: '5分 - 优秀', value: '5' },
|
||||||
|
{ text: '4分 - 良好', value: '4' },
|
||||||
|
{ text: '3分 - 一般', value: '3' },
|
||||||
|
{ text: '2分 - 较差', value: '2' },
|
||||||
|
{ text: '1分 - 很差', value: '1' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 结果选项 */
|
||||||
|
const overallOptions = [
|
||||||
|
{ text: '合格', value: 'pass' },
|
||||||
|
{ text: '不合格', value: 'fail' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 选择器状态 */
|
||||||
|
const showPshPicker = ref(false)
|
||||||
|
const showDrainPipeScore = ref(false)
|
||||||
|
const showPreTreatmentScore = ref(false)
|
||||||
|
const showOilSeparatorScore = ref(false)
|
||||||
|
const showRainSewageScore = ref(false)
|
||||||
|
const showOverallScore = ref(false)
|
||||||
|
const showOverall = ref(false)
|
||||||
|
|
||||||
|
/** 上传文件列表 */
|
||||||
|
const uploaderList = ref<{ url: string }[]>([])
|
||||||
|
|
||||||
|
/** 选择排水户 */
|
||||||
|
function onConfirmPsh({ selectedOptions }: any) {
|
||||||
|
formData.value.pshName = selectedOptions[0]?.text || ''
|
||||||
|
showPshPicker.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择评分 */
|
||||||
|
function onConfirmScore(field: string, { selectedOptions }: any) {
|
||||||
|
(formData.value as any)[field] = selectedOptions[0]?.text || ''
|
||||||
|
const scoreFields: Record<string, string> = {
|
||||||
|
drainPipeScore: 'showDrainPipeScore',
|
||||||
|
preTreatmentScore: 'showPreTreatmentScore',
|
||||||
|
oilSeparatorScore: 'showOilSeparatorScore',
|
||||||
|
rainSewageScore: 'showRainSewageScore',
|
||||||
|
overallScore: 'showOverallScore',
|
||||||
|
}
|
||||||
|
;(ref as any)[scoreFields[field]].value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 确认综合评定 */
|
||||||
|
function onConfirmOverall({ selectedOptions }: any) {
|
||||||
|
formData.value.overall = selectedOptions[0]?.text || ''
|
||||||
|
showOverall.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 上传图片后回调 */
|
||||||
|
function afterRead(file: any) {
|
||||||
|
uploaderList.value.push({ url: file.content || '' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
function onSubmit() {
|
||||||
|
if (!formData.value.pshName) {
|
||||||
|
showToast('请选择排水户')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.checkDate) {
|
||||||
|
showToast('请选择检查日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showToast('检查报告提交成功')
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="check-form-page">
|
||||||
|
<van-nav-bar title="检查报告" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-form @submit="onSubmit" class="form-wrapper">
|
||||||
|
<van-cell-group title="基本信息" class="form-group">
|
||||||
|
<!-- 排水户选择 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.pshName"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="pshName"
|
||||||
|
label="排水户"
|
||||||
|
placeholder="请选择排水户"
|
||||||
|
:rules="[{ required: true, message: '请选择排水户' }]"
|
||||||
|
@click="showPshPicker = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showPshPicker" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="pshOptions"
|
||||||
|
@confirm="onConfirmPsh"
|
||||||
|
@cancel="showPshPicker = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<!-- 检查日期 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.checkDate"
|
||||||
|
name="checkDate"
|
||||||
|
label="检查日期"
|
||||||
|
placeholder="请选择日期"
|
||||||
|
:rules="[{ required: true, message: '请选择检查日期' }]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 检查人 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.inspector"
|
||||||
|
name="inspector"
|
||||||
|
label="检查人"
|
||||||
|
placeholder="请输入检查人姓名"
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group title="检查项目" class="form-group">
|
||||||
|
<!-- 排水管道 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.drainPipe"
|
||||||
|
name="drainPipe"
|
||||||
|
label="排水管道"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
placeholder="描述排水管道状况"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="formData.drainPipeScore"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="drainPipeScore"
|
||||||
|
label="评分"
|
||||||
|
placeholder="请选择评分"
|
||||||
|
@click="showDrainPipeScore = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showDrainPipeScore" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="scoreOptions"
|
||||||
|
@confirm="(v: any) => onConfirmScore('drainPipeScore', v)"
|
||||||
|
@cancel="showDrainPipeScore = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<!-- 预处理设备 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.preTreatment"
|
||||||
|
name="preTreatment"
|
||||||
|
label="预处理设备"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
placeholder="描述预处理设备状况"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="formData.preTreatmentScore"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="preTreatmentScore"
|
||||||
|
label="评分"
|
||||||
|
placeholder="请选择评分"
|
||||||
|
@click="showPreTreatmentScore = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showPreTreatmentScore" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="scoreOptions"
|
||||||
|
@confirm="(v: any) => onConfirmScore('preTreatmentScore', v)"
|
||||||
|
@cancel="showPreTreatmentScore = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<!-- 油脂分离器 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.oilSeparator"
|
||||||
|
name="oilSeparator"
|
||||||
|
label="油脂分离器"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
placeholder="描述油脂分离器状况"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="formData.oilSeparatorScore"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="oilSeparatorScore"
|
||||||
|
label="评分"
|
||||||
|
placeholder="请选择评分"
|
||||||
|
@click="showOilSeparatorScore = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showOilSeparatorScore" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="scoreOptions"
|
||||||
|
@confirm="(v: any) => onConfirmScore('oilSeparatorScore', v)"
|
||||||
|
@cancel="showOilSeparatorScore = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<!-- 雨污分流 -->
|
||||||
|
<van-field
|
||||||
|
v-model="formData.rainSewage"
|
||||||
|
name="rainSewage"
|
||||||
|
label="雨污分流"
|
||||||
|
type="textarea"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
placeholder="描述雨污分流状况"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="formData.rainSewageScore"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="rainSewageScore"
|
||||||
|
label="评分"
|
||||||
|
placeholder="请选择评分"
|
||||||
|
@click="showRainSewageScore = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showRainSewageScore" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="scoreOptions"
|
||||||
|
@confirm="(v: any) => onConfirmScore('rainSewageScore', v)"
|
||||||
|
@cancel="showRainSewageScore = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group title="综合评定" class="form-group">
|
||||||
|
<van-field
|
||||||
|
v-model="formData.overall"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="overall"
|
||||||
|
label="综合评定"
|
||||||
|
placeholder="请选择评定结果"
|
||||||
|
@click="showOverall = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showOverall" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="overallOptions"
|
||||||
|
@confirm="onConfirmOverall"
|
||||||
|
@cancel="showOverall = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<van-field
|
||||||
|
v-model="formData.overallScore"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
name="overallScore"
|
||||||
|
label="综合评分"
|
||||||
|
placeholder="请选择综合评分"
|
||||||
|
@click="showOverallScore = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showOverallScore" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:columns="scoreOptions"
|
||||||
|
@confirm="(v: any) => onConfirmScore('overallScore', v)"
|
||||||
|
@cancel="showOverallScore = false"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
|
<van-field
|
||||||
|
v-model="formData.suggestion"
|
||||||
|
name="suggestion"
|
||||||
|
label="整改建议"
|
||||||
|
type="textarea"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
placeholder="请输入整改建议"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group title="现场照片" class="form-group">
|
||||||
|
<van-uploader
|
||||||
|
v-model="uploaderList"
|
||||||
|
:after-read="afterRead"
|
||||||
|
multiple
|
||||||
|
:max-count="6"
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<div class="submit-area">
|
||||||
|
<van-button round block type="primary" native-type="submit">
|
||||||
|
提交检查报告
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</van-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.check-form-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-wrapper {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
:deep(.van-uploader) {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-area {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
234
src/views/pshgl/pshCheckList.vue
Normal file
234
src/views/pshgl/pshCheckList.vue
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户检查选择列表页
|
||||||
|
*
|
||||||
|
* 展示待检查的排水户列表,支持搜索和复选框多选,
|
||||||
|
* 选中后可进入检查填报页面。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showToast } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const pshId = (route.params.id || route.query.id) as string
|
||||||
|
|
||||||
|
/** 搜索关键词 */
|
||||||
|
const searchText = ref('')
|
||||||
|
|
||||||
|
/** 选中的排水户 ID 列表 */
|
||||||
|
const checkedIds = ref<number[]>([])
|
||||||
|
|
||||||
|
/** 模拟待检查排水户数据 */
|
||||||
|
const mockDrainUsers = [
|
||||||
|
{ id: 1, name: '华丰食品厂', type: 'industrial', address: '城北工业园区A1栋', lastCheck: '2025-05-15', status: 'normal' },
|
||||||
|
{ id: 2, name: '阳光花园小区', type: 'domestic', address: '阳光路88号', lastCheck: '2025-04-20', status: 'normal' },
|
||||||
|
{ id: 3, name: '万达商业广场', type: 'commercial', address: '中山路100号', lastCheck: '2025-05-10', status: 'warning' },
|
||||||
|
{ id: 4, name: '东风化工厂', type: 'industrial', address: '高新区化工大道56号', lastCheck: '2025-03-01', status: 'danger' },
|
||||||
|
{ id: 5, name: '翠湖小区', type: 'domestic', address: '翠湖路66号', lastCheck: '2025-06-01', status: 'normal' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 类型映射 */
|
||||||
|
const typeMap: Record<string, string> = {
|
||||||
|
industrial: '工业',
|
||||||
|
domestic: '生活',
|
||||||
|
commercial: '商业',
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeColorMap: Record<string, string> = {
|
||||||
|
industrial: '#1989fa',
|
||||||
|
domestic: '#07c160',
|
||||||
|
commercial: '#ff976a',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
normal: '正常',
|
||||||
|
warning: '需检查',
|
||||||
|
danger: '急需检查',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'success' | 'warning' | 'danger'> = {
|
||||||
|
normal: 'success',
|
||||||
|
warning: 'warning',
|
||||||
|
danger: 'danger',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选后的列表 */
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockDrainUsers
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(d =>
|
||||||
|
d.name.toLowerCase().includes(kw) ||
|
||||||
|
d.address.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 切换选中 */
|
||||||
|
function toggleCheck(id: number) {
|
||||||
|
const idx = checkedIds.value.indexOf(id)
|
||||||
|
if (idx > -1) {
|
||||||
|
checkedIds.value.splice(idx, 1)
|
||||||
|
} else {
|
||||||
|
checkedIds.value.push(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 全选/取消全选 */
|
||||||
|
const isAllChecked = computed(() => {
|
||||||
|
return filteredList.value.length > 0 && checkedIds.value.length === filteredList.value.length
|
||||||
|
})
|
||||||
|
|
||||||
|
function toggleAll() {
|
||||||
|
if (isAllChecked.value) {
|
||||||
|
checkedIds.value = []
|
||||||
|
} else {
|
||||||
|
checkedIds.value = filteredList.value.map(d => d.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 开始检查 */
|
||||||
|
function startCheck() {
|
||||||
|
if (checkedIds.value.length === 0) {
|
||||||
|
showToast('请选择排水户')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const ids = checkedIds.value.join(',')
|
||||||
|
router.push(`/pshCheck/${ids}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="check-select-page">
|
||||||
|
<van-nav-bar title="选择检查排水户" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索排水户名称、地址" shape="round" />
|
||||||
|
|
||||||
|
<div class="toolbar">
|
||||||
|
<van-checkbox :model-value="isAllChecked" @change="toggleAll">全选</van-checkbox>
|
||||||
|
<span class="count-text">已选 {{ checkedIds.length }} 户</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无排水户" />
|
||||||
|
<div
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
class="check-card"
|
||||||
|
@click="toggleCheck(item.id)"
|
||||||
|
>
|
||||||
|
<van-checkbox :model-value="checkedIds.includes(item.id)" />
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<van-tag :color="typeColorMap[item.type]" size="medium" text-color="#fff">
|
||||||
|
{{ typeMap[item.type] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
<div class="card-desc">{{ item.address }}</div>
|
||||||
|
<div class="card-meta">上次检查: {{ item.lastCheck }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bottom-bar">
|
||||||
|
<van-button type="primary" block round @click="startCheck">
|
||||||
|
开始检查 ({{ checkedIds.length }})
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.check-select-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
padding-bottom: 80px;
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
|
||||||
|
.count-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
:deep(.van-checkbox) {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
151
src/views/pshgl/pshList.vue
Normal file
151
src/views/pshgl/pshList.vue
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户管理列表页
|
||||||
|
*
|
||||||
|
* 展示排水户列表,支持搜索和类型筛选,
|
||||||
|
* 点击卡片跳转排水户详情。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
/** 搜索关键词 */
|
||||||
|
const searchText = ref('')
|
||||||
|
|
||||||
|
/** 当前激活的 Tab (全部/工业/生活/商业) */
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 模拟排水户数据 */
|
||||||
|
const mockPshList = [
|
||||||
|
{ id: 1, name: '华丰食品厂', type: 'industrial', address: '城北工业园区A1栋', contact: '张经理', phone: '13800001011', status: 'normal', drainNo: 'PSH-2025-001' },
|
||||||
|
{ id: 2, name: '阳光花园小区', type: 'domestic', address: '阳光路88号', contact: '李主任', phone: '13800001012', status: 'normal', drainNo: 'PSH-2025-002' },
|
||||||
|
{ id: 3, name: '万达商业广场', type: 'commercial', address: '中山路100号', contact: '王主管', phone: '13800001013', status: 'warning', drainNo: 'PSH-2025-003' },
|
||||||
|
{ id: 4, name: '东风化工厂', type: 'industrial', address: '高新区化工大道56号', contact: '赵厂长', phone: '13800001014', status: 'danger', drainNo: 'PSH-2025-004' },
|
||||||
|
{ id: 5, name: '翠湖小区', type: 'domestic', address: '翠湖路66号', contact: '孙主任', phone: '13800001015', status: 'normal', drainNo: 'PSH-2025-005' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 类型映射 */
|
||||||
|
const typeMap: Record<string, string> = {
|
||||||
|
industrial: '工业',
|
||||||
|
domestic: '生活',
|
||||||
|
commercial: '商业',
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeColorMap: Record<string, string> = {
|
||||||
|
industrial: '#1989fa',
|
||||||
|
domestic: '#07c160',
|
||||||
|
commercial: '#ff976a',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
normal: '正常',
|
||||||
|
warning: '异常',
|
||||||
|
danger: '严重',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'success' | 'warning' | 'danger'> = {
|
||||||
|
normal: 'success',
|
||||||
|
warning: 'warning',
|
||||||
|
danger: 'danger',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选后的列表 */
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockPshList
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(p =>
|
||||||
|
p.name.toLowerCase().includes(kw) ||
|
||||||
|
p.address.toLowerCase().includes(kw) ||
|
||||||
|
p.drainNo.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(p => p.type === 'industrial')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(p => p.type === 'domestic')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(p => p.type === 'commercial')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 跳转详情 */
|
||||||
|
function goDetail(id: number) {
|
||||||
|
router.push(`/pshglDetail/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="psh-list-page">
|
||||||
|
<van-nav-bar title="排水户管理" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索名称、地址、编号" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="工业" />
|
||||||
|
<van-tab title="生活" />
|
||||||
|
<van-tab title="商业" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无排水户" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:desc="item.address"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :color="typeColorMap[item.type]" size="medium" text-color="#fff">
|
||||||
|
{{ typeMap[item.type] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>联系人: {{ item.contact }}</span>
|
||||||
|
<span>{{ item.drainNo }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.psh-list-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
167
src/views/pshgl/pshProblemDetail.vue
Normal file
167
src/views/pshgl/pshProblemDetail.vue
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户问题详情页
|
||||||
|
*
|
||||||
|
* 展示排水户问题详细信息,支持处理/转派等操作。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showToast } from 'vant'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const problemId = (route.params.detail || route.query.id) as string
|
||||||
|
|
||||||
|
/** 模拟问题详情 */
|
||||||
|
const problem = ref({
|
||||||
|
id: problemId || '1',
|
||||||
|
pshName: '华丰食品厂',
|
||||||
|
title: '排水管道堵塞',
|
||||||
|
severity: 'high',
|
||||||
|
status: 'pending',
|
||||||
|
reporter: '张工',
|
||||||
|
reportTime: '2025-06-15 09:30',
|
||||||
|
address: '城北工业园区A1栋东侧排水口',
|
||||||
|
description: '日常巡检中发现华丰食品厂东侧排水管道存在严重堵塞现象,排水不畅导致污水溢出,存在环境污染风险。经初步排查,堵塞原因为油脂凝固和杂物堆积。需尽快安排疏通车进行清淤处理,并建议排水户定期清理隔油池。',
|
||||||
|
assignee: '待分配',
|
||||||
|
createTime: '2025-06-15 09:30:00',
|
||||||
|
updateTime: '2025-06-15 09:30:00',
|
||||||
|
})
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '待处理',
|
||||||
|
processing: '处理中',
|
||||||
|
resolved: '已解决',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'primary' | 'success' | 'warning' | 'danger'> = {
|
||||||
|
pending: 'warning',
|
||||||
|
processing: 'primary',
|
||||||
|
resolved: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
const severityMap: Record<string, string> = {
|
||||||
|
low: '低',
|
||||||
|
medium: '中',
|
||||||
|
high: '高',
|
||||||
|
critical: '紧急',
|
||||||
|
}
|
||||||
|
|
||||||
|
const severityColorMap: Record<string, string> = {
|
||||||
|
low: '#07c160',
|
||||||
|
medium: '#ff976a',
|
||||||
|
high: '#ee0a24',
|
||||||
|
critical: '#ee0a24',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 接单 */
|
||||||
|
function acceptProblem() {
|
||||||
|
showToast('已接单处理')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 转派 */
|
||||||
|
function transferProblem() {
|
||||||
|
showToast('转派功能')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 解决 */
|
||||||
|
function resolveProblem() {
|
||||||
|
showToast('已标记为已解决')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="detail-page">
|
||||||
|
<van-nav-bar title="问题详情" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="status-bar">
|
||||||
|
<van-tag :type="statusColorMap[problem.status]" size="large">
|
||||||
|
{{ statusMap[problem.status] }}
|
||||||
|
</van-tag>
|
||||||
|
<span class="severity-tag" :style="{ color: severityColorMap[problem.severity] }">
|
||||||
|
严重程度: {{ severityMap[problem.severity] }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<van-cell-group title="基本信息" class="info-group">
|
||||||
|
<van-cell title="问题编号" :value="`PSH-PROB-${problem.id}`" />
|
||||||
|
<van-cell title="问题标题" :value="problem.title" />
|
||||||
|
<van-cell title="所属排水户" :value="problem.pshName" />
|
||||||
|
<van-cell title="上报人员" :value="problem.reporter" />
|
||||||
|
<van-cell title="上报时间" :value="problem.reportTime" />
|
||||||
|
<van-cell title="问题地址" :value="problem.address" />
|
||||||
|
<van-cell title="责任人" :value="problem.assignee" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 问题描述 -->
|
||||||
|
<van-cell-group title="问题描述" class="info-group">
|
||||||
|
<van-cell>
|
||||||
|
<p class="desc-text">{{ problem.description }}</p>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 时间信息 -->
|
||||||
|
<van-cell-group title="时间信息" class="info-group">
|
||||||
|
<van-cell title="创建时间" :value="problem.createTime" />
|
||||||
|
<van-cell title="更新时间" :value="problem.updateTime" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="action-buttons">
|
||||||
|
<van-button type="primary" block round @click="acceptProblem">接单处理</van-button>
|
||||||
|
<van-button plain block round class="mt-sm" @click="transferProblem">转派他人</van-button>
|
||||||
|
<van-button type="success" block round class="mt-sm" @click="resolveProblem">标记已解决</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.severity-tag {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-group {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
padding: 24px 16px;
|
||||||
|
|
||||||
|
.mt-sm {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
155
src/views/pshgl/pshProblemList.vue
Normal file
155
src/views/pshgl/pshProblemList.vue
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户问题列表页
|
||||||
|
*
|
||||||
|
* 展示排水户相关问题列表,支持搜索和状态筛选。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const pshId = (route.params.id || route.query.id) as string
|
||||||
|
|
||||||
|
/** 搜索关键词 */
|
||||||
|
const searchText = ref('')
|
||||||
|
|
||||||
|
/** 当前激活的 Tab */
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 模拟问题数据 */
|
||||||
|
const mockProblems = [
|
||||||
|
{ id: 1, pshName: '华丰食品厂', title: '排水管道堵塞', severity: 'high', status: 'pending', reportTime: '2025-06-15 09:30', reporter: '张工' },
|
||||||
|
{ id: 2, pshName: '阳光花园小区', title: '化粪池溢出', severity: 'medium', status: 'processing', reportTime: '2025-06-15 11:00', reporter: '李工' },
|
||||||
|
{ id: 3, pshName: '万达商业广场', title: '油脂分离器故障', severity: 'low', status: 'resolved', reportTime: '2025-06-14 08:00', reporter: '王工' },
|
||||||
|
{ id: 4, pshName: '东风化工厂', title: '污水超标排放', severity: 'critical', status: 'pending', reportTime: '2025-06-16 10:00', reporter: '赵工' },
|
||||||
|
{ id: 5, pshName: '翠湖小区', title: '雨污混接', severity: 'medium', status: 'processing', reportTime: '2025-06-15 14:30', reporter: '孙工' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '待处理',
|
||||||
|
processing: '处理中',
|
||||||
|
resolved: '已解决',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'primary' | 'success' | 'warning' | 'danger'> = {
|
||||||
|
pending: 'warning',
|
||||||
|
processing: 'primary',
|
||||||
|
resolved: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 严重程度映射 */
|
||||||
|
const severityMap: Record<string, string> = {
|
||||||
|
low: '低',
|
||||||
|
medium: '中',
|
||||||
|
high: '高',
|
||||||
|
critical: '紧急',
|
||||||
|
}
|
||||||
|
|
||||||
|
const severityColorMap: Record<string, string> = {
|
||||||
|
low: '#07c160',
|
||||||
|
medium: '#ff976a',
|
||||||
|
high: '#ee0a24',
|
||||||
|
critical: '#ee0a24',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选后的列表 */
|
||||||
|
const filteredProblems = computed(() => {
|
||||||
|
let list = mockProblems
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(p =>
|
||||||
|
p.title.toLowerCase().includes(kw) ||
|
||||||
|
p.pshName.toLowerCase().includes(kw) ||
|
||||||
|
p.reporter.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(p => p.status === 'pending')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(p => p.status === 'processing')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(p => p.status === 'resolved')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 跳转详情 */
|
||||||
|
function goDetail(id: number) {
|
||||||
|
router.push(`/pshProblemDetail/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="problem-page">
|
||||||
|
<van-nav-bar title="排水户问题列表" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索问题标题、排水户、上报人" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="待处理" />
|
||||||
|
<van-tab title="处理中" />
|
||||||
|
<van-tab title="已解决" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredProblems.length === 0" description="暂无问题" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredProblems"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.title"
|
||||||
|
:desc="`排水户: ${item.pshName}`"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :color="severityColorMap[item.severity]" size="medium" text-color="#fff" plain>
|
||||||
|
{{ severityMap[item.severity] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>上报人: {{ item.reporter }}</span>
|
||||||
|
<span>{{ item.reportTime }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.problem-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
161
src/views/pshgl/pshTaskList.vue
Normal file
161
src/views/pshgl/pshTaskList.vue
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户任务管理页
|
||||||
|
*
|
||||||
|
* 展示排水户相关任务列表,支持搜索和状态筛选。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const pshId = (route.params.detail || route.query.id) as string
|
||||||
|
|
||||||
|
/** 搜索关键词 */
|
||||||
|
const searchText = ref('')
|
||||||
|
|
||||||
|
/** 当前激活的 Tab */
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 模拟任务数据 */
|
||||||
|
const mockTasks = [
|
||||||
|
{ id: 1, pshName: '华丰食品厂', title: '排水管道清淤', type: 'clean', status: 'pending', assignee: '李师傅', deadline: '2025-06-20', createTime: '2025-06-15' },
|
||||||
|
{ id: 2, pshName: '阳光花园小区', title: '化粪池清理', type: 'maintenance', status: 'doing', assignee: '王师傅', deadline: '2025-06-18', createTime: '2025-06-14' },
|
||||||
|
{ id: 3, pshName: '万达商业广场', title: '油脂分离器检修', type: 'repair', status: 'done', assignee: '赵师傅', deadline: '2025-06-16', createTime: '2025-06-13' },
|
||||||
|
{ id: 4, pshName: '东风化工厂', title: '污水取样检测', type: 'inspection', status: 'pending', assignee: '孙师傅', deadline: '2025-06-22', createTime: '2025-06-16' },
|
||||||
|
{ id: 5, pshName: '翠湖小区', title: '雨污分流改造', type: 'construction', status: 'doing', assignee: '周师傅', deadline: '2025-07-01', createTime: '2025-06-10' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '待执行',
|
||||||
|
doing: '执行中',
|
||||||
|
done: '已完成',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'primary' | 'success' | 'warning'> = {
|
||||||
|
pending: 'warning',
|
||||||
|
doing: 'primary',
|
||||||
|
done: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 任务类型映射 */
|
||||||
|
const typeMap: Record<string, string> = {
|
||||||
|
clean: '清淤',
|
||||||
|
maintenance: '养护',
|
||||||
|
repair: '维修',
|
||||||
|
inspection: '检查',
|
||||||
|
construction: '施工',
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeColorMap: Record<string, string> = {
|
||||||
|
clean: '#1989fa',
|
||||||
|
maintenance: '#07c160',
|
||||||
|
repair: '#ff976a',
|
||||||
|
inspection: '#7232dd',
|
||||||
|
construction: '#ee0a24',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选后的任务列表 */
|
||||||
|
const filteredTasks = computed(() => {
|
||||||
|
let list = mockTasks
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(t =>
|
||||||
|
t.title.toLowerCase().includes(kw) ||
|
||||||
|
t.pshName.toLowerCase().includes(kw) ||
|
||||||
|
t.assignee.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(t => t.status === 'pending')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(t => t.status === 'doing')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(t => t.status === 'done')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 跳转任务详情 */
|
||||||
|
function goTaskDetail(id: number) {
|
||||||
|
router.push(`/pshTaskList/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="task-page">
|
||||||
|
<van-nav-bar title="排水户任务管理" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索任务、排水户、负责人" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="待执行" />
|
||||||
|
<van-tab title="执行中" />
|
||||||
|
<van-tab title="已完成" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredTasks.length === 0" description="暂无任务" />
|
||||||
|
<van-card
|
||||||
|
v-for="task in filteredTasks"
|
||||||
|
:key="task.id"
|
||||||
|
:title="task.title"
|
||||||
|
:desc="`排水户: ${task.pshName}`"
|
||||||
|
@click="goTaskDetail(task.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :color="typeColorMap[task.type]" size="medium" text-color="#fff">
|
||||||
|
{{ typeMap[task.type] }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="statusColorMap[task.status]" size="medium">
|
||||||
|
{{ statusMap[task.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>负责人: {{ task.assignee }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>截止: {{ task.deadline }}</span>
|
||||||
|
<span>创建: {{ task.createTime }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.task-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
131
src/views/pshgl/pshglDetail.vue
Normal file
131
src/views/pshgl/pshglDetail.vue
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 排水户详情页
|
||||||
|
*
|
||||||
|
* 展示排水户详细信息,包含基本信息、排水许可、检查记录等。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const detailId = (route.params.detail || route.query.id) as string
|
||||||
|
|
||||||
|
/** 模拟排水户详情 */
|
||||||
|
const drainUser = ref({
|
||||||
|
id: detailId || '1',
|
||||||
|
name: '华丰食品厂',
|
||||||
|
type: 'industrial',
|
||||||
|
typeLabel: '工业',
|
||||||
|
address: '城北工业园区A1栋',
|
||||||
|
contact: '张经理',
|
||||||
|
phone: '13800001011',
|
||||||
|
drainNo: 'PSH-2025-001',
|
||||||
|
status: 'normal',
|
||||||
|
statusLabel: '正常',
|
||||||
|
licenseNo: '排水许可证-2025-001',
|
||||||
|
licenseDate: '2025-01-15',
|
||||||
|
licenseExpire: '2030-01-14',
|
||||||
|
dischargeVolume: '500吨/日',
|
||||||
|
pipeMaterial: 'PE管',
|
||||||
|
pipeDiameter: 'DN300',
|
||||||
|
monitorPoint: '2个监测点',
|
||||||
|
remark: '该排水户已安装在线监测设备,运行正常。',
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 类型颜色 */
|
||||||
|
const typeColorMap: Record<string, string> = {
|
||||||
|
industrial: '#1989fa',
|
||||||
|
domestic: '#07c160',
|
||||||
|
commercial: '#ff976a',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'success' | 'warning' | 'danger'> = {
|
||||||
|
normal: 'success',
|
||||||
|
warning: 'warning',
|
||||||
|
danger: 'danger',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="detail-page">
|
||||||
|
<van-nav-bar title="排水户详情" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="status-bar">
|
||||||
|
<van-tag :color="typeColorMap[drainUser.type]" size="large" text-color="#fff">
|
||||||
|
{{ drainUser.typeLabel }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag :type="statusColorMap[drainUser.status]" size="large">
|
||||||
|
{{ drainUser.statusLabel }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<van-cell-group title="基本信息" class="info-group">
|
||||||
|
<van-cell title="排水户名称" :value="drainUser.name" />
|
||||||
|
<van-cell title="排水户编号" :value="drainUser.drainNo" />
|
||||||
|
<van-cell title="地址" :value="drainUser.address" />
|
||||||
|
<van-cell title="联系人" :value="drainUser.contact" />
|
||||||
|
<van-cell title="联系电话" :value="drainUser.phone" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 排水许可 -->
|
||||||
|
<van-cell-group title="排水许可" class="info-group">
|
||||||
|
<van-cell title="许可证编号" :value="drainUser.licenseNo" />
|
||||||
|
<van-cell title="发证日期" :value="drainUser.licenseDate" />
|
||||||
|
<van-cell title="有效期至" :value="drainUser.licenseExpire" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 排放信息 -->
|
||||||
|
<van-cell-group title="排放信息" class="info-group">
|
||||||
|
<van-cell title="排放量" :value="drainUser.dischargeVolume" />
|
||||||
|
<van-cell title="管道材质" :value="drainUser.pipeMaterial" />
|
||||||
|
<van-cell title="管径" :value="drainUser.pipeDiameter" />
|
||||||
|
<van-cell title="监测点" :value="drainUser.monitorPoint" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<!-- 备注 -->
|
||||||
|
<van-cell-group title="备注信息" class="info-group">
|
||||||
|
<van-cell>
|
||||||
|
<p class="desc-text">{{ drainUser.remark }}</p>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-group {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
159
src/views/xjgl/constructionDetail.vue
Normal file
159
src/views/xjgl/constructionDetail.vue
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 工程项目详情
|
||||||
|
*
|
||||||
|
* 展示工程项目的详细信息,包括基本信息、
|
||||||
|
* 施工进度、现场照片等。
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
/** 模拟项目详情 */
|
||||||
|
const project = {
|
||||||
|
id: route.params.id,
|
||||||
|
name: '城北雨水管网改造工程',
|
||||||
|
no: 'XM-2025-001',
|
||||||
|
company: '中建三局',
|
||||||
|
manager: '赵工',
|
||||||
|
phone: '13800001010',
|
||||||
|
progress: 75,
|
||||||
|
status: 'building',
|
||||||
|
startDate: '2025-03-01',
|
||||||
|
endDate: '2025-09-30',
|
||||||
|
budget: '1250万元',
|
||||||
|
address: '城北工业园区大道路段',
|
||||||
|
description: '该项目对城北工业园区范围内雨水管网进行全面改造升级,包括主管网更换、检查井增设、雨水口改造等内容。改造完成后将显著提升区域排水能力。',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟现场照片 */
|
||||||
|
const photos = ref([
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' },
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/apple-1.jpg' },
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/apple-2.jpg' },
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/apple-3.jpg' },
|
||||||
|
])
|
||||||
|
|
||||||
|
function progressColor(pct: number): string {
|
||||||
|
if (pct >= 80) return '#07c160'
|
||||||
|
if (pct >= 40) return '#1989fa'
|
||||||
|
return '#ff976a'
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
building: '在建',
|
||||||
|
paused: '暂停',
|
||||||
|
completed: '竣工',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar
|
||||||
|
title="项目详情"
|
||||||
|
left-arrow
|
||||||
|
fixed
|
||||||
|
placeholder
|
||||||
|
@click-left="router.back()"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-cell-group inset>
|
||||||
|
<van-cell title="项目名称" :value="project.name" />
|
||||||
|
<van-cell title="项目编号" :value="project.no" />
|
||||||
|
<van-cell title="施工单位" :value="project.company" />
|
||||||
|
<van-cell title="项目负责人" :value="project.manager" />
|
||||||
|
<van-cell title="联系电话" :value="project.phone" />
|
||||||
|
<van-cell title="项目状态">
|
||||||
|
<template #value>
|
||||||
|
<van-tag type="primary" size="medium">{{ statusMap[project.status] }}</van-tag>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
<van-cell title="施工地址" :value="project.address" />
|
||||||
|
<van-cell title="开工日期" :value="project.startDate" />
|
||||||
|
<van-cell title="计划竣工" :value="project.endDate" />
|
||||||
|
<van-cell title="项目预算" :value="project.budget" />
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group inset style="margin-top: 12px">
|
||||||
|
<van-cell title="施工进度" />
|
||||||
|
<div class="progress-section">
|
||||||
|
<van-progress
|
||||||
|
:percentage="project.progress"
|
||||||
|
:color="progressColor(project.progress)"
|
||||||
|
:pivot-text="`${project.progress}%`"
|
||||||
|
stroke-width="12"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group inset style="margin-top: 12px">
|
||||||
|
<van-cell title="项目概述" />
|
||||||
|
<div class="content-block">{{ project.description }}</div>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<div class="photo-section" v-if="photos.length > 0">
|
||||||
|
<div class="section-title">现场照片</div>
|
||||||
|
<div class="photo-grid">
|
||||||
|
<van-image
|
||||||
|
v-for="(photo, idx) in photos"
|
||||||
|
:key="idx"
|
||||||
|
:src="photo.url"
|
||||||
|
width="100%"
|
||||||
|
height="100"
|
||||||
|
fit="cover"
|
||||||
|
radius="8"
|
||||||
|
lazy-load
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-section {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-block {
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: var(--color-text-regular);
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-section {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
148
src/views/xjgl/constructionList.vue
Normal file
148
src/views/xjgl/constructionList.vue
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 工程项目列表
|
||||||
|
*
|
||||||
|
* 展示在建工程项目列表,支持按状态筛选和搜索,
|
||||||
|
* 显示项目进度信息。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const searchText = ref('')
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 状态映射 */
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
building: '在建',
|
||||||
|
paused: '暂停',
|
||||||
|
completed: '竣工',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusColorMap: Record<string, 'primary' | 'warning' | 'success'> = {
|
||||||
|
building: 'primary',
|
||||||
|
paused: 'warning',
|
||||||
|
completed: 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 进度颜色 */
|
||||||
|
function progressColor(pct: number): string {
|
||||||
|
if (pct >= 80) return '#07c160'
|
||||||
|
if (pct >= 40) return '#1989fa'
|
||||||
|
return '#ff976a'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟项目数据 */
|
||||||
|
const mockProjects = [
|
||||||
|
{ id: 1, name: '城北雨水管网改造工程', no: 'XM-2025-001', company: '中建三局', progress: 75, status: 'building', manager: '赵工', startDate: '2025-03-01' },
|
||||||
|
{ id: 2, name: '东风路排水泵站新建项目', no: 'XM-2025-002', company: '水务工程公司', progress: 30, status: 'building', manager: '钱工', startDate: '2025-04-15' },
|
||||||
|
{ id: 3, name: '中山河河道整治工程', no: 'XM-2025-003', company: '市政建设集团', progress: 90, status: 'building', manager: '孙工', startDate: '2025-01-10' },
|
||||||
|
{ id: 4, name: '开发区污水管网铺设', no: 'XM-2025-004', company: '中交一公局', progress: 0, status: 'paused', manager: '李工', startDate: '2025-05-01' },
|
||||||
|
{ id: 5, name: '老城区雨污分流改造', no: 'XM-2025-005', company: '中铁十二局', progress: 100, status: 'completed', manager: '周工', startDate: '2024-09-01' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
let list = mockProjects
|
||||||
|
if (searchText.value) {
|
||||||
|
const kw = searchText.value.toLowerCase()
|
||||||
|
list = list.filter(p =>
|
||||||
|
p.name.toLowerCase().includes(kw) ||
|
||||||
|
p.no.toLowerCase().includes(kw) ||
|
||||||
|
p.company.toLowerCase().includes(kw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (activeTab.value === 1) list = list.filter(p => p.status === 'building')
|
||||||
|
else if (activeTab.value === 2) list = list.filter(p => p.status === 'paused')
|
||||||
|
else if (activeTab.value === 3) list = list.filter(p => p.status === 'completed')
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
function goDetail(id: number) {
|
||||||
|
router.push(`/constructionDetail/${id}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<van-nav-bar title="工程项目" left-arrow fixed placeholder @click-left="router.back()" />
|
||||||
|
|
||||||
|
<van-search v-model="searchText" placeholder="搜索项目名称、编号、单位" shape="round" />
|
||||||
|
|
||||||
|
<van-tabs v-model:active="activeTab" sticky>
|
||||||
|
<van-tab title="全部" />
|
||||||
|
<van-tab title="在建" />
|
||||||
|
<van-tab title="暂停" />
|
||||||
|
<van-tab title="竣工" />
|
||||||
|
</van-tabs>
|
||||||
|
|
||||||
|
<div class="card-list">
|
||||||
|
<van-empty v-if="filteredList.length === 0" description="暂无项目" />
|
||||||
|
<van-card
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item.id"
|
||||||
|
:title="item.name"
|
||||||
|
:desc="`施工单位: ${item.company}`"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<template #tags>
|
||||||
|
<van-tag :type="statusColorMap[item.status]" size="medium">
|
||||||
|
{{ statusMap[item.status] }}
|
||||||
|
</van-tag>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="progress-wrap">
|
||||||
|
<van-progress
|
||||||
|
:percentage="item.progress"
|
||||||
|
:color="progressColor(item.progress)"
|
||||||
|
:pivot-text="`${item.progress}%`"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>{{ item.no }}</span>
|
||||||
|
<span>负责人: {{ item.manager }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
padding: 0 8px;
|
||||||
|
|
||||||
|
:deep(.van-card) {
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--color-bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tag) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-wrap {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user