forked from dyf/dyf-vue-ui
Compare commits
17 Commits
8a2978af6c
...
main
Author | SHA1 | Date | |
---|---|---|---|
1db495b08e | |||
e1738a6ea1 | |||
84aa490c20 | |||
fb8bbbf5f5 | |||
a195b3e325 | |||
c1adbbb9fe | |||
ae445e058f | |||
5835c7c3fe | |||
a6b07348a6 | |||
a01f66dcc4 | |||
3df4bc3c9b | |||
421df91afe | |||
4cfef311ec | |||
c66d309a3d | |||
f2dada978d | |||
9002ce6bc3 | |||
fa6af8602e |
@ -5,7 +5,7 @@ VITE_APP_TITLE = 物联网管理系统
|
||||
VITE_APP_ENV = 'development'
|
||||
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API = 'http://192.168.2.23:8001'
|
||||
VITE_APP_BASE_API = 'http://192.168.2.23:8000'
|
||||
|
||||
# 应用访问路径 例如使用前缀 /admin/
|
||||
VITE_APP_CONTEXT_PATH = '/'
|
||||
|
@ -1,11 +1,17 @@
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = 物联网管理系统
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
# 生产环境配置 晶全1
|
||||
VITE_APP_ENV = 'https://fuyuanshen.com/backend'
|
||||
|
||||
# 应用访问路径 例如使用前缀 /admin/
|
||||
VITE_APP_CONTEXT_PATH = '/'
|
||||
# 生产环境配置 富源晟2
|
||||
# VITE_APP_ENV = 'https://fuyuanshen.com/backend-fys'
|
||||
|
||||
# 应用访问路径 晶全1
|
||||
VITE_APP_CONTEXT_PATH = '/jingquan/'
|
||||
|
||||
# 应用访问路径 富源晟2
|
||||
#VITE_APP_CONTEXT_PATH = '/sys/'
|
||||
|
||||
# 监控地址
|
||||
VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
||||
@ -13,8 +19,11 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
||||
# SnailJob 控制台地址
|
||||
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||
|
||||
# 生产环境
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
# 生产环境 晶全3
|
||||
VITE_APP_BASE_API = '/backend'
|
||||
|
||||
# 生产环境 富源晟3
|
||||
#VITE_APP_BASE_API = '/backend-fys'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
53
README.md
53
README.md
@ -29,55 +29,4 @@ npm run dev
|
||||
npm run build:prod
|
||||
|
||||
# 前端访问地址 http://localhost:80
|
||||
```
|
||||
|
||||
## 本框架与RuoYi的业务差异
|
||||
|
||||
| 业务 | 功能说明 | 本框架 | RuoYi |
|
||||
| ------------ | ------------------------------------------------------------- | ------ | ----------------------------- |
|
||||
| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 |
|
||||
| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 |
|
||||
| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
|
||||
| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
|
||||
| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
|
||||
| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 |
|
||||
| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 |
|
||||
| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 |
|
||||
| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 |
|
||||
| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 |
|
||||
| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 |
|
||||
| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 |
|
||||
| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 |
|
||||
| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 |
|
||||
| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 |
|
||||
| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 |
|
||||
| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 |
|
||||
| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 |
|
||||
| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 |
|
||||
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 |
|
||||
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 |
|
||||
| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 |
|
||||
|
||||
## 演示图例
|
||||
|
||||
| | |
|
||||
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
"globals": "16.0.0",
|
||||
"prettier": "3.5.2",
|
||||
"sass": "1.87.0",
|
||||
"terser": "^5.43.1",
|
||||
"typescript": "~5.8.3",
|
||||
"unocss": "66.0.0",
|
||||
"unplugin-auto-import": "19.1.2",
|
||||
|
@ -72,12 +72,11 @@ export const userAllCustomerAll = () => {
|
||||
}
|
||||
|
||||
// 解绑
|
||||
|
||||
export const deviceUnbind = (data:any) => {
|
||||
export const deviceUnbind = (params:any) => {
|
||||
return request({
|
||||
url: '/api/device/unbind',
|
||||
method: 'post',
|
||||
data
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 撤回
|
||||
|
@ -4,5 +4,44 @@ export interface deviceQuery extends PageQuery {
|
||||
deviceImei: string;
|
||||
deviceType: string;
|
||||
deviceStatus: string;
|
||||
bluetoothName?: string; // 蓝牙名称查询字段
|
||||
}
|
||||
|
||||
export interface deviceForm {
|
||||
id?: string | number;
|
||||
deviceName: string;
|
||||
deviceMac?: string;
|
||||
deviceImei?: string;
|
||||
deviceType: string;
|
||||
devicePic?: string;
|
||||
image?: string | File;
|
||||
remark?: string;
|
||||
password?: string;
|
||||
customerId?: string | number;
|
||||
bluetoothName?: string; // 蓝牙名称字段
|
||||
}
|
||||
|
||||
export interface deviceVO {
|
||||
id: string | number;
|
||||
deviceName: string;
|
||||
deviceMac?: string;
|
||||
deviceImei?: string;
|
||||
deviceType: string;
|
||||
devicePic?: string;
|
||||
deviceStatus: number;
|
||||
bindingStatus: number;
|
||||
remark?: string;
|
||||
createTime?: string;
|
||||
createByName?: string;
|
||||
customerName?: string;
|
||||
customerId?: string | number;
|
||||
typeName?: string;
|
||||
bluetoothName?: string; // 蓝牙名称字段
|
||||
}
|
||||
|
||||
export interface deviceTypeOption {
|
||||
id: string | number;
|
||||
typeName: string;
|
||||
value: string | number;
|
||||
communicationMode?: string;
|
||||
}
|
@ -4,7 +4,7 @@ import { AxiosPromise } from 'axios';
|
||||
* 查询设备列表
|
||||
* @param query
|
||||
*/
|
||||
export const userList = (params): AxiosPromise => {
|
||||
export const userList = (params: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/app/user/list',
|
||||
method: 'get',
|
||||
@ -12,7 +12,7 @@ export const userList = (params): AxiosPromise => {
|
||||
});
|
||||
};
|
||||
// 绑定设备列表
|
||||
export const deviceList = (params): AxiosPromise => {
|
||||
export const deviceList = (params: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/api/app/device',
|
||||
method: 'get',
|
||||
@ -20,12 +20,24 @@ export const deviceList = (params): AxiosPromise => {
|
||||
});
|
||||
};
|
||||
// 账号状态
|
||||
export const userStatus = (data): AxiosPromise => {
|
||||
export const userStatus = (data: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/api/app/device',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
};
|
||||
// 解绑设备
|
||||
export const deviceUnBind = (data: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/api/app/device/unBind',
|
||||
method: 'delete',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data', //设置正确的 Content-Type
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default { userList,deviceList,userStatus }
|
||||
|
||||
export default { userList, deviceList, userStatus, deviceUnBind }
|
@ -20,7 +20,7 @@
|
||||
<div class="avatar-wrapper">
|
||||
<!-- <img :src="userStore.avatar" class="user-avatar" /> -->
|
||||
<img src="@/assets/images/avatar.png" class="user-avatar" />
|
||||
<div style="margin-left: 10px;">{{ useUserStore().roles[0] }}</div>
|
||||
<div style="margin-left: 10px;">{{ useUserStore().nickname }}</div>
|
||||
<el-icon><caret-bottom /></el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
@ -61,7 +61,7 @@ const newNotice = ref(<number>0);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const userId = ref(userStore.userId);
|
||||
console.log(useUserStore().roles[0], 'userStoreuserStoreuserStore');
|
||||
// console.log(useUserStore(), 'userStoreuserStoreuserStore');
|
||||
|
||||
|
||||
const companyName = ref(undefined);
|
||||
@ -82,7 +82,7 @@ const dynamicTenantEvent = async (tenantId: string) => {
|
||||
if (companyName.value != null && companyName.value !== '') {
|
||||
await dynamicTenant(tenantId);
|
||||
dynamic.value = true;
|
||||
await proxy?.$router.push('/');
|
||||
await router.push('/');
|
||||
await proxy?.$tab.closeAllPage();
|
||||
await proxy?.$tab.refreshPage();
|
||||
}
|
||||
@ -91,7 +91,7 @@ const dynamicTenantEvent = async (tenantId: string) => {
|
||||
const dynamicClearEvent = async () => {
|
||||
await dynamicClear();
|
||||
dynamic.value = false;
|
||||
await proxy?.$router.push('/');
|
||||
await router.push('/');
|
||||
await proxy?.$tab.closeAllPage();
|
||||
await proxy?.$tab.refreshPage();
|
||||
};
|
||||
|
@ -30,14 +30,14 @@ const processResponse = async (res: any) => {
|
||||
}
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
||||
location.href = (import.meta.env.VITE_APP_CONTEXT_PATH || '/') + 'index';
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleError = (error: any) => {
|
||||
ElMessage.error(error.message);
|
||||
setTimeout(() => {
|
||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
||||
location.href = (import.meta.env.VITE_APP_CONTEXT_PATH || '/') + 'index';
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
|
@ -1,29 +1,6 @@
|
||||
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
||||
/* Layout */
|
||||
import Layout from '@/layout/index.vue';
|
||||
|
||||
/**
|
||||
* Note: 路由配置项
|
||||
*
|
||||
* hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
|
||||
* alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
|
||||
* // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
|
||||
* // 若你想不管路由下面的 children 声明的个数都显示你的根路由
|
||||
* // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
|
||||
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
|
||||
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
|
||||
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
|
||||
* roles: ['admin', 'common'] // 访问路由的角色权限
|
||||
* permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
|
||||
* meta : {
|
||||
noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
|
||||
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
|
||||
icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
|
||||
breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
|
||||
activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
|
||||
}
|
||||
*/
|
||||
|
||||
// 公共路由
|
||||
export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
@ -100,7 +77,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
||||
* 创建路由
|
||||
*/
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.VITE_APP_CONTEXT_PATH),
|
||||
history: createWebHistory(import.meta.env.VITE_APP_CONTEXT_PATH || '/'),
|
||||
routes: constantRoutes,
|
||||
// 刷新时,滚动条位置还原
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
|
@ -34,9 +34,9 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="loginDate" width="180">
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ proxy.parseTime(scope.row.loginDate) }}</span>
|
||||
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" align="center">
|
||||
@ -137,10 +137,10 @@ const handleStatusChange = (row: any) => {
|
||||
getList();
|
||||
}
|
||||
}).catch(() => {
|
||||
row.status = !row.status
|
||||
getList();
|
||||
})
|
||||
}).catch(() => {
|
||||
row.status = !row.status
|
||||
getList();
|
||||
})
|
||||
};
|
||||
onMounted(() => {
|
||||
|
@ -16,18 +16,18 @@
|
||||
<el-table-column prop="deviceName" label="设备名称" />
|
||||
<el-table-column prop="devicePic" label="设备图片">
|
||||
<template #default="scope">
|
||||
<el-image style="width: 40px; height: 40px" :src="scope.row.devicePic"
|
||||
:preview-src-list="[scope.row.devicePic]" />
|
||||
<el-popover placement="right" trigger="click">
|
||||
<template #reference>
|
||||
<img :src="scope.row.devicePic" style="width: 40px; height: 40px; cursor: pointer;"
|
||||
class="hover:opacity-80 transition-opacity" />
|
||||
</template>
|
||||
<img :src="scope.row.devicePic" style="max-width: 600px; max-height: 600px;" />
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceMac" label="设备MAC" />
|
||||
<el-table-column prop="deviceImei" label="设备IMEI" />
|
||||
<el-table-column prop="deviceTypeName" label="设备类型" />
|
||||
<el-table-column prop="deviceStatus" label="状态">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.deviceStatus === 1 ? '正常' : '失效' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="typeName" label="设备类型" />
|
||||
<el-table-column prop="createTime" label="绑定日期" />
|
||||
<el-table-column label="操作" width="100" align="center">
|
||||
<template #default="scope">
|
||||
@ -74,27 +74,40 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.deviceImei = '',
|
||||
queryParams.deviceMac = '',
|
||||
queryParams.deviceName = '',
|
||||
getList()
|
||||
};
|
||||
// 列表
|
||||
const getList = async () => {
|
||||
bindingLoading.value = true;
|
||||
const res = await api.deviceList(queryParams);
|
||||
let data = {
|
||||
bindingUserId: info.value.userId,
|
||||
pageNum: queryParams.pageNum,
|
||||
pageSize: queryParams.pageSize,
|
||||
deviceName: queryParams.deviceName,
|
||||
deviceMac: queryParams.deviceMac,
|
||||
deviceImei: queryParams.deviceImei
|
||||
|
||||
}
|
||||
const res = await api.deviceList(data);
|
||||
boundDevices.value = res.rows;
|
||||
total.value = res.total;
|
||||
bindingLoading.value = false;
|
||||
};
|
||||
// 解绑
|
||||
const handleUnbind = (row) => {
|
||||
proxy?.$modal.confirm.confirm('此操作将解绑设备 "' + row.deviceName + '", 是否继续?', '提示', {
|
||||
proxy?.$modal.confirm('此操作将解绑设备 "' + row.deviceName + '", 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const data = {
|
||||
deviceMac: row.deviceMac,
|
||||
customerId: info.value.id
|
||||
// deviceMac: row.deviceMac,
|
||||
id: row.id
|
||||
}
|
||||
api.deviceList(data).then(() => {
|
||||
api.deviceUnBind(data).then(() => {
|
||||
proxy?.$modal.msgSuccess({ type: 'success', message: '解绑成功!' })
|
||||
getList()
|
||||
})
|
||||
|
@ -9,10 +9,10 @@
|
||||
<el-input v-model="queryParams.blurry" placeholder="请输入客户名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户状态" prop="status">
|
||||
<el-select v-model="queryParams.enabled" clearable placeholder="客户状态" class="filter-item">
|
||||
<el-select v-model="queryParams.status" clearable placeholder="客户状态" class="filter-item">
|
||||
<el-option label="全部" :value="''" />
|
||||
<el-option label="启用" :value="true" />
|
||||
<el-option label="禁用" :value="false" />
|
||||
<el-option label="启用" :value="0" />
|
||||
<el-option label="禁用" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" style="width: 308px">
|
||||
@ -53,10 +53,10 @@
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="客户名称" align="center" prop="nickName" />
|
||||
<el-table-column label="客户账号" align="center" prop="userName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="客户状态" align="center" prop="enabled">
|
||||
<el-table-column label="客户状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<div @click="handleStatusChange(scope.row)">
|
||||
<el-switch v-model="scope.row.enabled" />
|
||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -104,7 +104,7 @@
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item v-if="form.customerId === ''" label="账号密码" prop="password">
|
||||
<el-input v-model="form.password" placeholder="请输入账号密码" />
|
||||
<el-input v-model="form.password" placeholder="请输入账号密码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -171,8 +171,16 @@ const initData: PageData<UserForm, UserQuery> = {
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
|
||||
password: [
|
||||
{ required: true, message: '请输入账号密码', trigger: 'blur' },
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: '用户密码长度必须介于 5 和 20 之间',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{ pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
|
||||
],
|
||||
}
|
||||
};
|
||||
@ -199,6 +207,7 @@ const handleQuery = () => {
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryParams.value.pageNum = 1;
|
||||
queryParams.value.status=''
|
||||
handleQuery();
|
||||
|
||||
};
|
||||
@ -227,19 +236,24 @@ const handleDelete = async (row?: UserVO) => {
|
||||
|
||||
/** 用户状态修改 */
|
||||
const handleStatusChange = async (row: any) => {
|
||||
console.log(row, '33333333');
|
||||
const newStatus = row.enabled; // 获取新的状态值(取反)
|
||||
const text = newStatus ? '启用' : '停用';
|
||||
// 计算新状态(取反)
|
||||
const originalStatus = row.status;
|
||||
const actionText = row.status == 0 ? '启用' : '停用';
|
||||
try {
|
||||
await proxy?.$modal.confirm(`确认要${text}"${row.nickName}"客户吗?`);
|
||||
await proxy?.$modal.confirm(`确认要${actionText}"${row.nickName}"客户吗?`);
|
||||
await api.updateCustomer({
|
||||
customerId: row.customerId,
|
||||
enabled: newStatus
|
||||
enabled: originalStatus == 0 ? true : false
|
||||
});
|
||||
proxy?.$modal.msgSuccess(text + '成功');
|
||||
proxy?.$modal.msgSuccess(actionText + '成功');
|
||||
await getList();
|
||||
} catch (err) {
|
||||
row.enabled = !newStatus; // 回滚状态
|
||||
if (err == 'cancel') { // 这里假设confirm方法在用户取消时reject with 'cancel'
|
||||
console.log(err, 'errr');
|
||||
proxy?.$modal.msgWarning('操作已取消');
|
||||
await getList();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -90,6 +90,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceMac" label="设备MAC" />
|
||||
<el-table-column prop="bluetoothName" label="蓝牙名称" />
|
||||
<el-table-column prop="deviceImei" label="设备IMEI" />
|
||||
<el-table-column prop="typeName" label="设备类型" />
|
||||
<el-table-column prop="bindingStatus" label="绑定状态">
|
||||
@ -112,22 +113,21 @@
|
||||
|
||||
<el-table-column label="操作" fixed="right" width="280" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row.id !== 1" content="修改" placement="top">
|
||||
<el-tooltip v-if="scope.row.id !== 1 && scope.row.deviceStatus == 1" content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="scope.row.id !== 1" content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip :disabled="scope.row.deviceStatus === 0" content="分配" placement="top">
|
||||
<el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top">
|
||||
<el-button link type="primary" icon="User" @click="handleAssign(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="scope.row.customerName" :disabled="scope.row.deviceStatus === 0" content="撤回"
|
||||
placement="top">
|
||||
<el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top">
|
||||
<el-button link type="primary" icon="UploadFilled" @click="handleWithdraw(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑"
|
||||
placement="top">
|
||||
<el-button link type="primary" icon="UploadFilled" @click="handleUnbind(scope.row)"></el-button>
|
||||
<el-button link type="primary" icon="Refresh" @click="handleUnbind(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -166,6 +166,13 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="showMacField">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="蓝牙名称" prop="bluetoothName">
|
||||
<el-input v-model="form.bluetoothName" placeholder="请输入蓝牙名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="showImeiField">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备IMEI" prop="deviceImei">
|
||||
@ -269,7 +276,7 @@
|
||||
|
||||
<script setup name="User" lang="ts">
|
||||
import api from '@/api/equipmentManagement/device/index';
|
||||
import { deviceForm, deviceQuery, deviceVO } from '@/api/equipmentManagement/device/types';
|
||||
import { deviceForm, deviceQuery, deviceVO, deviceTypeOption } from '@/api/equipmentManagement/device/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const deviceDist = ref<deviceVO[]>();
|
||||
import { to } from 'await-to-js';
|
||||
@ -278,7 +285,7 @@ import { getBearerToken } from '@/utils/auth'
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const ids = ref<Array<number | string>>([]);
|
||||
const ids = ref<deviceVO[]>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
@ -310,7 +317,8 @@ const initFormData: deviceForm = {
|
||||
remark: '',
|
||||
id: '',
|
||||
deviceType: "",
|
||||
image: ''
|
||||
image: '',
|
||||
bluetoothName: '' // 蓝牙名称字段
|
||||
};
|
||||
|
||||
const initData: PageData<deviceForm, deviceQuery> = {
|
||||
@ -334,8 +342,8 @@ const initData: PageData<deviceForm, deviceQuery> = {
|
||||
],
|
||||
}
|
||||
};
|
||||
const data = reactive<PageData<deviceVO, deviceQuery>>(initData);
|
||||
const { queryParams, form, rules } = toRefs<PageData<deviceVO, deviceQuery>>(data);
|
||||
const data = reactive<PageData<deviceForm, deviceQuery>>(initData);
|
||||
const { queryParams, form, rules } = toRefs<PageData<deviceForm, deviceQuery>>(data);
|
||||
/** 查询设备列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
@ -363,7 +371,7 @@ const handleDelete = async (row?: deviceVO) => {
|
||||
// 批量删除逻辑
|
||||
let arrey = ids.value.map((item) => item.id);
|
||||
if (!row) {
|
||||
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`) as any);
|
||||
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`));
|
||||
if (!err) {
|
||||
await api.deleteDevice(arrey);
|
||||
await getList();
|
||||
@ -372,7 +380,7 @@ const handleDelete = async (row?: deviceVO) => {
|
||||
return;
|
||||
}
|
||||
// 单行删除逻辑
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?') as any);
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?'));
|
||||
if (!err) {
|
||||
await api.deleteDevice([row.id]);
|
||||
await getList();
|
||||
@ -397,12 +405,15 @@ const handleUnbind = (row) => {
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
api.deviceUnbind(row).then(res => {
|
||||
if (res.code === 0) {
|
||||
proxy?.$modal.msgSuccess('解绑成功')
|
||||
let data = {
|
||||
id: row.id
|
||||
}
|
||||
api.deviceUnbind(data).then(res => {
|
||||
if (res.code == 200) {
|
||||
proxy?.$modal.msgSuccess(res.msg)
|
||||
getList(); // 初始化列表数据
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '解绑失败')
|
||||
proxy?.$modal.msgError(res.msg)
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
@ -417,7 +428,7 @@ const handleWithdraw = (row: any) => {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
api.withdrawDevice([row.id]).then(res => {
|
||||
if (res.code === 0) {
|
||||
if (res.code === 200) {
|
||||
proxy?.$modal.msgSuccess('撤回成功')
|
||||
getList(); // 初始化列表数据
|
||||
} else {
|
||||
@ -459,6 +470,8 @@ const handleAdd = async () => {
|
||||
// 新增时默认不显示
|
||||
showMacField.value = false;
|
||||
showImeiField.value = false;
|
||||
// 每次打开弹框时获取最新的设备类型数据
|
||||
getDeviceType();
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
@ -466,8 +479,12 @@ const handleUpdate = async (row?: deviceForm) => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改设备';
|
||||
// 每次打开弹框时获取最新的设备类型数据
|
||||
getDeviceType();
|
||||
try {
|
||||
if (row) {
|
||||
// 使用 nextTick 确保对话框完全渲染后再设置表单值
|
||||
await nextTick();
|
||||
Object.assign(form.value, row);
|
||||
form.value.image = row.devicePic
|
||||
// 编辑时根据已有值显示字段
|
||||
@ -519,7 +536,7 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
|
||||
return;
|
||||
}
|
||||
const res = await api.getCommunicationMode({ id: deviceTypeId });
|
||||
if (res.code === 0 && res.data) {
|
||||
if (res.code == 200 && res.data) {
|
||||
communicationModeInfo.value = res.data;
|
||||
// 根据通讯方式确定显示哪个字段
|
||||
if (res.data.communicationMode == '1') { // 蓝牙设备 - 显示MAC
|
||||
@ -539,7 +556,9 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
|
||||
};
|
||||
|
||||
// 覆盖默认的上传行为,可以自定义上传的实现
|
||||
const httpRequestImg = (parm) => { };
|
||||
const httpRequestImg = (parm): Promise<any> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
const beforeUpload = (file) => {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
|
||||
@ -594,6 +613,10 @@ const submitForm = async () => {
|
||||
if (form.value.deviceImei) {
|
||||
formData.append('deviceImei', form.value.deviceImei);
|
||||
}
|
||||
// 添加蓝牙名称字段(仅蓝牙设备)
|
||||
if (form.value.bluetoothName) {
|
||||
formData.append('bluetoothName', form.value.bluetoothName);
|
||||
}
|
||||
// 根据操作类型设置URL和方法
|
||||
const isAdd = !form.value.id; // 注意这里逻辑反了,应该是没有id时是新增
|
||||
const res = await request({
|
||||
@ -604,7 +627,7 @@ const submitForm = async () => {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
if (res.code == 0) {
|
||||
if (res.code == 200) {
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
loadingIng.value = false;
|
||||
@ -645,7 +668,7 @@ const resetForm = () => {
|
||||
// 设备类型
|
||||
const getDeviceType = () => {
|
||||
api.deviceTypeAll().then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.code == 200) {
|
||||
deviceTypeOptions.value = res.data
|
||||
}
|
||||
}).catch(err => {
|
||||
@ -655,7 +678,7 @@ const getDeviceType = () => {
|
||||
// 客户下拉框
|
||||
const getAllCustomerAll = () => {
|
||||
api.userAllCustomerAll().then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.code == 200) {
|
||||
customerList.value = res.data
|
||||
}
|
||||
})
|
||||
@ -681,7 +704,7 @@ const handleAssignConfirm = () => {
|
||||
deviceIds: [assignRow.value.id]
|
||||
}
|
||||
api.deviceAssignCustomer(data).then((res) => {
|
||||
if (res.code == 0) {
|
||||
if (res.code == 200) {
|
||||
loadingIng.value = false;
|
||||
const customer = customerList.value.find(c => c.id === assignCustomerId.value)
|
||||
const customerName = customer ? customer.nickName : `ID: ${assignCustomerId.value}`
|
||||
@ -715,7 +738,7 @@ const handleBatchImport = () => {
|
||||
const downloadTemplate = () => {
|
||||
// 这里可用 window.open 或 a 标签下载模板
|
||||
const link = document.createElement('a');
|
||||
link.href = 'http://fuyuanshen.com:81/images/excel/equipmenttemplate.xlsx';
|
||||
link.href = 'https://fuyuanshen.com/fys/Equipmentimporttemplate/EquipmentImportTemplate.xlsx';
|
||||
link.download = '设备数据导入模板.xlsx'; // 可选:指定下载文件名
|
||||
link.style.display = 'none'; // 隐藏标签
|
||||
document.body.appendChild(link);
|
||||
@ -733,7 +756,7 @@ const beforeImportUpload = (file: any) => {
|
||||
//添加tokenf方法head_upload 直接返回 getBearerToken()
|
||||
const head_upload = () => getBearerToken();
|
||||
const handleImportSuccess = (response: any) => {
|
||||
if (response.code === 0) {
|
||||
if (response.code == 200) {
|
||||
importResult.value.isShow = true
|
||||
if (response.data) {
|
||||
importResult.value.succeed = response.data.successCount || 0
|
||||
@ -767,7 +790,7 @@ const handleBatchAssignConfirm = () => {
|
||||
deviceIds: selectedIds // 选中的设备ID数组
|
||||
}
|
||||
api.deviceAssignCustomer(data).then((res) => {
|
||||
if (res.code == 0) {
|
||||
if (res.code == 200) {
|
||||
batchAssignDialogVisible.value = false
|
||||
getList();
|
||||
return proxy?.$modal.msgSuccess(`分配成功`)
|
||||
|
@ -5,11 +5,22 @@ import path from 'path';
|
||||
|
||||
export default defineConfig(({ mode, command }) => {
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
|
||||
// 参考eladmin-web的部署方式,使用相对路径
|
||||
let basePath = '/';
|
||||
if (mode === 'production') {
|
||||
// 生产环境:如果设置了上下文路径则使用,否则使用相对路径
|
||||
basePath = env.VITE_APP_CONTEXT_PATH || './';
|
||||
} else {
|
||||
// 开发环境:使用上下文路径或默认根路径
|
||||
basePath = env.VITE_APP_CONTEXT_PATH || '/';
|
||||
}
|
||||
|
||||
return {
|
||||
// 部署生产环境和开发环境下的URL。
|
||||
// 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
|
||||
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
|
||||
base: env.VITE_APP_CONTEXT_PATH,
|
||||
base: basePath,
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src')
|
||||
@ -24,7 +35,7 @@ export default defineConfig(({ mode, command }) => {
|
||||
open: true,
|
||||
proxy: {
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
target: 'http://localhost:8001',
|
||||
target: env.VITE_APP_PROXY_TARGET || 'http://localhost:8001',
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||
@ -54,6 +65,48 @@ export default defineConfig(({ mode, command }) => {
|
||||
]
|
||||
}
|
||||
},
|
||||
// 构建配置
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'static',
|
||||
// 生产环境关闭source map
|
||||
sourcemap: mode === 'development',
|
||||
// 构建时清理输出目录
|
||||
emptyOutDir: true,
|
||||
// 大文件警告限制
|
||||
chunkSizeWarningLimit: 2000,
|
||||
// 代码分割配置
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// 静态资源分类打包
|
||||
chunkFileNames: 'static/js/[name]-[hash].js',
|
||||
entryFileNames: 'static/js/[name]-[hash].js',
|
||||
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
|
||||
// 代码分割
|
||||
manualChunks: {
|
||||
// 将 Vue 相关的包打包到一个 chunk 中
|
||||
vue: ['vue', 'vue-router', 'pinia'],
|
||||
// 将 Element Plus 相关的包打包到一个 chunk 中
|
||||
elementPlus: ['element-plus', '@element-plus/icons-vue'],
|
||||
// 将 ECharts 相关的包打包到一个 chunk 中
|
||||
echarts: ['echarts'],
|
||||
// 将工具库打包到一个 chunk 中
|
||||
utils: ['axios', '@vueuse/core', 'crypto-js', 'js-cookie', 'jsencrypt'],
|
||||
// 将编辑器相关的包打包到一个 chunk 中
|
||||
editor: ['@vueup/vue-quill', 'vue-json-pretty']
|
||||
}
|
||||
}
|
||||
},
|
||||
// 压缩配置
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
// 生产环境移除console
|
||||
drop_console: mode === 'production',
|
||||
drop_debugger: mode === 'production'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 预编译
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
|
Reference in New Issue
Block a user