修复设备列表过滤筛选的bug

This commit is contained in:
柳清爽
2025-03-28 16:20:32 +08:00
parent a734ae2864
commit caea0b4b99
5 changed files with 793 additions and 229 deletions

84
Cunkebao/api/device.js Normal file
View File

@@ -0,0 +1,84 @@
import request from '@/utils/request'
/**
* 获取设备列表
* @param {Object} params 查询参数
* @param {string} params.keyword 关键词搜索同时搜索IMEI和备注
* @param {number} params.alive 设备在线状态可选1:在线 0:离线)
* @param {number} params.page 页码
* @param {number} params.limit 每页数量
* @returns {Promise} 设备列表
*
* 注意: params 参数会被自动添加到URL查询字符串中如 /v1/devices?keyword=xxx&alive=1&page=1&limit=20
*/
export function getDeviceList(params) {
return request({
url: '/v1/devices',
method: 'GET',
params
})
}
/**
* 获取设备总数
* @param {Object} params 查询参数
* @param {number} params.alive 设备在线状态可选1:在线 0:离线)
* @returns {Promise} 设备总数
*/
export function getDeviceCount(params) {
return request({
url: '/v1/devices/count',
method: 'GET',
params
})
}
/**
* 获取设备详情
* @param {number} id 设备ID
* @returns {Promise} 设备详情
*/
export function getDeviceDetail(id) {
return request({
url: `/v1/devices/${id}`,
method: 'GET'
})
}
/**
* 删除设备
* @param {number} id 设备ID
* @returns {Promise} 删除结果
*/
export function deleteDevice(id) {
return request({
url: `/v1/devices/${id}`,
method: 'DELETE'
})
}
/**
* 刷新设备状态
* @returns {Promise} 刷新结果
*/
export function refreshDevices() {
return request({
url: '/v1/devices/refresh',
method: 'PUT'
})
}
/**
* 添加设备
* @param {Object} data 设备数据
* @param {string} data.imei 设备IMEI
* @param {string} data.memo 设备备注
* @returns {Promise} 添加结果
*/
export function addDevice(data) {
return request({
url: '/v1/devices',
method: 'POST',
data
})
}

View File

@@ -19,11 +19,11 @@
<view class="stats-cards"> <view class="stats-cards">
<view class="stat-card"> <view class="stat-card">
<view class="stat-label">总设备数</view> <view class="stat-label">总设备数</view>
<view class="stat-value blue">42</view> <view class="stat-value blue">{{ totalDeviceCount }}</view>
</view> </view>
<view class="stat-card"> <view class="stat-card">
<view class="stat-label">在线设备</view> <view class="stat-label">在线设备</view>
<view class="stat-value green">35</view> <view class="stat-value green">{{ onlineDeviceCount }}</view>
</view> </view>
</view> </view>
@@ -40,6 +40,9 @@
bgColor="#fff" bgColor="#fff"
searchIconSize="50" searchIconSize="50"
shape="round" shape="round"
@search="handleSearch"
@clear="handleClearSearch"
@input="handleSearchInput"
></u-search> ></u-search>
</view> </view>
<view class="filter-btn" @click="showFilter"> <view class="filter-btn" @click="showFilter">
@@ -56,8 +59,20 @@
<text>{{ statusText }}</text> <text>{{ statusText }}</text>
<u-icon name="arrow-down" size="28" color="#333"></u-icon> <u-icon name="arrow-down" size="28" color="#333"></u-icon>
</view> </view>
<view class="select-all"> <!-- 添加搜索过滤标签 -->
<u-checkbox v-model="selectAll" size="40" iconSize="35" shape="circle" activeColor="#4080ff"></u-checkbox> <view class="filter-tag" v-if="searchKeyword">
<text>{{ searchKeyword }}</text>
<text class="close-icon" @click.stop="clearSearch">×</text>
</view>
<view class="select-all" v-if="deviceList.length > 0">
<u-checkbox
v-model="selectAll"
size="40"
iconSize="35"
shape="circle"
activeColor="#4080ff"
@change="handleSelectAllChange"
></u-checkbox>
<text class="select-text">全选</text> <text class="select-text">全选</text>
</view> </view>
<view class="delete-btn" @click="deleteDevices" :class="{disabled: !hasSelected}"> <view class="delete-btn" @click="deleteDevices" :class="{disabled: !hasSelected}">
@@ -67,83 +82,66 @@
<!-- 设备列表 --> <!-- 设备列表 -->
<view class="device-list"> <view class="device-list">
<!-- 设备项 1 --> <!-- 加载中 -->
<view class="device-item" @click="goToDeviceDetail(1)"> <view v-if="loading && page === 1" class="loading-container">
<view class="device-checkbox"> <u-loading-icon mode="circle" size="36"></u-loading-icon>
<u-checkbox size="40" iconSize="35" v-model="device1Selected" shape="circle" activeColor="#4080ff" @click.stop></u-checkbox> <text class="loading-text">加载中...</text>
</view>
<view class="device-info">
<view class="device-header">
<view class="device-name">设备 1</view>
<view class="device-status online">在线</view>
</view>
<view class="device-imei">IMEI: sd123123</view>
<view class="device-wx">微信号: wxid_hxdxdoal</view>
<view class="device-likes">
<text>好友数: 435</text>
<text class="today-stats">今日新增: +20</text>
</view>
</view>
</view> </view>
<!-- 设备项 2 --> <!-- 空状态 -->
<view class="device-item" @click="goToDeviceDetail(2)"> <view v-else-if="deviceList.length === 0" class="empty-container">
<view class="device-checkbox"> <u-empty mode="list" text="暂无设备"></u-empty>
<u-checkbox v-model="device2Selected" shape="circle" activeColor="#4080ff"
size="40" iconSize="35" @click.stop
></u-checkbox>
</view>
<view class="device-info">
<view class="device-header">
<view class="device-name">设备 2</view>
<view class="device-status online">在线</view>
</view>
<view class="device-imei">IMEI: sd123124</view>
<view class="device-wx">微信号: wxid_2i7sncgq</view>
<view class="device-likes">
<text>好友数: 143</text>
<text class="today-stats">今日新增: +26</text>
</view>
</view>
</view> </view>
<!-- 设备 3 --> <!-- 设备列表内容 -->
<view class="device-item" @click="goToDeviceDetail(3)"> <template v-else>
<view class="device-checkbox"> <!-- 设备项 -->
<u-checkbox size="40" iconSize="35" v-model="device3Selected" shape="circle" activeColor="#4080ff" @click.stop></u-checkbox> <view
</view> class="device-item"
<view class="device-info"> v-for="(device, index) in deviceList"
<view class="device-header"> :key="device.id"
<view class="device-name">设备 3</view> @click="goToDeviceDetail(device.id)"
<view class="device-status online">在线</view> >
<view class="device-checkbox">
<u-checkbox
:size="40"
:iconSize="35"
v-model="device.selected"
shape="circle"
activeColor="#4080ff"
@click.stop
@change="handleDeviceSelectChange"
></u-checkbox>
</view> </view>
<view class="device-imei">IMEI: sd123125</view> <view class="device-info">
<view class="device-wx">微信号: wxid_yunzn4lp</view> <view class="device-header">
<view class="device-likes"> <view class="device-name">{{ device.memo || '未命名设备' }}</view>
<text>好友数: 707</text> <view :class="['device-status', device.alive === 1 ? 'online' : 'offline']">
<text class="today-stats">今日新增: +48</text> {{ device.alive === 1 ? '在线' : '离线' }}
</view>
</view>
<view class="device-imei" @click.stop="showImeiDetail(device.imei)">
IMEI: <text class="imei-text">{{ formatImei(device.imei) }}</text>
</view>
<view class="device-wx">微信号: {{ device.wechatId || '未登录' }}</view>
<view class="device-likes">
<text>好友数: {{ device.totalFriend || 0 }}</text>
</view>
</view> </view>
</view> </view>
</view>
<!-- 加载更多 -->
<!-- 设备项 4 --> <view v-if="hasMoreData && !loadingMore" class="load-more" @click="loadMore">
<view class="device-item" @click="goToDeviceDetail(4)"> <text class="load-more-text">点击加载更多</text>
<view class="device-checkbox">
<u-checkbox size="40" iconSize="35" v-model="device4Selected" shape="circle" activeColor="#4080ff" @click.stop></u-checkbox>
</view> </view>
<view class="device-info"> <view v-else-if="loadingMore" class="load-more">
<view class="device-header"> <u-loading-icon mode="circle" size="24"></u-loading-icon>
<view class="device-name">设备 4</view> <text class="load-more-text">加载中...</text>
<view class="device-status offline">离线</view>
</view>
<view class="device-imei">IMEI: sd123126</view>
<view class="device-wx">微信号: wxid_4k39dnsc</view>
<view class="device-likes">
<text>好友数: 529</text>
<text class="today-stats">今日新增: +0</text>
</view>
</view> </view>
</view> <view v-else-if="deviceList.length >= 20" class="load-more">
<text class="load-more-text">没有更多数据了</text>
</view>
</template>
</view> </view>
</view> </view>
@@ -190,13 +188,37 @@
</view> </view>
</view> </view>
<!-- IMEI详情模态框 -->
<view class="imei-modal" v-if="showImeiModal">
<view class="modal-mask" @click="closeImeiModal"></view>
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">IMEI详情</text>
<view class="modal-close" @click="closeImeiModal">
<text class="close-icon">×</text>
</view>
</view>
<view class="modal-body">
<view class="imei-detail">
<text class="imei-label">IMEI:</text>
<text class="imei-value">{{ currentImei }}</text>
</view>
<view class="copy-btn" @click="copyImei">
<text class="copy-text">复制IMEI</text>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 --> <!-- 底部导航栏 -->
<CustomTabBar active="profile"></CustomTabBar> <CustomTabBar active="device"></CustomTabBar>
</view> </view>
</template> </template>
<script> <script>
import CustomTabBar from '@/components/CustomTabBar.vue' import CustomTabBar from '@/components/CustomTabBar.vue'
import * as DeviceApi from '@/api/device'
import Auth from '@/utils/auth'
export default { export default {
components: { components: {
@@ -204,12 +226,29 @@ export default {
}, },
data() { data() {
return { return {
// 搜索相关
searchKeyword: '', searchKeyword: '',
prevSearchKeyword: '', // 添加前一次搜索关键词
searchTimer: null, // 添加搜索防抖定时器
// 设备列表相关
deviceList: [],
page: 1,
limit: 20,
total: 0,
loading: false,
loadingMore: false,
hasMoreData: false,
// 统计相关
totalDeviceCount: 0,
onlineDeviceCount: 0,
// 选择相关
selectAll: false, selectAll: false,
device1Selected: false, selectedIds: [],
device2Selected: false,
device3Selected: false, // 筛选相关
device4Selected: false,
statusPickerShow: false, statusPickerShow: false,
statusOptions: [ statusOptions: [
{ text: '全部状态', value: 'all' }, { text: '全部状态', value: 'all' },
@@ -217,40 +256,318 @@ export default {
{ text: '离线', value: 'offline' } { text: '离线', value: 'offline' }
], ],
currentStatus: 'all', currentStatus: 'all',
// 添加设备相关数据
// 添加设备相关
showAddDeviceModal: false, showAddDeviceModal: false,
deviceId: '' deviceId: '',
// IMEI详情相关
showImeiModal: false,
currentImei: '',
} }
}, },
computed: { computed: {
hasSelected() { hasSelected() {
return this.device1Selected || this.device2Selected || this.device3Selected || this.device4Selected; return this.selectedIds.length > 0;
}, },
statusText() { statusText() {
const selected = this.statusOptions.find(option => option.value === this.currentStatus); const selected = this.statusOptions.find(option => option.value === this.currentStatus);
return selected ? selected.text : '全部状态'; return selected ? selected.text : '全部状态';
},
queryParams() {
const params = {
page: this.page,
limit: this.limit
};
// 添加搜索关键词添加trim避免空格干扰
if (this.searchKeyword && this.searchKeyword.trim()) {
// 同时搜索IMEI和备注使用OR关系
params.keyword = this.searchKeyword.trim();
}
// 添加状态筛选
if (this.currentStatus === 'online') {
params.alive = 1;
} else if (this.currentStatus === 'offline') {
params.alive = 0;
}
console.log('请求参数:', params); // 调试输出,观察参数
return params;
} }
}, },
onLoad() {
// 检查登录状态
if (!Auth.isLogin()) {
uni.reLaunch({
url: '/pages/login/index'
});
return;
}
// 获取设备统计数据
this.loadDeviceStats();
// 加载设备列表
this.loadDeviceList();
},
methods: { methods: {
// 加载设备统计数据
async loadDeviceStats() {
try {
// 获取设备总数
const totalRes = await DeviceApi.getDeviceCount();
if (totalRes.code === 200) {
this.totalDeviceCount = totalRes.data.count || 0;
}
// 获取在线设备数
const onlineRes = await DeviceApi.getDeviceCount({ alive: 1 });
if (onlineRes.code === 200) {
this.onlineDeviceCount = onlineRes.data.count || 0;
}
} catch (error) {
console.error('加载设备统计数据失败', error);
uni.showToast({
title: '加载统计数据失败',
icon: 'none'
});
}
},
// 加载设备列表
async loadDeviceList(isLoadMore = false) {
try {
if (isLoadMore) {
this.loadingMore = true;
} else {
this.loading = true;
if (!isLoadMore) {
// 重置页码
this.page = 1;
this.deviceList = [];
}
}
console.log('发送请求参数:', this.queryParams); // 查看请求参数
const res = await DeviceApi.getDeviceList(this.queryParams);
if (res.code === 200) {
const newDevices = res.data.list.map(item => ({
...item,
selected: false
}));
if (isLoadMore) {
this.deviceList = [...this.deviceList, ...newDevices];
} else {
this.deviceList = newDevices;
}
this.total = res.data.total || 0;
this.hasMoreData = this.deviceList.length < this.total;
} else {
uni.showToast({
title: res.msg || '加载设备列表失败',
icon: 'none'
});
}
} catch (error) {
console.error('加载设备列表失败', error);
uni.showToast({
title: '加载设备列表失败',
icon: 'none'
});
} finally {
this.loading = false;
this.loadingMore = false;
}
},
// 加载更多
loadMore() {
if (this.hasMoreData && !this.loadingMore) {
this.page++;
this.loadDeviceList(true);
}
},
// 处理搜索输入(带防抖)
handleSearchInput(value) {
// 清除之前的定时器
if (this.searchTimer) {
clearTimeout(this.searchTimer);
}
// 设置新的定时器300ms防抖
this.searchTimer = setTimeout(() => {
// 如果搜索关键词与前一次相同,不重新加载
if (this.searchKeyword.trim() === this.prevSearchKeyword.trim()) {
return;
}
this.prevSearchKeyword = this.searchKeyword.trim();
this.loadDeviceList();
}, 300);
},
// 处理搜索
handleSearch() {
if (this.searchKeyword.trim() === this.prevSearchKeyword.trim()) {
return;
}
this.prevSearchKeyword = this.searchKeyword.trim();
this.loadDeviceList();
},
// 清除搜索关键词
clearSearch() {
this.searchKeyword = '';
this.prevSearchKeyword = '';
this.loadDeviceList();
},
// 处理清除搜索组件clear按钮触发
handleClearSearch() {
this.searchKeyword = '';
this.prevSearchKeyword = '';
this.loadDeviceList();
},
// 刷新列表
refreshList() {
uni.showLoading({
title: '刷新中...'
});
Promise.all([
DeviceApi.refreshDevices(),
this.loadDeviceStats(),
this.loadDeviceList()
]).finally(() => {
uni.hideLoading();
uni.showToast({
title: '刷新成功',
icon: 'success'
});
});
},
// 显示状态筛选
showStatusPopup() {
this.statusPickerShow = true;
},
// 确认状态筛选
confirmStatus(e) {
this.currentStatus = e.value[0];
this.statusPickerShow = false;
// 重新加载设备列表
this.loadDeviceList();
},
// 取消状态筛选
cancelStatus() {
this.statusPickerShow = false;
},
// 处理全选状态变化
handleSelectAllChange(value) {
// 注意这里的value是uView的checkbox传递的布尔值
console.log('全选状态变更为:', value);
// 更新所有设备的选择状态
this.deviceList.forEach(device => {
device.selected = value;
});
// 更新已选择的设备ID数组
this.selectedIds = value ? this.deviceList.map(device => device.id) : [];
},
// 处理设备选择状态变化
handleDeviceSelectChange() {
// 更新已选择的设备ID数组
this.selectedIds = this.deviceList
.filter(device => device.selected)
.map(device => device.id);
// 更新全选状态
this.selectAll = this.deviceList.length > 0 && this.selectedIds.length === this.deviceList.length;
console.log('更新全选状态为:', this.selectAll, '选中设备数:', this.selectedIds.length);
},
// 删除设备
deleteDevices() {
if (!this.hasSelected) return;
uni.showModal({
title: '删除设备',
content: `确定要删除已选择的 ${this.selectedIds.length} 台设备吗?`,
confirmColor: '#f56c6c',
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: '删除中...'
});
try {
const deletePromises = this.selectedIds.map(id => DeviceApi.deleteDevice(id));
await Promise.all(deletePromises);
// 刷新列表和统计
await this.loadDeviceStats();
await this.loadDeviceList();
uni.showToast({
title: '删除成功',
icon: 'success'
});
} catch (error) {
console.error('删除设备失败', error);
uni.showToast({
title: '删除设备失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
}
}
});
},
// 返回上一页 // 返回上一页
goBack() { goBack() {
uni.navigateBack(); uni.navigateBack();
}, },
// 前往设备详情页
goToDeviceDetail(id) {
uni.navigateTo({
url: `/pages/device/detail?id=${id}`
});
},
// 显示筛选
showFilter() {
uni.showToast({
title: '筛选功能开发中',
icon: 'none'
});
},
// 添加设备 // 添加设备
addDevice() { addDevice() {
this.showAddDeviceModal = true; this.showAddDeviceModal = true;
}, },
// 取消添加设备
cancelAddDevice() {
this.showAddDeviceModal = false;
this.deviceId = '';
},
// 确认添加设备 // 确认添加设备
confirmAddDevice() { async confirmAddDevice() {
if (!this.deviceId.trim()) { if (!this.deviceId) {
uni.showToast({ uni.showToast({
title: '请输入设备ID', title: '请输入设备ID',
icon: 'none' icon: 'none'
@@ -259,119 +576,87 @@ export default {
} }
uni.showLoading({ uni.showLoading({
title: '添加中' title: '添加中...'
}); });
setTimeout(() => { try {
uni.hideLoading(); const res = await DeviceApi.addDevice({
uni.showToast({ imei: this.deviceId,
title: '添加成功', memo: `设备-${this.deviceId.slice(-6)}`
icon: 'success'
}); });
this.cancelAddDevice();
}, 1500);
},
// 刷新列表
refreshList() {
uni.showLoading({
title: '刷新中'
});
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: '刷新成功',
icon: 'success'
});
}, 1000);
},
// 显示筛选
showFilter() {
uni.showToast({
title: '筛选功能待实现',
icon: 'none'
});
},
// 显示状态选择
showStatusPopup() {
this.statusPickerShow = true;
},
// 确认状态选择
confirmStatus(e) {
this.currentStatus = e.value[0];
this.statusPickerShow = false;
// 应用筛选逻辑
this.applyStatusFilter();
},
// 应用状态筛选
applyStatusFilter() {
uni.showLoading({
title: '筛选中'
});
// 模拟筛选过程
setTimeout(() => {
uni.hideLoading();
// 提示用户 if (res.code === 200) {
uni.showToast({
title: '添加成功',
icon: 'success'
});
this.showAddDeviceModal = false;
this.deviceId = '';
// 刷新列表和统计
await this.loadDeviceStats();
await this.loadDeviceList();
} else {
uni.showToast({
title: res.msg || '添加失败',
icon: 'none'
});
}
} catch (error) {
console.error('添加设备失败', error);
uni.showToast({ uni.showToast({
title: `已筛选: ${this.statusText}`, title: '添加设备失败',
icon: 'none' icon: 'none'
}); });
} finally {
// 这里可以添加实际的设备筛选逻辑 uni.hideLoading();
// 根据 this.currentStatus 对设备列表进行筛选 }
}, 500);
}, },
// 取消状态选择 // 取消添加设备
cancelStatus() { cancelAddDevice() {
this.statusPickerShow = false; this.showAddDeviceModal = false;
this.deviceId = '';
}, },
// 删除设备 // 格式化IMEI超过一定长度显示省略号
deleteDevices() { formatImei(imei) {
if (!this.hasSelected) return; if (!imei) return '';
uni.showModal({ // 如果IMEI长度超过16个字符则截取前16个字符并添加省略号
title: '确认删除', if (imei.length > 16) {
content: '确定要删除选中的设备吗?', return imei.substring(0, 16) + '...';
success: (res) => { }
if (res.confirm) {
uni.showToast({ return imei;
title: '删除成功', },
icon: 'success'
}); // 显示IMEI详情
this.device1Selected = false; showImeiDetail(imei) {
this.device2Selected = false; this.currentImei = imei;
this.device3Selected = false; this.showImeiModal = true;
this.device4Selected = false; },
this.selectAll = false;
} // 关闭IMEI详情模态框
closeImeiModal() {
this.showImeiModal = false;
this.currentImei = '';
},
// 复制IMEI到剪贴板
copyImei() {
uni.setClipboardData({
data: this.currentImei,
success: () => {
uni.showToast({
title: 'IMEI已复制',
icon: 'success'
});
this.closeImeiModal();
} }
}); });
}, },
// 跳转到设备详情页
goToDeviceDetail(deviceId) {
uni.navigateTo({
url: `/pages/device/detail?id=${deviceId}`
});
}
},
watch: {
selectAll(newVal) {
this.device1Selected = newVal;
this.device2Selected = newVal;
this.device3Selected = newVal;
this.device4Selected = newVal;
}
} }
} }
</script> </script>
@@ -518,8 +803,8 @@ export default {
color: #333; color: #333;
padding: 10rpx 20rpx; padding: 10rpx 20rpx;
border-radius: 20rpx; border-radius: 20rpx;
background-color: #fff; background-color: #f0f5ff;
border: 1rpx solid #e5e5e5; border: 1rpx solid #d6e4ff;
min-width: 180rpx; min-width: 180rpx;
justify-content: space-between; justify-content: space-between;
@@ -528,7 +813,35 @@ export default {
} }
&:active { &:active {
background-color: #f8f8f8; background-color: #e0ebff;
}
}
.filter-tag {
display: inline-flex;
align-items: center;
font-size: 24rpx;
color: #4080ff;
padding: 6rpx 16rpx;
border-radius: 16rpx;
background-color: #f0f5ff;
border: 1rpx solid #d6e4ff;
margin-left: 16rpx;
margin-right: auto;
max-width: 250rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.close-icon {
margin-left: 12rpx;
font-size: 28rpx;
line-height: 24rpx;
color: #999;
&:active {
color: #666;
}
} }
} }
@@ -618,6 +931,20 @@ export default {
color: #666; color: #666;
} }
.device-imei {
cursor: pointer;
.imei-text {
color: #4080ff;
padding-left: 10rpx;
font-size: 32rpx;
}
&:active {
opacity: 0.7;
}
}
.device-likes { .device-likes {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -626,6 +953,33 @@ export default {
} }
} }
} }
.loading-container, .empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.loading-text {
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
}
}
.load-more {
display: flex;
align-items: center;
justify-content: center;
padding: 30rpx 0;
.load-more-text {
font-size: 28rpx;
color: #999;
margin-left: 10rpx;
}
}
} }
/* 添加设备弹窗样式 */ /* 添加设备弹窗样式 */
@@ -740,4 +1094,104 @@ export default {
} }
} }
} }
/* IMEI详情模态框样式 */
.imei-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
position: relative;
width: 600rpx;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 40rpx;
.modal-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.modal-close {
padding: 10rpx;
.close-icon {
font-size: 44rpx;
color: #777;
line-height: 1;
}
}
}
.modal-body {
padding: 20rpx 40rpx 40rpx;
.imei-detail {
background-color: #f5f7fa;
padding: 30rpx;
border-radius: 10rpx;
margin-bottom: 30rpx;
.imei-label {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.imei-value {
display: block;
font-size: 32rpx;
color: #333;
word-break: break-all;
font-family: monospace;
line-height: 1.5;
}
}
.copy-btn {
display: flex;
align-items: center;
justify-content: center;
background-color: #4080ff;
color: #fff;
padding: 20rpx 0;
border-radius: 10rpx;
.copy-text {
margin-left: 10rpx;
font-size: 28rpx;
}
&:active {
opacity: 0.8;
}
}
}
}
}
</style> </style>

View File

@@ -91,6 +91,25 @@ function responseInterceptor(response) {
return response.data; return response.data;
} }
/**
* 构建完整的URL包括查询参数
* @param {string} baseUrl 基础URL
* @param {Object} params 查询参数
* @returns {string} 完整的URL
*/
function buildUrlWithParams(baseUrl, params) {
if (!params || Object.keys(params).length === 0) {
return baseUrl;
}
const queryString = Object.keys(params)
.filter(key => params[key] !== undefined && params[key] !== null)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&');
return queryString ? `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${queryString}` : baseUrl;
}
/** /**
* 统一请求函数 * 统一请求函数
* @param {Object} options 请求选项 * @param {Object} options 请求选项
@@ -110,12 +129,24 @@ function request(options) {
// 请求拦截 // 请求拦截
const interceptedConfig = requestInterceptor(config); const interceptedConfig = requestInterceptor(config);
// 处理GET请求参数
let url = `${interceptedConfig.baseURL}${interceptedConfig.url}`;
const method = interceptedConfig.method || 'GET';
// 如果是GET请求并且有params参数将其转换为URL查询字符串
if (method.toUpperCase() === 'GET' && interceptedConfig.params) {
url = buildUrlWithParams(url, interceptedConfig.params);
// 打印完整请求URL便于调试
console.log('完整请求URL:', url);
}
// 发起请求 // 发起请求
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.request({ uni.request({
url: `${interceptedConfig.baseURL}${interceptedConfig.url}`, url: url,
method: interceptedConfig.method || 'GET', method: method,
data: interceptedConfig.data, data: method.toUpperCase() === 'GET' ? undefined : interceptedConfig.data,
header: interceptedConfig.header, header: interceptedConfig.header,
timeout: interceptedConfig.timeout, timeout: interceptedConfig.timeout,
success: (res) => { success: (res) => {
@@ -127,12 +158,25 @@ function request(options) {
} }
}, },
fail: (err) => { fail: (err) => {
// 显示提示
uni.showToast({ uni.showToast({
title: '网络请求失败', title: '网络请求失败',
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}); });
reject(err);
// 增强错误对象,添加更多信息便于调试
const enhancedError = {
...err,
url: url,
method: method,
params: method.toUpperCase() === 'GET' ? interceptedConfig.params : undefined,
data: method.toUpperCase() === 'GET' ? undefined : interceptedConfig.data,
message: err.errMsg || '网络请求失败'
};
console.error('请求失败详情:', enhancedError);
reject(enhancedError);
} }
}); });
}); });

View File

@@ -106,26 +106,14 @@ class Device extends Controller
try { try {
// 获取登录用户信息 // 获取登录用户信息
$userInfo = request()->userInfo; $userInfo = request()->userInfo;
if (empty($userInfo)) {
return json([
'code' => 401,
'msg' => '未登录或登录已过期'
]);
}
// 获取查询条件 // 获取查询条件
$where = []; $where = [];
// 设备IMEI // 关键词搜索同时搜索IMEI和备注
$imei = Request::param('imei'); $keyword = Request::param('keyword');
if (!empty($imei)) { if (!empty($keyword)) {
$where['d.imei'] = ['like', "%{$imei}%"]; // 使用复杂条件实现OR查询
} $where[] = ['exp', "d.imei LIKE '%{$keyword}%' OR d.memo LIKE '%{$keyword}%'"];
// 设备备注
$memo = Request::param('memo');
if (!empty($memo)) {
$where['d.memo'] = ['like', "%{$memo}%"];
} }
// 设备在线状态 // 设备在线状态

View File

@@ -79,31 +79,25 @@ class Device extends Model
$where['d.isDeleted'] = 0; $where['d.isDeleted'] = 0;
} }
// 处理查询条件,避免排序规则冲突 // 构建查询对象
$conditions = [];
foreach ($where as $key => $value) {
// 对于涉及 JOIN 的字段特殊处理
if (strpos($key, 'imei') !== false) {
// 删除原本的 imei 条件,避免直接使用它
continue;
}
$conditions[$key] = $value;
}
$query = self::alias('d') $query = self::alias('d')
->field(['d.id', 'd.imei', 'd.memo', 'w.wechatId', 'd.alive', 'w.totalFriend']) ->field(['d.id', 'd.imei', 'd.memo', 'w.wechatId', 'd.alive', 'w.totalFriend'])
->leftJoin('tk_wechat_account w', 'd.imei = w.imei COLLATE utf8mb4_unicode_ci') ->leftJoin('tk_wechat_account w', 'd.imei = w.imei COLLATE utf8mb4_unicode_ci');
->where($conditions);
// 单独处理 imei 搜索条件,确保使用相同的排序规则 // 处理查询条件
if (isset($where['imei'])) { foreach ($where as $key => $value) {
if (is_array($where['imei']) && isset($where['imei'][0]) && $where['imei'][0] === 'like') { // 处理特殊的exp表达式条件
$query->where('d.imei', 'like', $where['imei'][1]); if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') {
} else { // 直接添加原始SQL表达式
$query->where('d.imei', $where['imei']); $query->whereExp('', $value[1]);
continue;
} }
// 处理普通条件
$query->where($key, $value);
} }
// 返回分页结果
return $query->order($order) return $query->order($order)
->paginate($limit, false, ['page' => $page]); ->paginate($limit, false, ['page' => $page]);
} }