中航光电PDA端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

862 lines
18 KiB

<template>
<ifrm ref="ifrm">
<view class="container">
<!-- Content -->
<scroll-view
class="scroll-content"
scroll-y
refresher-enabled
:refresher-triggered="isRefreshing"
@refresherrefresh="onRefresh"
@scrolltolower="handleLoadMore"
lower-threshold="100"
>
<view class="content">
<!-- 站点码输入区域 -->
<view class="input-section">
<text class="label">站点码:</text>
<view class="input-wrapper">
<input
class="input"
type="text"
placeholder="站点码"
:value="siteCode"
@input="handleInput"
@confirm="handleSearch"
confirm-type="search"
/>
<!-- <view class="scan-btn" @tap="handleScan">
<text class="scan-icon"></text>
</view> -->
</view>
</view>
<!-- 空状态 -->
<view v-if="sites.length === 0" class="empty-state">
<view class="empty-icon">
<text class="icon-large">⚏</text>
</view>
<text class="empty-title">未找到匹配的站点</text>
<text class="empty-desc">请尝试其他站点码</text>
</view>
<!-- 站点列表 -->
<view v-else class="site-list">
<view class="list-header">
<text class="list-title">{{
hasSearched ? "搜索结果" : "全部站点"
}}</text>
<view class="site-count">{{ page.total }} 个站点</view>
</view>
<view v-for="(site,index) in displayedSites" :key="index" class="site-card">
<!-- 头部 -->
<view class="card-header">
<view class="card-info">
<text class="site-name">{{ site.stationName }}</text>
<text class="site-code">站点编码: {{ site.stationCode }}</text>
</view>
<view class="status-btn" @tap="handleStatusChange(site)">
{{ site.stationStatus == "1" ? "闲置" : "占用" }}
</view>
</view>
<!-- 详情 -->
<view class="card-details">
<view class="detail-row">
<text class="detail-label">站点区域</text>
<text class="detail-value">{{ site.stationRegion }}</text>
</view>
<view class="detail-row">
<text class="detail-label">站点楼层</text>
<text class="detail-value">{{ site.stationPosition }}楼</text>
</view>
<view class="detail-row">
<text class="detail-label">作业中心</text>
<text class="detail-value">{{ site.wcName }}</text>
</view>
<view class="detail-row">
<text class="detail-label">站点状态</text>
<view
:class="['status-badge', getStatusClass(site.stationStatus)]"
>
<view class="status-dot">
<view class="dot-ping"></view>
<view class="dot-core"></view>
</view>
<text class="status-text">{{
getStatusLabel(site.stationStatus)
}}</text>
</view>
</view>
</view>
</view>
<!-- 加载中 -->
<view v-if="isLoading" class="loading">
<text class="loading-text">加载中...</text>
</view>
</view>
</view>
</scroll-view>
<!-- 确认对话框 -->
<view
v-if="confirmDialog.isOpen"
class="modal-overlay"
@tap="cancelStatusChange"
>
<view class="modal-content" @tap.stop>
<text class="modal-title">确认状态变更</text>
<text class="modal-desc">
确认将站点
<text class="bold">{{ confirmDialog.siteName }}</text> 的状态从
<text
:class="[
'bold',
confirmDialog.currentStatus === '占用'
? 'text-red'
: 'text-green',
]"
>
{{ confirmDialog.currentStatus }}
</text>
变更为
<text
:class="[
'bold',
confirmDialog.newStatus === '占用' ? 'text-red' : 'text-green',
]"
>
{{ confirmDialog.newStatus }}
</text>
吗?
</text>
<view class="modal-actions">
<view class="modal-btn btn-cancel" @tap="cancelStatusChange">
取消
</view>
<view class="modal-btn btn-confirm" @tap="confirmStatusChange">
确认
</view>
</view>
</view>
</view>
</view>
</ifrm>
</template>
<script>
import ifrm from "@/pages/index/ifrm";
export default {
components: {
ifrm,
},
onNavigationBarButtonTap(btn) {
this.$refs.ifrm.topMenuClick(btn);
},
data() {
return {
siteCode: "",
sites: [], // 当前显示的站点列表
allSites: [], // 缓存所有数据(可选)
hasSearched: false,
isLoading: false,
isRefreshing: false,
noMoreData: false, // 是否没有更多数据
confirmDialog: {
isOpen: false,
siteId: null,
siteName: "",
currentStatus: "",
newStatus: "",
},
page: {
pageSize: 10,
currentPage: 1,
total: 0,
},
searchParams: {}, // 搜索参数
};
},
computed: {
displayedSites() {
return this.sites.slice(0, this.displayCount);
},
},
mounted() {
this.initData();
},
methods: {
// 添加方法
onRefresh() {
this.isRefreshing = true;
this.loadSites(true).then(() => {
this.isRefreshing = false;
});
},
// 初始化数据
initData() {
this.loadSites(true);
},
// 加载站点数据
loadSites(isRefresh = false) {
if (this.isLoading || (this.noMoreData && !isRefresh)) {
return;
}
this.isLoading = true;
if (isRefresh) {
this.page.currentPage = 1;
this.sites = [];
this.noMoreData = false;
}
this.$u.api
.getStationList({
pageSize: this.page.pageSize,
currentPage: this.page.currentPage,
stationCode: this.siteCode ? this.siteCode : null,
...this.searchParams,
})
.then((res) => {
const records = res.data?.records || [];
const total = res.data?.total || 0;
// 处理数据格式
const formattedData = records.map((item) => ({
id: item.id,
code: item.stationCode,
name: item.stationName,
area: item.wcName || "",
floor: item.stationPosition || "",
workCenter: item.wcName || "",
status: item.stationStatus == "1" ? "occupied" : "available",
...item,
}));
if (isRefresh) {
this.sites = formattedData;
} else {
this.sites = [...this.sites, ...formattedData];
}
this.page.total = total;
// 判断是否还有更多数据
if (this.sites.length >= total) {
this.noMoreData = true;
}
this.isLoading = false;
})
.catch((err) => {
this.isLoading = false;
uni.showToast({
title: "加载失败",
icon: "error",
});
});
},
// 输入框输入事件
handleInput(e) {
const value = e.detail.value;
this.siteCode = value;
},
// 回车搜索
handleSearch() {
this.page.currentPage = 1;
this.sites = [];
this.noMoreData = false;
this.loadSites(true);
// 收起键盘
uni.hideKeyboard();
},
// 过滤站点
filterSites(keyword) {
const lowerKeyword = keyword.toLowerCase();
this.sites = this.allSites.filter(
(site) =>
site.code.toLowerCase().includes(lowerKeyword) ||
site.name.toLowerCase().includes(lowerKeyword) ||
site.area.toLowerCase().includes(lowerKeyword)
);
this.hasSearched = true;
},
// 模拟扫描
handleScan() {
// 使用UniApp的扫码API
uni.scanCode({
success: (res) => {
this.siteCode = res.result;
this.filterSites(res.result);
},
fail: () => {
// 扫码失败,使用模拟数据
const randomSite =
this.allSites[Math.floor(Math.random() * this.allSites.length)];
this.siteCode = randomSite.code;
this.sites = this.allSites.filter((s) => s.code === randomSite.code);
this.hasSearched = true;
},
});
},
// 重置
handleReset() {
this.siteCode = "";
this.searchParams = {};
this.page.currentPage = 1;
this.sites = [];
this.noMoreData = false;
this.loadSites(true);
},
// 关闭页面
handleClose() {
uni.navigateBack();
},
// 懒加载更多
handleLoadMore() {
if (this.isLoading || this.noMoreData) {
return;
}
this.page.currentPage += 1;
this.loadSites(false);
},
// 获取状态样式类
getStatusClass(status) {
return status == 1 ? "status-occupied" : "status-available";
},
// 获取状态标签
getStatusLabel(status) {
return status == 0 ? "闲置" : "占用";
},
// 打开状态变更确认对话框
handleStatusChange(site) {
const newStatus = site.stationStatus == 0 ? 1 : 0;
this.confirmDialog = {
...site,
isOpen: true,
siteName: site.name,
currentStatus: this.getStatusLabel(site.stationStatus),
newStatus: this.getStatusLabel(newStatus),
newStationStatus: newStatus,
};
},
// 确认状态变更
confirmStatusChange() {
if (this.confirmDialog.siteId !== null) {
this.confirmDialog.stationStatus = this.confirmDialog.newStationStatus;
console.log("获取当前列表的数据", this.confirmDialog);
// 调用接口更新状态
this.$u.api
.stationUpdate(this.confirmDialog)
.then((res) => {
// 更新本地数据
const index = this.sites.findIndex(
(s) => s.id == this.confirmDialog.id
);
console.log(
"更新站点状态成功",
this.confirmDialog.id,
this.sites,
index
);
if (index !== -1) {
this.sites[index].stationStatus =
this.confirmDialog.stationStatus;
}
uni.showToast({
title: "状态更新成功",
icon: "success",
});
this.cancelStatusChange();
})
.catch((err) => {
uni.showToast({
title: "状态更新失败",
icon: "error",
});
this.cancelStatusChange();
});
}
},
// 取消确认
cancelStatusChange() {
this.confirmDialog = {
isOpen: false,
};
},
},
};
</script>
<style scoped>
/* 容器 */
.container {
width: 100%;
height: 100vh;
background-color: #f7f8fa;
display: flex;
flex-direction: column;
}
/* Header */
.header {
background: linear-gradient(135deg, #4a7de8 0%, #5b8ff9 100%);
padding: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.header-left {
display: flex;
align-items: center;
gap: 16rpx;
}
.header-btn {
width: 72rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.2s;
}
.header-btn:active {
background-color: rgba(255, 255, 255, 0.2);
transform: scale(0.95);
}
.icon {
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
}
.header-title {
color: #ffffff;
font-size: 36rpx;
font-weight: 600;
}
/* 滚动内容 */
.scroll-content {
flex: 1;
height: 100%;
}
.content {
padding: 32rpx;
padding-bottom: 60rpx;
}
/* 输入区域 */
.input-section {
margin-bottom: 48rpx;
}
.label {
color: #374151;
font-size: 28rpx;
font-weight: 500;
display: block;
margin-bottom: 24rpx;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.input {
width: 100%;
padding: 24rpx 32rpx;
/* padding-right: 100rpx; */
background-color: #ffffff;
border: 2rpx solid #e5e7eb;
border-radius: 16rpx;
color: #374151;
font-size: 28rpx;
}
.input::placeholder {
color: #9ca3af;
}
.scan-btn {
position: absolute;
right: 16rpx;
width: 72rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12rpx;
transition: all 0.2s;
}
.scan-btn:active {
background-color: #f3f4f6;
transform: scale(0.95);
}
.scan-icon {
color: #5b8ff9;
font-size: 40rpx;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 120rpx 0;
display: flex;
flex-direction: column;
align-items: center;
}
.empty-icon {
width: 160rpx;
height: 160rpx;
background-color: #f3f4f6;
border-radius: 32rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 32rpx;
}
.icon-large {
font-size: 80rpx;
color: #9ca3af;
}
.empty-title {
color: #6b7280;
font-size: 28rpx;
font-weight: 500;
margin-bottom: 8rpx;
}
.empty-desc {
color: #9ca3af;
font-size: 24rpx;
}
/* 站点列表 */
.site-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.list-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.list-title {
color: #374151;
font-size: 26rpx;
font-weight: 600;
}
.site-count {
background-color: #f3f4f6;
color: #6b7280;
font-size: 22rpx;
padding: 6rpx 20rpx;
border-radius: 999rpx;
}
/* 站点卡片 */
.site-card {
background-color: #ffffff;
border-radius: 20rpx;
padding: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
border: 2rpx solid #e5e7eb;
}
.card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 20rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #f3f4f6;
}
.card-info {
flex: 1;
padding-right: 20rpx;
display: flex;
flex-direction: column;
}
.site-name {
color: #111827;
font-size: 30rpx;
font-weight: bold;
margin-bottom: 6rpx;
}
.site-code {
color: #6b7280;
font-size: 22rpx;
}
.status-btn {
padding: 10rpx 24rpx;
border-radius: 10rpx;
font-size: 22rpx;
font-weight: 600;
color: #ffffff;
white-space: nowrap;
transition: all 0.2s;
background-color: #5b8ff9;
box-shadow: 0 4rpx 12rpx rgba(91, 143, 249, 0.3);
}
.status-btn:active {
transform: scale(0.95);
}
.btn-green {
background-color: #10b981;
}
.btn-red {
background-color: #ef4444;
}
/* 卡片详情 */
.card-details {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.detail-row {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 26rpx;
}
.detail-label {
color: #6b7280;
}
.detail-value {
color: #111827;
font-weight: 500;
}
/* 状态徽章 */
.status-badge {
display: flex;
align-items: center;
gap: 10rpx;
padding: 8rpx 16rpx;
border-radius: 999rpx;
}
.status-occupied {
background-color: #fef2f2;
}
.status-available {
background-color: #f0fdf4;
}
.status-dot {
position: relative;
width: 12rpx;
height: 12rpx;
}
.dot-ping {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
opacity: 0.75;
}
.dot-core {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
}
.status-occupied .dot-ping,
.status-occupied .dot-core {
background-color: #ef4444;
}
.status-available .dot-ping,
.status-available .dot-core {
background-color: #10b981;
}
.status-text {
font-size: 24rpx;
font-weight: 600;
}
.status-occupied .status-text {
color: #b91c1c;
}
.status-available .status-text {
color: #15803d;
}
@keyframes ping {
75%,
100% {
transform: scale(2);
opacity: 0;
}
}
/* 加载中 */
.loading {
text-align: center;
padding: 32rpx 0;
}
.loading-text {
color: #6b7280;
font-size: 28rpx;
font-weight: 500;
}
/* 模态框 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
padding: 32rpx;
}
.modal-content {
background-color: #ffffff;
border-radius: 32rpx;
padding: 48rpx;
width: 100%;
max-width: 600rpx;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
animation: modal-in 0.2s ease-out;
}
@keyframes modal-in {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.modal-title {
color: #111827;
font-size: 36rpx;
font-weight: bold;
margin-bottom: 24rpx;
display: block;
}
.modal-desc {
color: #6b7280;
font-size: 28rpx;
line-height: 1.6;
margin-bottom: 48rpx;
display: block;
}
.bold {
font-weight: bold;
color: #111827;
}
.text-red {
color: #dc2626 !important;
}
.text-green {
color: #16a34a !important;
}
.modal-actions {
display: flex;
align-items: center;
gap: 24rpx;
}
.modal-btn {
flex: 1;
padding: 24rpx 32rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 600;
text-align: center;
transition: all 0.2s;
}
.modal-btn:active {
transform: scale(0.95);
}
.btn-cancel {
background-color: #f3f4f6;
color: #374151;
}
.btn-confirm {
background-color: #5b8ff9;
color: #ffffff;
box-shadow: 0 4rpx 12rpx rgba(91, 143, 249, 0.3);
}
</style>