first commit
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
const { deviceApi } = require("../../utils/api");
|
||||
|
||||
Page({
|
||||
data: {
|
||||
device_id: null,
|
||||
device: null,
|
||||
subDevices: [],
|
||||
loading: true,
|
||||
loadError: false,
|
||||
|
||||
// 子设备状态相关
|
||||
statusDialogVisible: false,
|
||||
selectedStatus: 0,
|
||||
currentSubDeviceForStatus: null,
|
||||
|
||||
deviceStatusMap: {
|
||||
0: "空闲",
|
||||
1: "使用中",
|
||||
2: "维护中",
|
||||
},
|
||||
|
||||
// 状态选择选项
|
||||
statusOptions: [
|
||||
{ value: 0, label: "空闲", color: "#06a56c" },
|
||||
{ value: 1, label: "使用中", color: "#1890ff" },
|
||||
{ value: 2, label: "维护中", color: "#fa8c16" },
|
||||
],
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
if (options.device_id) {
|
||||
this.setData({ device_id: options.device_id });
|
||||
this.loadDeviceInfo();
|
||||
this.loadSubDevices();
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: "缺少设备ID",
|
||||
icon: "error",
|
||||
});
|
||||
wx.navigateBack();
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 页面显示时刷新数据
|
||||
if (this.data.device_id) {
|
||||
this.loadSubDevices();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载设备信息
|
||||
async loadDeviceInfo() {
|
||||
try {
|
||||
const response = await deviceApi.getDevices();
|
||||
const deviceList = response.data.list || response.data || [];
|
||||
const device = deviceList.find((d) => d.id === parseInt(this.data.device_id));
|
||||
|
||||
if (device) {
|
||||
this.setData({ device });
|
||||
}
|
||||
} catch (error) {
|
||||
// 加载设备信息失败,继续执行
|
||||
}
|
||||
},
|
||||
|
||||
// 加载子设备列表
|
||||
async loadSubDevices() {
|
||||
this.setData({ loading: true, loadError: false });
|
||||
|
||||
try {
|
||||
const response = await deviceApi.getSubDevicesByDeviceId(this.data.device_id);
|
||||
const subDevices = response.data.list || response.data || [];
|
||||
|
||||
// 为每个子设备添加状态信息
|
||||
const formattedSubDevices = subDevices.map((subDevice) => ({
|
||||
...subDevice,
|
||||
status: subDevice.status !== undefined ? subDevice.status : 0,
|
||||
statusText: this.data.deviceStatusMap[subDevice.status !== undefined ? subDevice.status : 0],
|
||||
}));
|
||||
|
||||
this.setData({
|
||||
subDevices: formattedSubDevices,
|
||||
loading: false,
|
||||
});
|
||||
} catch (error) {
|
||||
this.setData({
|
||||
loadError: true,
|
||||
loading: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 显示状态更改对话框
|
||||
showStatusDialog(e) {
|
||||
const subDevice = e.currentTarget.dataset.subdevice;
|
||||
this.setData({
|
||||
statusDialogVisible: true,
|
||||
selectedStatus: subDevice.status !== undefined ? subDevice.status : 0,
|
||||
currentSubDeviceForStatus: subDevice,
|
||||
});
|
||||
},
|
||||
|
||||
// 关闭状态对话框
|
||||
closeStatusDialog() {
|
||||
this.setData({
|
||||
statusDialogVisible: false,
|
||||
selectedStatus: 0,
|
||||
currentSubDeviceForStatus: null,
|
||||
});
|
||||
},
|
||||
|
||||
// 选择状态
|
||||
selectStatus(e) {
|
||||
const status = parseInt(e.currentTarget.dataset.status);
|
||||
this.setData({
|
||||
selectedStatus: status,
|
||||
});
|
||||
},
|
||||
|
||||
// 确认状态更改
|
||||
async confirmStatusChange() {
|
||||
const { selectedStatus, currentSubDeviceForStatus } = this.data;
|
||||
|
||||
try {
|
||||
await deviceApi.updateSubDevice(currentSubDeviceForStatus.id, {
|
||||
status: selectedStatus,
|
||||
name: currentSubDeviceForStatus.name,
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: "状态更新成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
this.closeStatusDialog();
|
||||
this.loadSubDevices();
|
||||
} catch (error) {
|
||||
wx.showToast({
|
||||
title: "状态更新失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 查看子设备保养记录
|
||||
viewMaintenance(e) {
|
||||
const subDevice = e.currentTarget.dataset.subdevice;
|
||||
wx.navigateTo({
|
||||
url: `/pages/device_maintenance/index?sub_device_id=${subDevice.id}`,
|
||||
});
|
||||
},
|
||||
|
||||
// 添加保养记录
|
||||
addMaintenance(e) {
|
||||
const subDevice = e.currentTarget.dataset.subdevice;
|
||||
wx.navigateTo({
|
||||
url: `/pages/device_maintenance/create/index?sub_device_id=${subDevice.id}`,
|
||||
});
|
||||
},
|
||||
|
||||
// 返回上一页
|
||||
onBack() {
|
||||
wx.navigateBack();
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadSubDevices()
|
||||
.then(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
})
|
||||
.catch(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"navigationBarTitleText": "子设备管理",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundColor": "#f7f8fa",
|
||||
"enablePullDownRefresh": true,
|
||||
"usingComponents": {
|
||||
"t-toast": "tdesign-miniprogram/toast/toast",
|
||||
"t-dialog": "tdesign-miniprogram/dialog/dialog",
|
||||
"t-skeleton": "tdesign-miniprogram/skeleton/skeleton",
|
||||
"t-empty": "tdesign-miniprogram/empty/empty",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-button": "tdesign-miniprogram/button/button",
|
||||
"t-tag": "tdesign-miniprogram/tag/tag"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<view class="subdevices-page">
|
||||
<!-- 页面头部 -->
|
||||
<view class="page-header">
|
||||
<view class="device-info">
|
||||
<view class="device-name">{{device.name}}</view>
|
||||
<view class="device-meta">
|
||||
<text class="subdevice-count">子设备: {{subDevices.length}}个</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<block wx:if="{{loading}}">
|
||||
<view class="loading-container">
|
||||
<t-skeleton theme="paragraph" loading />
|
||||
<t-skeleton theme="paragraph" loading />
|
||||
<t-skeleton theme="paragraph" loading />
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<block wx:elif="{{loadError}}">
|
||||
<view class="error-container">
|
||||
<t-empty icon="error-circle" description="加载失败,请下拉刷新重试" />
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 子设备列表 -->
|
||||
<block wx:elif="{{subDevices.length > 0}}">
|
||||
<view class="subdevices-list">
|
||||
<view
|
||||
wx:for="{{subDevices}}"
|
||||
wx:key="id"
|
||||
class="subdevice-card">
|
||||
<view class="card-header">
|
||||
<view class="subdevice-info">
|
||||
<view class="subdevice-name">{{item.name}}</view>
|
||||
<view class="subdevice-meta">
|
||||
<text class="subdevice-status">
|
||||
状态: <text class="status-badge status-{{item.status}}">{{item.statusText}}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="usage-info">
|
||||
<text class="usage-count">{{item.usage_count || 0}}次</text>
|
||||
<text class="usage-label">使用</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{item.description}}" class="subdevice-desc">
|
||||
<text>{{item.description}}</text>
|
||||
</view>
|
||||
|
||||
<view class="card-actions">
|
||||
<t-button
|
||||
size="small"
|
||||
variant="outline"
|
||||
bind:tap="viewMaintenance"
|
||||
data-subdevice="{{item}}">
|
||||
保养记录
|
||||
</t-button>
|
||||
<t-button
|
||||
size="small"
|
||||
variant="outline"
|
||||
bind:tap="addMaintenance"
|
||||
data-subdevice="{{item}}">
|
||||
添加保养
|
||||
</t-button>
|
||||
<t-button
|
||||
size="small"
|
||||
variant="outline"
|
||||
bind:tap="showStatusDialog"
|
||||
data-subdevice="{{item}}">
|
||||
更改状态
|
||||
</t-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<block wx:else>
|
||||
<view class="empty-container">
|
||||
<t-empty icon="device" description="暂无子设备" />
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
<!-- 状态更改对话框 -->
|
||||
<view class="dialog-mask" wx:if="{{statusDialogVisible}}" bindtap="closeStatusDialog">
|
||||
<view class="dialog-container" catchtap="">
|
||||
<view class="dialog-header">
|
||||
<text class="dialog-title">更改子设备状态</text>
|
||||
<text class="dialog-close" bindtap="closeStatusDialog">×</text>
|
||||
</view>
|
||||
|
||||
<view class="dialog-body">
|
||||
<view class="status-current">
|
||||
<text>当前状态:{{currentSubDeviceForStatus ? deviceStatusMap[currentSubDeviceForStatus.status] : '未知'}}</text>
|
||||
</view>
|
||||
|
||||
<view class="status-options">
|
||||
<view
|
||||
wx:for="{{statusOptions}}"
|
||||
wx:key="value"
|
||||
class="status-option {{selectedStatus === item.value ? 'selected' : ''}}"
|
||||
catchtap="selectStatus"
|
||||
data-status="{{item.value}}">
|
||||
<text class="status-dot" style="background-color: {{item.color}}"></text>
|
||||
<text class="status-label">{{item.label}}</text>
|
||||
<text class="status-check" wx:if="{{selectedStatus === item.value}}">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dialog-footer">
|
||||
<button class="dialog-btn cancel-btn" bindtap="closeStatusDialog">取消</button>
|
||||
<button class="dialog-btn confirm-btn" bindtap="confirmStatusChange">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -0,0 +1,340 @@
|
||||
.subdevices-page {
|
||||
padding: 0;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 页面头部 */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #e8e8e8;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.device-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.device-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.device-meta {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.subdevice-count {
|
||||
color: #0052d9;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 加载和错误状态 */
|
||||
.loading-container,
|
||||
.error-container,
|
||||
.empty-container {
|
||||
padding: 100rpx 30rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 子设备列表 */
|
||||
.subdevices-list {
|
||||
padding: 20rpx 30rpx;
|
||||
}
|
||||
|
||||
.subdevice-card {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.subdevice-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.subdevice-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.subdevice-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.subdevice-id {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.subdevice-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
font-size: 24rpx;
|
||||
padding: 2rpx 8rpx;
|
||||
border-radius: 4rpx;
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
.status-0 {
|
||||
color: #06a56c;
|
||||
background-color: #e8f6f1;
|
||||
}
|
||||
|
||||
.status-1 {
|
||||
color: #1890ff;
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.status-2 {
|
||||
color: #fa8c16;
|
||||
background-color: #fff7e6;
|
||||
}
|
||||
|
||||
.usage-info {
|
||||
text-align: center;
|
||||
padding: 12rpx;
|
||||
background: #f0f2f5;
|
||||
border-radius: 8rpx;
|
||||
min-width: 100rpx;
|
||||
}
|
||||
|
||||
.usage-count {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #0052d9;
|
||||
}
|
||||
|
||||
.usage-label {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.subdevice-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 12rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.card-actions .t-button {
|
||||
flex: 1;
|
||||
min-width: 120rpx;
|
||||
font-size: 24rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
}
|
||||
|
||||
/* 状态选择器 */
|
||||
.status-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.status-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 32rpx;
|
||||
border-radius: 8rpx;
|
||||
background-color: #f7f8fa;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.status-option.selected {
|
||||
background-color: #eef4ff;
|
||||
border-color: #0052d9;
|
||||
}
|
||||
|
||||
.status-option:active {
|
||||
background-color: #e7e9eb;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
margin-left: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-check {
|
||||
position: absolute;
|
||||
right: 32rpx;
|
||||
color: #0052d9;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 自定义弹窗样式 */
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
width: 600rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(100rpx);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
font-size: 40rpx;
|
||||
color: #999;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dialog-close:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.dialog-body {
|
||||
padding: 30rpx;
|
||||
max-height: 600rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.dialog-btn {
|
||||
flex: 1;
|
||||
height: 100rpx;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
font-size: 28rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.dialog-btn:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
color: #666;
|
||||
border-right: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: #0052d9;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 弹窗内容区域 */
|
||||
.dialog-content {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.status-current {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 16rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 6rpx;
|
||||
text-align: center;
|
||||
}
|
||||
Reference in New Issue
Block a user