diff --git a/Cunkebao/api/device.js b/Cunkebao/api/device.js
new file mode 100644
index 00000000..d233516c
--- /dev/null
+++ b/Cunkebao/api/device.js
@@ -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
+ })
+}
\ No newline at end of file
diff --git a/Cunkebao/pages/device/index.vue b/Cunkebao/pages/device/index.vue
index 2addc163..0d6ebcad 100644
--- a/Cunkebao/pages/device/index.vue
+++ b/Cunkebao/pages/device/index.vue
@@ -19,11 +19,11 @@
总设备数
- 42
+ {{ totalDeviceCount }}
在线设备
- 35
+ {{ onlineDeviceCount }}
@@ -40,6 +40,9 @@
bgColor="#fff"
searchIconSize="50"
shape="round"
+ @search="handleSearch"
+ @clear="handleClearSearch"
+ @input="handleSearchInput"
>
@@ -56,8 +59,20 @@
{{ statusText }}
-
-
+
+
+ {{ searchKeyword }}
+ ×
+
+
+
全选
@@ -67,83 +82,66 @@
-
-
-
-
-
-
-
- IMEI: sd123123
- 微信号: wxid_hxdxdoal
-
- 好友数: 435
- 今日新增: +20
-
-
+
+
+
+ 加载中...
-
-
-
-
-
-
-
- IMEI: sd123124
- 微信号: wxid_2i7sncgq
-
- 好友数: 143
- 今日新增: +26
-
-
+
+
+
-
-
-
-
-
-
-
@@ -190,13 +188,37 @@
+
+
+
+
+
+
+
+ IMEI:
+ {{ currentImei }}
+
+
+ 复制IMEI
+
+
+
+
+
-
+
@@ -518,8 +803,8 @@ export default {
color: #333;
padding: 10rpx 20rpx;
border-radius: 20rpx;
- background-color: #fff;
- border: 1rpx solid #e5e5e5;
+ background-color: #f0f5ff;
+ border: 1rpx solid #d6e4ff;
min-width: 180rpx;
justify-content: space-between;
@@ -528,7 +813,35 @@ export default {
}
&: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;
}
+ .device-imei {
+ cursor: pointer;
+
+ .imei-text {
+ color: #4080ff;
+ padding-left: 10rpx;
+ font-size: 32rpx;
+ }
+
+ &:active {
+ opacity: 0.7;
+ }
+ }
+
.device-likes {
display: flex;
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;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cunkebao/utils/request.js b/Cunkebao/utils/request.js
index 8868477c..47966488 100644
--- a/Cunkebao/utils/request.js
+++ b/Cunkebao/utils/request.js
@@ -91,6 +91,25 @@ function responseInterceptor(response) {
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 请求选项
@@ -110,12 +129,24 @@ function request(options) {
// 请求拦截
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) => {
uni.request({
- url: `${interceptedConfig.baseURL}${interceptedConfig.url}`,
- method: interceptedConfig.method || 'GET',
- data: interceptedConfig.data,
+ url: url,
+ method: method,
+ data: method.toUpperCase() === 'GET' ? undefined : interceptedConfig.data,
header: interceptedConfig.header,
timeout: interceptedConfig.timeout,
success: (res) => {
@@ -127,12 +158,25 @@ function request(options) {
}
},
fail: (err) => {
+ // 显示提示
uni.showToast({
title: '网络请求失败',
icon: 'none',
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);
}
});
});
diff --git a/Server/application/devices/controller/Device.php b/Server/application/devices/controller/Device.php
index a95b653e..9c264a3f 100644
--- a/Server/application/devices/controller/Device.php
+++ b/Server/application/devices/controller/Device.php
@@ -106,26 +106,14 @@ class Device extends Controller
try {
// 获取登录用户信息
$userInfo = request()->userInfo;
- if (empty($userInfo)) {
- return json([
- 'code' => 401,
- 'msg' => '未登录或登录已过期'
- ]);
- }
-
// 获取查询条件
$where = [];
- // 设备IMEI
- $imei = Request::param('imei');
- if (!empty($imei)) {
- $where['d.imei'] = ['like', "%{$imei}%"];
- }
-
- // 设备备注
- $memo = Request::param('memo');
- if (!empty($memo)) {
- $where['d.memo'] = ['like', "%{$memo}%"];
+ // 关键词搜索(同时搜索IMEI和备注)
+ $keyword = Request::param('keyword');
+ if (!empty($keyword)) {
+ // 使用复杂条件实现OR查询
+ $where[] = ['exp', "d.imei LIKE '%{$keyword}%' OR d.memo LIKE '%{$keyword}%'"];
}
// 设备在线状态
diff --git a/Server/application/devices/model/Device.php b/Server/application/devices/model/Device.php
index cff3748e..507b9139 100644
--- a/Server/application/devices/model/Device.php
+++ b/Server/application/devices/model/Device.php
@@ -79,31 +79,25 @@ class Device extends Model
$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')
->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')
- ->where($conditions);
+ ->leftJoin('tk_wechat_account w', 'd.imei = w.imei COLLATE utf8mb4_unicode_ci');
- // 单独处理 imei 搜索条件,确保使用相同的排序规则
- if (isset($where['imei'])) {
- if (is_array($where['imei']) && isset($where['imei'][0]) && $where['imei'][0] === 'like') {
- $query->where('d.imei', 'like', $where['imei'][1]);
- } else {
- $query->where('d.imei', $where['imei']);
+ // 处理查询条件
+ foreach ($where as $key => $value) {
+ // 处理特殊的exp表达式条件
+ if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') {
+ // 直接添加原始SQL表达式
+ $query->whereExp('', $value[1]);
+ continue;
}
+
+ // 处理普通条件
+ $query->where($key, $value);
}
+ // 返回分页结果
return $query->order($order)
->paginate($limit, false, ['page' => $page]);
}