- 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
357 lines
8.3 KiB
Vue
357 lines
8.3 KiB
Vue
<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>
|