odf_new/odf-uniapp/pages/search/index.vue
zpc 7e260a1d57 feat(odf-uniapp): Refactor global background styling to use centralized page background
- Replace individual page background images with global page background in App.vue
- Update pages.json global styles to use transparent colors for navigation and backgrounds
- Remove redundant bg-image elements and styles from all page components
- Set global page background with login_bg.png image, cover sizing, and fixed attachment
- Simplify individual page styling by removing duplicate background color declarations
- Consolidate background management to single source of truth in App.vue for consistent theming
2026-04-04 00:20:24 +08:00

357 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="search-page">
<view class="content">
<!-- 顶部导航栏 -->
<view class="nav-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="nav-bar-inner">
<image
class="nav-icon"
src="/static/images/ic_back.png"
mode="aspectFit"
@click="goBack"
/>
<text class="nav-title">{{ roomIdRef ? '机房搜索' : '搜索' }}</text>
<view class="nav-icon-placeholder" />
</view>
</view>
<!-- 搜索栏 -->
<view class="search-bar">
<input
class="search-input"
v-model="keyword"
placeholder="请输入要搜索的备注内容"
confirm-type="search"
@confirm="doSearch"
/>
<view class="search-btn" @click="doSearch">
<text class="search-btn-text">搜索</text>
</view>
</view>
<!-- 搜索结果 -->
<view class="result-area" v-if="searched">
<!-- 机房区域(仅全局搜索时显示) -->
<view class="section" v-if="!roomIdRef && rooms.length > 0">
<text class="section-title">机房</text>
<view
class="room-card"
v-for="item in rooms"
:key="item.roomId"
@click="goRack(item)"
>
<text class="room-card-name">{{ item.roomName }}</text>
</view>
</view>
<!-- 备注信息区域 -->
<view class="section" v-if="ports.length > 0">
<text class="section-title">备注信息</text>
<view
class="port-card"
v-for="item in ports"
:key="item.id"
@click="goPortDetail(item)"
>
<view class="port-card-row">
<text class="port-label">机房:</text>
<text class="port-value">{{ item.roomName }}</text>
</view>
<view class="port-card-row" v-if="item.address">
<text class="port-label">地址:</text>
<text class="port-value">{{ item.address }}</text>
</view>
<view class="port-card-row">
<text class="port-label">ODF名称</text>
<text class="port-value">{{ item.rackName }}</text>
</view>
<view class="port-card-row">
<text class="port-label">点位置:</text>
<text class="port-value">{{ item.frameName }}{{ item.name }}</text>
</view>
<view class="port-card-row" v-if="item.remarks">
<text class="port-label">备注:</text>
<text class="port-value">{{ item.remarks }}</text>
</view>
<view class="port-card-row" v-if="item.opticalAttenuation">
<text class="port-label">光衰信息:</text>
<text class="port-value">{{ item.opticalAttenuation }}</text>
</view>
<view class="port-card-row" v-if="item.historyRemarks">
<text class="port-label">历史故障:</text>
<text class="port-value">{{ item.historyRemarks }}</text>
</view>
<view class="port-card-row" v-if="item.opticalCableOffRemarks">
<text class="port-label">光缆段信息:</text>
<text class="port-value">{{ item.opticalCableOffRemarks }}</text>
</view>
<view class="port-card-row">
<text class="port-label">状态:</text>
<view class="status-wrap">
<view
class="status-dot"
:class="item.status === 1 ? 'status-green' : 'status-red'"
/>
<text class="status-text">{{ item.status === 1 ? '已连接' : '已断开' }}</text>
</view>
</view>
</view>
</view>
<!-- 无结果 -->
<view class="no-result" v-if="rooms.length === 0 && ports.length === 0">
<text class="no-result-text">暂无搜索结果</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import { searchPorts } from '@/services/search'
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 0
const keyword = ref('')
const rooms = ref([])
const ports = ref([])
const searched = ref(false)
const pageNum = ref(1)
const pageSize = 20
const totalPage = ref(0)
const loading = ref(false)
const roomIdRef = ref('')
async function doSearch() {
const key = keyword.value.trim()
if (!key) return
pageNum.value = 1
loading.value = true
try {
const res = await searchPorts(key, 1, pageSize, roomIdRef.value || undefined)
if (res.code === 200 && res.data) {
rooms.value = res.data.rooms || []
const portsData = res.data.ports || {}
ports.value = portsData.result || []
totalPage.value = portsData.totalPage || 0
}
} finally {
loading.value = false
searched.value = true
}
}
async function loadMore() {
if (loading.value) return
if (pageNum.value >= totalPage.value) return
loading.value = true
pageNum.value++
try {
const res = await searchPorts(keyword.value.trim(), pageNum.value, pageSize, roomIdRef.value || undefined)
if (res.code === 200 && res.data) {
const portsData = res.data.ports || {}
ports.value = [...ports.value, ...(portsData.result || [])]
totalPage.value = portsData.totalPage || 0
}
} finally {
loading.value = false
}
}
function goBack() {
uni.navigateBack()
}
function goRack(item) {
uni.navigateTo({
url: '/pages/rack/index?roomId=' + item.roomId + '&roomName=' + encodeURIComponent(item.roomName)
})
}
function goPortDetail(item) {
uni.navigateTo({
url: '/pages/rack-detail/index?rackId=' + item.rackId + '&rackName=' + encodeURIComponent(item.rackName) + '&roomName=' + encodeURIComponent(item.roomName) + '&portId=' + item.id
})
}
onReachBottom(() => {
loadMore()
})
onLoad((options) => {
if (options.roomId) {
roomIdRef.value = options.roomId
}
})
</script>
<style scoped>
.search-page {
position: relative;
min-height: 100vh;
background-color: transparent;
}
.content {
position: relative;
z-index: 1;
}
.nav-bar {
width: 100%;
}
.nav-bar-inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 24rpx;
}
.nav-icon {
width: 44rpx;
height: 44rpx;
}
.nav-icon-placeholder {
width: 44rpx;
height: 44rpx;
}
.nav-title {
font-size: 34rpx;
font-weight: 600;
color: #fff;
}
.search-bar {
display: flex;
align-items: center;
padding: 16rpx 24rpx;
}
.search-input {
flex: 1;
height: 72rpx;
padding: 0 24rpx;
background-color: #fff;
border-radius: 12rpx;
font-size: 28rpx;
}
.search-btn {
margin-left: 16rpx;
padding: 0 28rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #1A73EC;
border-radius: 12rpx;
}
.search-btn-text {
color: #fff;
font-size: 28rpx;
}
.result-area {
padding: 16rpx 24rpx;
}
.section {
margin-bottom: 24rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 16rpx;
}
.room-card {
display: flex;
align-items: center;
padding: 32rpx 24rpx;
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.room-card-name {
font-size: 30rpx;
font-weight: 500;
color: #333;
}
.port-card {
padding: 24rpx;
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.port-card-row {
display: flex;
align-items: flex-start;
margin-bottom: 12rpx;
}
.port-card-row:last-child {
margin-bottom: 0;
}
.port-label {
font-size: 26rpx;
color: #999;
flex-shrink: 0;
}
.port-value {
font-size: 26rpx;
color: #333;
flex: 1;
}
.status-wrap {
display: flex;
align-items: center;
}
.status-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
margin-right: 8rpx;
}
.status-green {
background-color: #4CAF50;
}
.status-red {
background-color: #F44336;
}
.status-text {
font-size: 26rpx;
color: #333;
}
.no-result {
display: flex;
justify-content: center;
padding: 80rpx 0;
}
.no-result-text {
font-size: 28rpx;
color: #999;
}
</style>