Compare commits
2 Commits
e9b7973b83
...
9715c8755d
| Author | SHA1 | Date | |
|---|---|---|---|
| 9715c8755d | |||
| 1aa9eb23e0 |
@ -1,11 +1,11 @@
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统11
|
||||
VITE_APP_TITLE = 物联网管理系统
|
||||
|
||||
# 开发环境配置
|
||||
VITE_APP_ENV = 'development'
|
||||
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
VITE_APP_BASE_API = 'http://192.168.2.23:8001'
|
||||
|
||||
# 应用访问路径 例如使用前缀 /admin/
|
||||
VITE_APP_CONTEXT_PATH = '/'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
|
||||
VITE_APP_TITLE = 物联网管理系统
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title>RuoYi-Vue-Plus多租户管理系统</title>
|
||||
<title>物联网管理系统</title>
|
||||
<!--[if lt IE 11
|
||||
]><script>
|
||||
window.location.href = '/html/ie.html';
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package",
|
||||
"name": "ruoyi-vue-plus",
|
||||
"name": "fys",
|
||||
"version": "5.4.0-2.4.0",
|
||||
"description": "RuoYi-Vue-Plus多租户管理系统",
|
||||
"description": "物联网管理系统",
|
||||
"author": "LionLi",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -35,6 +35,7 @@
|
||||
"image-conversion": "2.1.1",
|
||||
"js-cookie": "3.0.5",
|
||||
"jsencrypt": "3.3.2",
|
||||
"mitt": "^3.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "3.0.2",
|
||||
"screenfull": "6.0.2",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.9 KiB |
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
42
src/api/customerManagement/index.ts
Normal file
42
src/api/customerManagement/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { customerManagementForm, customerManagementQuery, customerManagementVO, customerManagementInfoVO } from './types';
|
||||
/**
|
||||
* 查询用户客户列表
|
||||
* @param query
|
||||
*/
|
||||
export const customerUser = (query: customerManagementQuery): AxiosPromise<customerManagementVO[]> => {
|
||||
return request({
|
||||
url: '/api/customers/customer',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
// *********新增客户*************
|
||||
export const addCustomer = (data: any): AxiosPromise<customerManagementVO[]> => {
|
||||
return request({
|
||||
url: '/api/customers/addCustomer',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 修改
|
||||
export const updateCustomer = (data: any): AxiosPromise<customerManagementVO[]> => {
|
||||
return request({
|
||||
url: '/api/customers/updateCustomer',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 删除
|
||||
export const deleteCustomer = (ids: any): AxiosPromise<customerManagementVO[]> => {
|
||||
return request({
|
||||
url: '/api/customers/deleteCustomer',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export default { customerUser, addCustomer, updateCustomer, deleteCustomer }
|
||||
|
||||
0
src/api/customerManagement/types.ts
Normal file
0
src/api/customerManagement/types.ts
Normal file
103
src/api/equipmentManagement/device/index.ts
Normal file
103
src/api/equipmentManagement/device/index.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { deviceForm, deviceQuery, deviceVO } from './types';
|
||||
/**
|
||||
* 查询设备列表
|
||||
* @param query
|
||||
*/
|
||||
export const deviceList = (query: deviceQuery): AxiosPromise<deviceVO[]> => {
|
||||
return request({
|
||||
url: '/api/device',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
// *********新增设备列表*************
|
||||
export const addDevice = (data: any): AxiosPromise<deviceVO[]> => {
|
||||
return request({
|
||||
url: '/api/device/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 修改
|
||||
export const updateDevice = (data: any): AxiosPromise<deviceVO[]> => {
|
||||
return request({
|
||||
url: '/api/device/update',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 删除
|
||||
export const deleteDevice = (ids: any): AxiosPromise<deviceVO[]> => {
|
||||
return request({
|
||||
url: '/api/device/delete',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
// 设备下拉框
|
||||
export const deviceTypeAll = () => {
|
||||
return request({
|
||||
url: '/api/deviceType/all',
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 设备类型
|
||||
export const getCommunicationMode = (params: any) => {
|
||||
return request({
|
||||
url: '/api/deviceType/communicationMode',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 分配客户
|
||||
export const deviceAssignCustomer = (data: any) => {
|
||||
return request({
|
||||
url: '/api/device/assignCustomer',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 客户下拉框
|
||||
export const userAllCustomerAll = () => {
|
||||
return request({
|
||||
url: '/api/customers/allCustomer',
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 解绑
|
||||
|
||||
export const deviceUnbind = (data:any) => {
|
||||
return request({
|
||||
url: '/api/device/unbind',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 撤回
|
||||
export const withdrawDevice = (data:any) => {
|
||||
return request({
|
||||
url: '/api/device/withdraw',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 下载模板
|
||||
export const deviceTemplate=()=> {
|
||||
return request({
|
||||
url: '/api/device/template',
|
||||
method: ' GET',
|
||||
})
|
||||
}
|
||||
// 导入文件excel
|
||||
export const devicDeimport = () => {
|
||||
return `${import.meta.env.VITE_APP_BASE_API}/api/device/import`
|
||||
}
|
||||
export default { deviceList, addDevice, updateDevice, deleteDevice, deviceTypeAll, getCommunicationMode, userAllCustomerAll, deviceAssignCustomer, deviceUnbind,withdrawDevice,deviceTemplate,devicDeimport }
|
||||
|
||||
8
src/api/equipmentManagement/device/types.ts
Normal file
8
src/api/equipmentManagement/device/types.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface deviceQuery extends PageQuery {
|
||||
deviceName: string;
|
||||
deviceMac: string;
|
||||
deviceImei: string;
|
||||
deviceType: string;
|
||||
deviceStatus: string;
|
||||
|
||||
}
|
||||
42
src/api/equipmentManagement/deviceType/index.ts
Normal file
42
src/api/equipmentManagement/deviceType/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { deviceTypeForm, deviceTypeQuery, deviceTypeVO } from './types';
|
||||
/**
|
||||
* 查询设备类型
|
||||
* @param query
|
||||
*/
|
||||
export const deviceType = (query: deviceTypeQuery): AxiosPromise<deviceTypeVO[]> => {
|
||||
return request({
|
||||
url: '/api/deviceType',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
// *********新增设备类型*************
|
||||
export const addDeviceType = (data: any): AxiosPromise<deviceTypeVO[]> => {
|
||||
return request({
|
||||
url: '/api/deviceType/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 修改
|
||||
export const updateDeviceType = (data: any): AxiosPromise<deviceTypeVO[]> => {
|
||||
return request({
|
||||
url: '/api/deviceType/update',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 删除
|
||||
export const deleteDeviceType = (ids: any): AxiosPromise<deviceTypeVO[]> => {
|
||||
return request({
|
||||
url: '/api/deviceType/delete',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export default { deviceType, addDeviceType, updateDeviceType, deleteDeviceType }
|
||||
|
||||
4
src/api/equipmentManagement/deviceType/types.ts
Normal file
4
src/api/equipmentManagement/deviceType/types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface deviceTypeQuery extends PageQuery {
|
||||
typeName: string;
|
||||
|
||||
}
|
||||
BIN
src/assets/images/avatar.png
Normal file
BIN
src/assets/images/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/images/下载.png
Normal file
BIN
src/assets/images/下载.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 19 KiB |
@ -134,7 +134,7 @@
|
||||
/* 当 el-form 的 inline 属性为 true 时 */
|
||||
/* 设置 label 的宽度默认为 68px */
|
||||
.el-form--inline .el-form-item__label {
|
||||
width: 68px;
|
||||
// width: 68px;
|
||||
}
|
||||
|
||||
/* 设置 el-select 的宽度默认为 240px */
|
||||
|
||||
@ -1,34 +1,28 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
|
||||
@toggle-click="toggleSideBar" />
|
||||
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
|
||||
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
|
||||
|
||||
<div class="right-menu flex align-center">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<el-select
|
||||
v-if="userId === 1 && tenantEnabled"
|
||||
v-model="companyName"
|
||||
class="min-w-244px"
|
||||
clearable
|
||||
filterable
|
||||
reserve-keyword
|
||||
:placeholder="proxy.$t('navbar.selectTenant')"
|
||||
@change="dynamicTenantEvent"
|
||||
@clear="dynamicClearEvent"
|
||||
>
|
||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
|
||||
<el-select v-if="userId === 1 && tenantEnabled" v-model="companyName" class="min-w-244px" clearable filterable
|
||||
reserve-keyword :placeholder="proxy.$t('navbar.selectTenant')" @change="dynamicTenantEvent"
|
||||
@clear="dynamicClearEvent">
|
||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId">
|
||||
</el-option>
|
||||
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
||||
</el-select>
|
||||
|
||||
<search-menu ref="searchMenuRef" />
|
||||
<!-- <search-menu ref="searchMenuRef" />
|
||||
<el-tooltip content="搜索" effect="dark" placement="bottom">
|
||||
<div class="right-menu-item hover-effect" @click="openSearchMenu">
|
||||
<svg-icon class-name="search-icon" icon-class="search" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</el-tooltip> -->
|
||||
<!-- 消息 -->
|
||||
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||
<!-- <el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||
<div>
|
||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||
<template #reference>
|
||||
@ -41,8 +35,8 @@
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="Github" effect="dark" placement="bottom">
|
||||
</el-tooltip> -->
|
||||
<!-- <el-tooltip content="Github" effect="dark" placement="bottom">
|
||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
|
||||
@ -60,12 +54,14 @@
|
||||
|
||||
<el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom">
|
||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
</el-tooltip> -->
|
||||
</template>
|
||||
<div class="avatar-container">
|
||||
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="userStore.avatar" class="user-avatar" />
|
||||
<!-- <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>
|
||||
<el-icon><caret-bottom /></el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
@ -109,6 +105,9 @@ const newNotice = ref(<number>0);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const userId = ref(userStore.userId);
|
||||
console.log(useUserStore().roles[0], 'userStoreuserStoreuserStore');
|
||||
|
||||
|
||||
const companyName = ref(undefined);
|
||||
const tenantList = ref<TenantVO[]>([]);
|
||||
// 是否切换了租户
|
||||
@ -159,7 +158,7 @@ const toggleSideBar = () => {
|
||||
};
|
||||
|
||||
const logout = async () => {
|
||||
await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
||||
await ElMessageBox.confirm('确定要退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
@ -285,21 +284,25 @@ watch(
|
||||
.avatar-wrapper {
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
// margin-top: 10px;
|
||||
}
|
||||
|
||||
i {
|
||||
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
right: -28px;
|
||||
top: -2px;
|
||||
font-size: 21px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const title = ref('RuoYi-Vue-Plus');
|
||||
const title = ref('物联网管理系统');
|
||||
const settingsStore = useSettingsStore();
|
||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
</script>
|
||||
|
||||
@ -11,7 +11,9 @@ import router from './router';
|
||||
|
||||
// 自定义指令
|
||||
import directive from './directive';
|
||||
|
||||
//引入mitt
|
||||
import mitt, { Emitter } from "mitt";
|
||||
const mitter = mitt();
|
||||
// 注册插件
|
||||
import plugins from './plugins/index'; // plugins
|
||||
|
||||
@ -43,7 +45,10 @@ import { ElDialog } from 'element-plus';
|
||||
ElDialog.props.closeOnClickModal.default = false;
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
//mit事件总线
|
||||
app.config.globalProperties.$mitt = mitter;
|
||||
// 不需使用 getCurrentInstance 获取实例
|
||||
app.provide("$mitt", mitter);
|
||||
app.use(HighLight);
|
||||
app.use(ElementIcons);
|
||||
app.use(router);
|
||||
|
||||
@ -51,7 +51,7 @@ export default {
|
||||
ElNotification.warning(content);
|
||||
},
|
||||
// 确认窗体
|
||||
confirm(content: any): Promise<MessageBoxData> {
|
||||
confirm(content: any, p0: string, p1: { confirmButtonText: string; cancelButtonText: string; type: string; }): Promise<MessageBoxData> {
|
||||
return ElMessageBox.confirm(content, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
|
||||
@ -3,6 +3,11 @@ const TokenKey = 'Admin-Token';
|
||||
const tokenStorage = useStorage<null | string>(TokenKey, null);
|
||||
|
||||
export const getToken = () => tokenStorage.value;
|
||||
//添加token特殊处理,没有应用到全局
|
||||
export const getBearerToken = () => ({
|
||||
Authorization: tokenStorage.value ? `Bearer ${tokenStorage.value}` : undefined,
|
||||
clientid: import.meta.env.VITE_APP_CLIENT_ID,
|
||||
});
|
||||
|
||||
export const setToken = (access_token: string) => (tokenStorage.value = access_token);
|
||||
|
||||
|
||||
@ -146,7 +146,7 @@ service.interceptors.response.use(
|
||||
isRelogin.show = false;
|
||||
});
|
||||
}
|
||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
|
||||
return Promise.reject('token已过期,请重新登录。');
|
||||
} else if (code === HttpStatus.SERVER_ERROR) {
|
||||
ElMessage({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg));
|
||||
@ -173,19 +173,28 @@ service.interceptors.response.use(
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
// 通用下载方法
|
||||
export function download(url: string, params: any, fileName: string) {
|
||||
downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
|
||||
// prettier-ignore
|
||||
return service.post(url, params, {
|
||||
transformRequest: [
|
||||
(params: any) => {
|
||||
return tansParams(params);
|
||||
}
|
||||
],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
responseType: 'blob'
|
||||
}).then(async (resp: any) => {
|
||||
// 通用下载方法 get 跟post下载方式
|
||||
export function download(url: string, params: any, fileName: string, method: 'get' | 'post' = 'post') {
|
||||
downloadLoadingInstance = ElLoading.service({
|
||||
text: '正在下载数据,请稍候',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
// 请求配置
|
||||
const config = {
|
||||
method,
|
||||
responseType: 'blob',
|
||||
[method === 'get' ? 'params' : 'data']: method === 'get' ? params : tansParams(params),
|
||||
headers: {
|
||||
'Content-Type': method === 'get'
|
||||
? 'application/json'
|
||||
: 'application/x-www-form-urlencoded'
|
||||
}
|
||||
};
|
||||
return service.request({
|
||||
url,
|
||||
...config
|
||||
})
|
||||
.then(async (resp: any) => {
|
||||
const isLogin = blobValidate(resp);
|
||||
if (isLogin) {
|
||||
const blob = new Blob([resp]);
|
||||
@ -203,6 +212,7 @@ export function download(url: string, params: any, fileName: string) {
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!');
|
||||
downloadLoadingInstance.close();
|
||||
});
|
||||
|
||||
}
|
||||
// 导出 axios 实例
|
||||
export default service;
|
||||
|
||||
328
src/views/customerManagement/index.vue
Normal file
328
src/views/customerManagement/index.vue
Normal file
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="客户名称" prop="blurry">
|
||||
<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-option label="全部" :value="''" />
|
||||
<el-option label="启用" :value="true" />
|
||||
<el-option label="禁用" :value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" style="width: 308px">
|
||||
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||||
修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="customerList" @selection-change="handleSelectionChange">
|
||||
<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">
|
||||
<template #default="scope">
|
||||
<div @click="handleStatusChange(scope.row)">
|
||||
<el-switch v-model="scope.row.enabled" />
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.createTime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row.userId !== 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.userId !== 1" content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||||
:total="total" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="25%" append-to-body
|
||||
@close="closeDialog">
|
||||
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="客户名称" prop="nickName">
|
||||
<el-input v-model="form.nickName" placeholder="请输入客户名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="客户账号" prop="userName">
|
||||
<el-input v-model="form.userName" placeholder="请输入客户账号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item v-if="form.customerId === ''" label="账号密码" prop="password">
|
||||
<el-input v-model="form.password" placeholder="请输入账号密码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm" :loading="loadingIng">确 定</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="User" lang="ts">
|
||||
import api from '@/api/customerManagement';
|
||||
import { UserForm, UserQuery, UserVO } from '@/api/customerManagement/types';
|
||||
import { to } from 'await-to-js';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const customerList = ref<UserVO[]>();
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<number | string>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const initPassword = ref<string>('');
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const userFormRef = ref<ElFormInstance>();
|
||||
const formDialogRef = ref<ElDialogInstance>();
|
||||
const loadingIng = ref(false)
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: UserForm = {
|
||||
userName: '',
|
||||
nickName: undefined,
|
||||
password: '',
|
||||
enabled: true,
|
||||
customerId: ''
|
||||
};
|
||||
|
||||
const initData: PageData<UserForm, UserQuery> = {
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
blurry: '',
|
||||
enabled: '',
|
||||
},
|
||||
rules: {
|
||||
nickName: [
|
||||
{ required: true, message: '请输入客户名称', trigger: 'blur' },
|
||||
],
|
||||
userName: [
|
||||
{ required: true, message: '请输入客户账号', trigger: 'blur' },
|
||||
{
|
||||
min: 2,
|
||||
max: 20,
|
||||
message: '客户账号长度必须在 2 和 20 之间',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入账号密码', trigger: 'blur' },
|
||||
],
|
||||
}
|
||||
};
|
||||
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
||||
|
||||
const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
|
||||
|
||||
/** 查询用户列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await api.customerUser(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||
loading.value = false;
|
||||
customerList.value = res.rows;
|
||||
total.value = res.total;
|
||||
};
|
||||
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryParams.value.pageNum = 1;
|
||||
handleQuery();
|
||||
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: UserVO) => {
|
||||
// 批量删除逻辑
|
||||
let arrey = ids.value.map((item) => item.customerId);
|
||||
if (!row) {
|
||||
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`) as any);
|
||||
if (!err) {
|
||||
await api.deleteCustomer(arrey);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 单行删除逻辑
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.nickName + '"的数据项?') as any);
|
||||
if (!err) {
|
||||
await api.deleteCustomer([row.customerId]);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
};
|
||||
|
||||
/** 用户状态修改 */
|
||||
const handleStatusChange = async (row: any) => {
|
||||
console.log(row, '33333333');
|
||||
const newStatus = row.enabled; // 获取新的状态值(取反)
|
||||
const text = newStatus ? '启用' : '停用';
|
||||
try {
|
||||
await proxy?.$modal.confirm(`确认要${text}"${row.nickName}"客户吗?`);
|
||||
await api.updateCustomer({
|
||||
customerId: row.customerId,
|
||||
enabled: newStatus
|
||||
});
|
||||
proxy?.$modal.msgSuccess(text + '成功');
|
||||
await getList();
|
||||
} catch (err) {
|
||||
row.enabled = !newStatus; // 回滚状态
|
||||
}
|
||||
};
|
||||
|
||||
/** 选择条数 */
|
||||
const handleSelectionChange = (selection: UserVO[]) => {
|
||||
ids.value = selection.map((item) => item);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
|
||||
/** 重置操作表单 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
userFormRef.value?.resetFields();
|
||||
};
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
dialog.visible = false;
|
||||
reset();
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = async () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '新增客户';
|
||||
form.value.password = initPassword.value.toString();
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: UserForm) => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改客户';
|
||||
try {
|
||||
if (row) {
|
||||
// 从行内按钮调用,直接使用行数据
|
||||
Object.assign(form.value, row);
|
||||
} else {
|
||||
const customerId = ids.value[0];
|
||||
Object.assign(form.value, customerId);
|
||||
}
|
||||
} catch (error) {
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
|
||||
userFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
loadingIng.value = true
|
||||
form.value.customerId ? await api.updateCustomer(form.value) : await api.addCustomer(form.value);
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
loadingIng.value = false
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭用户弹窗
|
||||
*/
|
||||
const closeDialog = () => {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
userFormRef.value?.resetFields();
|
||||
userFormRef.value?.clearValidate();
|
||||
form.value.customerId = undefined;
|
||||
};
|
||||
onMounted(() => {
|
||||
getList(); // 初始化列表数据
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
315
src/views/equipmentManagement/deviceType/index.vue
Normal file
315
src/views/equipmentManagement/deviceType/index.vue
Normal file
@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="型号名称" prop="typeName">
|
||||
<el-input v-model="queryParams.typeName" placeholder="请输入型号名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||||
修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="deviceTypeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="型号名称" align="center" prop="typeName" />
|
||||
<el-table-column label="是否支持蓝牙" align="center" prop="isSupportBle">
|
||||
<template #default="scope">
|
||||
{{ scope.row.isSupportBle ? '是' : '否' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="locateMode" label="定位方式">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.locateMode == 0">无</div>
|
||||
<div v-if="scope.row.locateMode == 1">GPS</div>
|
||||
<div v-if="scope.row.locateMode == 2">基站</div>
|
||||
<div v-if="scope.row.locateMode == 3">wifi</div>
|
||||
<div v-if="scope.row.locateMode == 4">北斗</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="communicationMode" label="通讯方式">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.communicationMode == 0">4G</div>
|
||||
<div v-if="scope.row.communicationMode == 1">蓝牙</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建日期" />
|
||||
<el-table-column prop="createByName" label="创建人" />
|
||||
|
||||
<el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row.id !== 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>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||||
:total="total" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="30%" append-to-body
|
||||
@close="closeDialog">
|
||||
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备类型名称" prop="typeName">
|
||||
<el-input v-model="form.typeName" placeholder="请输入设备类型名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="是否支持蓝牙" prop="isSupportBle">
|
||||
<el-select v-model="form.isSupportBle" placeholder="请选择">
|
||||
<el-option label="是" :value="true" />
|
||||
<el-option label="否" :value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="定位方式" prop="locateMode">
|
||||
<el-select v-model="form.locateMode" placeholder="请选择">
|
||||
<el-option label="无" value="0" />
|
||||
<el-option label="GPS" value="1" />
|
||||
<el-option label="基站" value="2" />
|
||||
<el-option label="wifi" value="3" />
|
||||
<el-option label="北斗" value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="通讯方式" prop="communicationMode">
|
||||
<el-select v-model="form.communicationMode" placeholder="请选择">
|
||||
<el-option label="4G" value="0" />
|
||||
<el-option label="蓝牙" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm" :loading="loadingIng">确 定</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="User" lang="ts">
|
||||
import api from '@/api/equipmentManagement/deviceType/index';
|
||||
import { UserForm, deviceTypeQuery, deviceTypeVO } from '@/api/equipmentManagement/deviceType/types';
|
||||
import { UserQuery, UserVO } from '@/api/system/user/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const deviceTypeList = ref<deviceTypeVO[]>();
|
||||
import { to } from 'await-to-js';
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<number | string>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const initPassword = ref<string>('');
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const userFormRef = ref<ElFormInstance>();
|
||||
const formDialogRef = ref<ElDialogInstance>();
|
||||
const loadingIng = ref(false)
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: UserForm = {
|
||||
typeName: '',
|
||||
isSupportBle: '',
|
||||
locateMode: '',
|
||||
communicationMode: '',
|
||||
id: ''
|
||||
};
|
||||
|
||||
const initData: PageData<UserForm, deviceTypeQuery> = {
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
typeName: '',
|
||||
|
||||
},
|
||||
rules: {
|
||||
typeName: [
|
||||
{ required: true, message: '请输入设备类型名称', trigger: 'blur' },
|
||||
],
|
||||
locateMode: [
|
||||
{ required: true, message: '请选择定位方式', trigger: 'blur' },
|
||||
],
|
||||
communicationMode: [
|
||||
{ required: true, message: '请选择通讯方式', trigger: 'blur' },
|
||||
],
|
||||
}
|
||||
};
|
||||
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
||||
const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
|
||||
/** 查询用户列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await api.deviceType(queryParams.value);
|
||||
loading.value = false;
|
||||
deviceTypeList.value = res.rows;
|
||||
total.value = res.total;
|
||||
};
|
||||
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryParams.value.typeName = ''
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: UserVO) => {
|
||||
// 批量删除逻辑
|
||||
let arrey = ids.value.map((item) => item.id);
|
||||
if (!row) {
|
||||
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`) as any);
|
||||
if (!err) {
|
||||
await api.deleteDeviceType(arrey);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 单行删除逻辑
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.typeName + '"的数据项?') as any);
|
||||
if (!err) {
|
||||
await api.deleteDeviceType([row.id]);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
};
|
||||
|
||||
/** 选择条数 */
|
||||
const handleSelectionChange = (selection: UserVO[]) => {
|
||||
ids.value = selection.map((item) => item);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
|
||||
/** 重置操作表单 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
userFormRef.value?.resetFields();
|
||||
};
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
dialog.visible = false;
|
||||
reset();
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = async () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '新增设备类型';
|
||||
form.value.password = initPassword.value.toString();
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: UserForm) => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改设备类型';
|
||||
try {
|
||||
if (row) {
|
||||
// 从行内按钮调用,直接使用行数据
|
||||
Object.assign(form.value, row);
|
||||
} else {
|
||||
const customerId = ids.value[0];
|
||||
Object.assign(form.value, customerId);
|
||||
}
|
||||
} catch (error) {
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
userFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
loadingIng.value = true;
|
||||
form.value.id ? await api.updateDeviceType(form.value) : await api.addDeviceType(form.value);
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
loadingIng.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭用户弹窗
|
||||
*/
|
||||
const closeDialog = () => {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
userFormRef.value?.resetFields();
|
||||
userFormRef.value?.clearValidate();
|
||||
form.value.customerId = undefined;
|
||||
};
|
||||
onMounted(() => {
|
||||
getList(); // 初始化列表数据
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
813
src/views/equipmentManagement/devices/index.vue
Normal file
813
src/views/equipmentManagement/devices/index.vue
Normal file
@ -0,0 +1,813 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="设备名称" prop="deviceName">
|
||||
<el-input v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备MAC" prop="deviceMac">
|
||||
<el-input v-model="queryParams.deviceMac" placeholder="请输入设备MAC" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="请输入设备IMEI" prop="deviceImei">
|
||||
<el-input v-model="queryParams.deviceImei" placeholder="请输入设备IMEI" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型" prop="deviceType">
|
||||
<el-select v-model="queryParams.deviceType" placeholder="设备类型">
|
||||
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName"
|
||||
:value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备状态" prop="deviceStatus">
|
||||
<el-select v-model="queryParams.deviceStatus" placeholder="设备状态" style="margin-left: 10px;">
|
||||
<el-option label="正常" value="1" />
|
||||
<el-option label="失效" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||||
修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" :disabled="multiple" plain icon="Download" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain :disabled="multiple" @click="handleDelete()">
|
||||
批量删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain @click="handleBatchImport">
|
||||
批量导入
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain :disabled="multiple" @click="handleBatchAssign">
|
||||
批量分配客户
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="deviceDist" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="设备名称" align="center" prop="deviceName" />
|
||||
<el-table-column prop="customerName" label="所属客户" />
|
||||
<el-table-column prop="devicePic" label="设备图片">
|
||||
<template #default="scope">
|
||||
<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="typeName" label="设备类型" />
|
||||
<el-table-column prop="bindingStatus" label="绑定状态">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.bindingStatus === 1 ? 'success' : 'info'">
|
||||
{{ scope.row.bindingStatus === 1 ? '已绑定' : '未绑定' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceStatus" label="设备状态">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.deviceStatus == 1 ? 'success' : 'danger'">
|
||||
{{ scope.row.deviceStatus == 1 ? '正常' : '失效' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
<el-table-column prop="createTime" label="创建日期" width="160" />
|
||||
<el-table-column prop="createByName" label="创建人" />
|
||||
|
||||
<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-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-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-button link type="primary" icon="UploadFilled" @click="handleWithdraw(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
<el-button v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0"
|
||||
@click="handleUnbind(scope.row)">解绑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||||
:total="total" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="30%" append-to-body
|
||||
@close="closeDialog">
|
||||
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备名称" prop="deviceName">
|
||||
<el-input v-model="form.deviceName" placeholder="请输入设备名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备类型" prop="deviceType">
|
||||
<el-select v-model="form.deviceType" placeholder="设备类型" @change="id => handleDeviceTypeChange(id)"
|
||||
:disabled="form.id != ''">
|
||||
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName"
|
||||
:value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="showMacField">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备MAC" prop="deviceMac">
|
||||
<el-input v-model="form.deviceMac" placeholder="请输入设备MAC" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="showImeiField">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备IMEI" prop="deviceImei">
|
||||
<el-input v-model="form.deviceImei" placeholder="请输入设备IMEI" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="设备图片" prop="image">
|
||||
<el-upload action="#" list-type="picture-card" :before-upload="beforeUpload" :on-change="fileUploadChange"
|
||||
:http-request="httpRequestImg" :file-list="fileList" :limit="1">
|
||||
<i class="el-icon-plus"></i>
|
||||
<template v-if="form.image && typeof form.image === 'string'">
|
||||
<img :src="form.image" class="avatar" style="width:100px; height:100px;" />
|
||||
</template>
|
||||
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm" :loading="loadingIng">确 定</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 分配客户弹窗 -->
|
||||
<el-dialog v-model="assignDialogVisible" title="分配客户" width="400px">
|
||||
<el-form>
|
||||
<el-form-item label="选择客户">
|
||||
<el-select v-model="assignCustomerId" placeholder="请选择客户" style="width: 100%">
|
||||
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName"
|
||||
:value="item.customerId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="assignDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleAssignConfirm" :loading="loadingIng">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 导入设备数据弹窗 -->
|
||||
<el-dialog v-model="importDialogVisible" title="导入设备数据" width="500px">
|
||||
<div style="margin-bottom: 16px;">
|
||||
<p>请按照模板文件的格式准备需要导入的数据。</p>
|
||||
<p>模板文件中的表头请勿修改,数据请从第二行开始填写。</p>
|
||||
<el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载模板文件</el-button>
|
||||
</div>
|
||||
<el-upload ref="importUpload" :action="api.devicDeimport()" :headers="head_upload()" :show-file-list="false"
|
||||
:before-upload="beforeImportUpload" :on-success="handleImportSuccess" :on-error="handleImportError" :limit="1"
|
||||
accept=".xlsx,.xls">
|
||||
<el-button type="success">选择文件开始导入</el-button>
|
||||
<div v-if="!importResult.isShow" slot="tip" class="el-upload__tip">
|
||||
<div style="color:#409EFF">只能上传模板excel文件</div>
|
||||
</div>
|
||||
<div v-if="importResult.isShow" slot="tip" class="el-upload__tip">
|
||||
<span style="color:#409EFF">批量导入完成,共检测到 <span style="color:#E6A23C">{{ importResult.total }}</span>
|
||||
条数据,导入成功 <span style="color:#67C23A">{{ importResult.succeed }}</span> 条,失败 <span style="color:red">{{
|
||||
importResult.errorSun }}</span> 条。</span>
|
||||
<p v-if="importResult.errorSun > 0" style="padding:10px;"><a :href="importResult.link">>>>
|
||||
上传失败明细下载 <i class="el-icon-download" /></a></p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="importDialogVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 批量分配客户弹窗 -->
|
||||
<el-dialog v-model="batchAssignDialogVisible" title="批量分配客户" width="400px">
|
||||
<el-form>
|
||||
<el-form-item label="选择客户">
|
||||
<el-select v-model="batchAssignCustomerId" placeholder="请选择客户" style="width: 100%">
|
||||
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName"
|
||||
:value="item.customerId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="batchAssignDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleBatchAssignConfirm">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="User" lang="ts">
|
||||
import api from '@/api/equipmentManagement/device/index';
|
||||
import { deviceForm, deviceQuery, deviceVO } from '@/api/equipmentManagement/device/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const deviceDist = ref<deviceVO[]>();
|
||||
import { to } from 'await-to-js';
|
||||
import request from "@/utils/request";
|
||||
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 single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const initPassword = ref<string>('');
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const userFormRef = ref<ElFormInstance>();
|
||||
const formDialogRef = ref<ElDialogInstance>();
|
||||
const deviceTypeOptions = ref([]); //设备类型
|
||||
const fileList = ref()
|
||||
const communicationModeInfo = ref<any>(null);
|
||||
const showMacField = ref(false); //MAC地址
|
||||
const showImeiField = ref(false); //mei地址
|
||||
const assignDialogVisible = ref(false); //分配客户
|
||||
const importDialogVisible = ref(false);//批量导入
|
||||
const batchAssignDialogVisible = ref(false) //批量分配客户
|
||||
const loadingIng = ref(false)
|
||||
const assignCustomerId = ref(); //分配客户id
|
||||
const batchAssignCustomerId = ref() //批量分配客户id
|
||||
const customerList = ref()
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: deviceForm = {
|
||||
deviceName: '',
|
||||
deviceMac: '',
|
||||
deviceImei: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
deviceType: "",
|
||||
image: ''
|
||||
};
|
||||
|
||||
const initData: PageData<deviceForm, deviceQuery> = {
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deviceName: '',
|
||||
deviceMac: '',
|
||||
deviceImei: '',
|
||||
deviceType: '',
|
||||
deviceStatus: '',
|
||||
|
||||
},
|
||||
rules: {
|
||||
deviceName: [
|
||||
{ required: true, message: '请输入设备名称', trigger: 'blur' },
|
||||
],
|
||||
deviceType: [
|
||||
{ required: true, message: '请选择设备类型', trigger: 'blur' },
|
||||
],
|
||||
}
|
||||
};
|
||||
const data = reactive<PageData<deviceVO, deviceQuery>>(initData);
|
||||
const { queryParams, form, rules } = toRefs<PageData<deviceVO, deviceQuery>>(data);
|
||||
/** 查询设备列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await api.deviceList(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||
loading.value = false;
|
||||
deviceDist.value = res.rows;
|
||||
total.value = res.total;
|
||||
};
|
||||
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
dateRange.value = ['', ''];
|
||||
handleQuery()
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
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);
|
||||
if (!err) {
|
||||
await api.deleteDevice(arrey);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 单行删除逻辑
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?') as any);
|
||||
if (!err) {
|
||||
await api.deleteDevice([row.id]);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
};
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'/api/device/download',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`${new Date().getTime()}.xlsx`,
|
||||
'get'
|
||||
);
|
||||
};
|
||||
// 解绑
|
||||
const handleUnbind = (row) => {
|
||||
proxy?.$modal.confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
api.deviceUnbind(row).then(res => {
|
||||
if (res.code === 0) {
|
||||
proxy?.$modal.msgSuccess('解绑成功')
|
||||
getList(); // 初始化列表数据
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '解绑失败')
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
};
|
||||
// 撤回
|
||||
const handleWithdraw = (row: any) => {
|
||||
proxy?.$modal.confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
api.withdrawDevice([row.id]).then(res => {
|
||||
if (res.code === 0) {
|
||||
proxy?.$modal.msgSuccess('撤回成功')
|
||||
getList(); // 初始化列表数据
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '撤回失败')
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
proxy?.$modal.msgError('已取消撤回')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/** 选择条数 */
|
||||
const handleSelectionChange = (selection: deviceVO[]) => {
|
||||
ids.value = selection.map((item) => item);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
|
||||
/** 重置操作表单 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
userFormRef.value?.resetFields();
|
||||
fileList.value = []
|
||||
};
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
dialog.visible = false;
|
||||
reset();
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = async () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '新增设备';
|
||||
form.value.password = initPassword.value.toString();
|
||||
// 新增时默认不显示
|
||||
showMacField.value = false;
|
||||
showImeiField.value = false;
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: deviceForm) => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改设备';
|
||||
try {
|
||||
if (row) {
|
||||
Object.assign(form.value, row);
|
||||
form.value.image = row.devicePic
|
||||
// 编辑时根据已有值显示字段
|
||||
showMacField.value = !!row.deviceMac;
|
||||
showImeiField.value = !!row.deviceImei;
|
||||
} else {
|
||||
const customerId = ids.value[0];
|
||||
Object.assign(form.value, customerId);
|
||||
form.value.image = customerId.devicePic //图片回显
|
||||
// 编辑时根据已有值显示字段
|
||||
showMacField.value = !!customerId.deviceMac;
|
||||
showImeiField.value = !!customerId.deviceImei;
|
||||
}
|
||||
// 加载设备类型对应的通讯方式
|
||||
if (form.value.deviceType) {
|
||||
await handleDeviceTypeChange(form.value.deviceType);
|
||||
}
|
||||
} catch (error) {
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
// 设备类型触发事件
|
||||
const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
|
||||
// 重置规则和显示状态
|
||||
rules.value.deviceMac = [];
|
||||
rules.value.deviceImei = [];
|
||||
showMacField.value = false;
|
||||
showImeiField.value = false;
|
||||
communicationModeInfo.value = null;
|
||||
|
||||
// 编辑时如果有值,根据已有值确定显示哪个字段
|
||||
if (form.value.id) {
|
||||
if (form.value.deviceMac) {
|
||||
showMacField.value = true;
|
||||
rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }];
|
||||
} else if (form.value.deviceImei) {
|
||||
showImeiField.value = true;
|
||||
rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 新增或编辑时没有值,根据设备类型获取通讯方式
|
||||
try {
|
||||
userFormRef.value?.clearValidate(['deviceMac', 'deviceImei']);
|
||||
if (!deviceTypeId) {
|
||||
return;
|
||||
}
|
||||
const res = await api.getCommunicationMode({ id: deviceTypeId });
|
||||
if (res.code === 0 && res.data) {
|
||||
communicationModeInfo.value = res.data;
|
||||
// 根据通讯方式确定显示哪个字段
|
||||
if (res.data.communicationMode === '1') { // 蓝牙设备 - 显示MAC
|
||||
showMacField.value = true;
|
||||
showImeiField.value = false;
|
||||
rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }];
|
||||
form.value.deviceImei = ''; // 清空IMEI
|
||||
} else if (res.data.communicationMode === '0') { // 4G设备 - 显示IMEI
|
||||
showMacField.value = false;
|
||||
showImeiField.value = true;
|
||||
rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }];
|
||||
form.value.deviceMac = ''; // 清空MAC
|
||||
}
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '获取通讯方式失败');
|
||||
}
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('获取通讯方式失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 覆盖默认的上传行为,可以自定义上传的实现
|
||||
const httpRequestImg = (parm) => { };
|
||||
const beforeUpload = (file) => {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
|
||||
if (!isJPG) {
|
||||
ElMessage.warning("请上传jpg、png格式,大小不超过2M的照片");
|
||||
return false;
|
||||
}
|
||||
if (!isLt2M) {
|
||||
ElMessage.warning("大小不超过2M的照片片");
|
||||
return false;
|
||||
}
|
||||
return isJPG && isLt2M;
|
||||
};
|
||||
// 文件上传状态改变时触发
|
||||
const fileUploadChange = (files, fileList) => {
|
||||
console.log(fileList, '5555');
|
||||
if (fileList.length > 0) {
|
||||
form.value.image = fileList[0].raw; // 正确获取File对象
|
||||
// 调试:检查是否是真正的 File 对象
|
||||
console.log('File对象验证:', form.value.image);
|
||||
} else {
|
||||
form.value.image = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = async () => {
|
||||
try {
|
||||
const valid = await userFormRef.value?.validate();
|
||||
if (!valid) return;
|
||||
loadingIng.value = true;
|
||||
const formData = new FormData();
|
||||
// 处理图片字段
|
||||
if (form.value.image instanceof File) {
|
||||
formData.append('file', form.value.image);
|
||||
} else if (form.value.image && typeof form.value.image === 'string') {
|
||||
// 如果是URL且需要转换为二进制
|
||||
const blob = await urlToBlob(form.value.image);
|
||||
formData.append('file', blob, 'image.jpg'); // 添加文件名
|
||||
}
|
||||
// 添加其他必要字段
|
||||
const fields = ['id', 'deviceName', 'deviceType', 'remark'];
|
||||
fields.forEach(key => {
|
||||
if (form.value[key] !== undefined && form.value[key] !== null) {
|
||||
formData.append(key, String(form.value[key])); // 确保所有值都转为字符串
|
||||
}
|
||||
});
|
||||
// 根据通讯方式,有条件地添加deviceMac或deviceImei
|
||||
if (form.value.deviceMac) {
|
||||
formData.append('deviceMac', form.value.deviceMac);
|
||||
}
|
||||
if (form.value.deviceImei) {
|
||||
formData.append('deviceImei', form.value.deviceImei);
|
||||
}
|
||||
// 根据操作类型设置URL和方法
|
||||
const isAdd = !form.value.id; // 注意这里逻辑反了,应该是没有id时是新增
|
||||
const res = await request({
|
||||
url: isAdd ? '/api/device/add' : '/api/device/update',
|
||||
method: isAdd ? 'post' : 'put',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
if (res.code == 0) {
|
||||
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
loadingIng.value = false;
|
||||
await getList();
|
||||
} else {
|
||||
proxy?.$modal.msgWarning(res.msg)
|
||||
loadingIng.value = false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
loadingIng.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// URL转Blob的方法函数
|
||||
const urlToBlob = async (url: string): Promise<Blob> => {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('图片加载失败');
|
||||
return await response.blob();
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭用户弹窗
|
||||
*/
|
||||
const closeDialog = () => {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
userFormRef.value?.resetFields();
|
||||
userFormRef.value?.clearValidate();
|
||||
form.value.customerId = undefined;
|
||||
};
|
||||
// 设备类型
|
||||
const getDeviceType = () => {
|
||||
api.deviceTypeAll().then(res => {
|
||||
if (res.code == 0) {
|
||||
deviceTypeOptions.value = res.data
|
||||
}
|
||||
}).catch(err => {
|
||||
|
||||
})
|
||||
};
|
||||
// 客户下拉框
|
||||
const getAllCustomerAll = () => {
|
||||
api.userAllCustomerAll().then(res => {
|
||||
if (res.code == 0) {
|
||||
customerList.value = res.data
|
||||
}
|
||||
})
|
||||
};
|
||||
// 分配客户
|
||||
const assignRow = ref()
|
||||
const handleAssign = (row: any) => {
|
||||
getAllCustomerAll()
|
||||
assignDialogVisible.value = true
|
||||
assignRow.value = row
|
||||
assignCustomerId.value = row.customerId
|
||||
}
|
||||
const handleAssignConfirm = () => {
|
||||
if (!assignCustomerId.value) {
|
||||
return proxy?.$modal.msgError('请选择客户')
|
||||
}
|
||||
loadingIng.value = true;
|
||||
// 这里调用分配API
|
||||
let data = {
|
||||
customerId: assignCustomerId.value,
|
||||
deviceIds: [assignRow.value.id]
|
||||
}
|
||||
api.deviceAssignCustomer(data).then((res) => {
|
||||
if (res.code == 0) {
|
||||
loadingIng.value = false;
|
||||
const customer = customerList.value.find(c => c.id === assignCustomerId.value)
|
||||
const customerName = customer ? customer.nickName : `ID: ${assignCustomerId.value}`
|
||||
getList();
|
||||
assignDialogVisible.value = false
|
||||
return proxy?.$modal.msgSuccess(`设备已分配给客户: ${customerName}`)
|
||||
|
||||
} else {
|
||||
loadingIng.value = false;
|
||||
}
|
||||
})
|
||||
};
|
||||
const importUpload = ref()
|
||||
const importResult = ref()
|
||||
const handleBatchImport = () => {
|
||||
importDialogVisible.value = true
|
||||
importResult.value = {
|
||||
isShow: false,
|
||||
total: 0,
|
||||
succeed: 0,
|
||||
errorSun: 0,
|
||||
link: ''
|
||||
}
|
||||
nextTick(() => {
|
||||
if (importUpload.value) {
|
||||
importUpload.value.clearFiles()
|
||||
}
|
||||
})
|
||||
};
|
||||
const downloadTemplate = () => {
|
||||
// 这里可用 window.open 或 a 标签下载模板
|
||||
const link = document.createElement('a');
|
||||
link.href = 'http://fuyuanshen.com:81/images/excel/equipmenttemplate.xlsx';
|
||||
link.download = '设备数据导入模板.xlsx'; // 可选:指定下载文件名
|
||||
link.style.display = 'none'; // 隐藏标签
|
||||
document.body.appendChild(link);
|
||||
link.click(); // 触发下载
|
||||
document.body.removeChild(link); // 移除标签
|
||||
};
|
||||
const beforeImportUpload = (file: any) => {
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
proxy?.$modal.msgError('上传文件大小不能超过 5MB!')
|
||||
}
|
||||
return isLt5M
|
||||
};
|
||||
|
||||
//添加tokenf方法head_upload 直接返回 getBearerToken()
|
||||
const head_upload = () => getBearerToken();
|
||||
const handleImportSuccess = (response: any) => {
|
||||
if (response.code === 0) {
|
||||
importResult.value.isShow = true
|
||||
if (response.data) {
|
||||
importResult.value.succeed = response.data.successCount || 0
|
||||
importResult.value.errorSun = response.data.failureCount || 0
|
||||
importResult.value.total = importResult.value.succeed + importResult.value.errorSun
|
||||
importResult.value.link = response.data.errorExcelUrl || ''
|
||||
}
|
||||
getList(); // 初始化列表数据
|
||||
} else {
|
||||
proxy?.$modal.msgError(response.msg || '导入失败')
|
||||
}
|
||||
};
|
||||
const handleImportError = () => {
|
||||
proxy?.$modal.msgError('导入失败')
|
||||
};
|
||||
// 批量分配客户
|
||||
const handleBatchAssign = () => {
|
||||
batchAssignDialogVisible.value = true
|
||||
getAllCustomerAll()
|
||||
};
|
||||
// 批量分配客户确定
|
||||
const handleBatchAssignConfirm = () => {
|
||||
if (!batchAssignCustomerId.value) {
|
||||
return proxy?.$modal.msgError('请选择客户')
|
||||
}
|
||||
// 这里可以调用批量分配API,传递 crud.selections 和 batchAssignCustomerId
|
||||
// 提取选中设备的 ID 数组
|
||||
const selectedIds = ids.value.map((item) => item.id)
|
||||
// 构造请求数据
|
||||
const data = {
|
||||
customerId: batchAssignCustomerId.value, // 目标客户ID
|
||||
deviceIds: selectedIds // 选中的设备ID数组
|
||||
}
|
||||
api.deviceAssignCustomer(data).then((res) => {
|
||||
if (res.code == 0) {
|
||||
batchAssignDialogVisible.value = false
|
||||
getList();
|
||||
return proxy?.$modal.msgSuccess(`分配成功`)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
watch(() => form.value.deviceType, (newVal) => {
|
||||
if (dialog.title === '新增设备') { // Only for add form
|
||||
handleDeviceTypeChange(newVal);
|
||||
}
|
||||
});
|
||||
onMounted(() => {
|
||||
getList(); // 初始化列表数据
|
||||
getDeviceType()
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep .el-upload--picture-card {
|
||||
width: 100px !important;
|
||||
height: 100px !important;
|
||||
border: 1px solid #cccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
:deep .el-upload.el-upload--text {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep .el-upload-list--picture-card .el-upload-list__item {
|
||||
width: 100px !important;
|
||||
height: 100px !important;
|
||||
}
|
||||
|
||||
:deep .el-upload-list__item-thumbnail {
|
||||
width: 100px !important;
|
||||
height: 100px !important;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
@ -2,92 +2,8 @@
|
||||
<div class="app-container home">
|
||||
<el-row :gutter="20">
|
||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
||||
<h2>RuoYi-Vue-Plus多租户管理系统</h2>
|
||||
<p>
|
||||
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
|
||||
<br />
|
||||
* 前端开发框架 Vue3、TS、Element Plus<br />
|
||||
* 后端开发框架 Spring Boot<br />
|
||||
* 容器框架 Undertow 基于 Netty 的高性能容器<br />
|
||||
* 权限认证框架 Sa-Token 支持多终端认证系统<br />
|
||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
||||
* 缓存数据库 Redis 适配 6.X 最低 4.X<br />
|
||||
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br />
|
||||
* 数据库框架 p6spy 更强劲的 SQL 分析<br />
|
||||
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br />
|
||||
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br />
|
||||
* Redis客户端 Redisson 性能强劲、API丰富<br />
|
||||
* 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br />
|
||||
* 分布式锁 Lock4j 注解锁、工具锁 多种多样<br />
|
||||
* 分布式幂等 Lock4j 基于分布式锁实现<br />
|
||||
* 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br />
|
||||
* 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br />
|
||||
* 文件存储 Minio 本地存储<br />
|
||||
* 文件存储 七牛、阿里、腾讯 云存储<br />
|
||||
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
|
||||
* 校验框架 Validation 增强接口安全性 严谨性<br />
|
||||
* Excel框架 FastExcel(原Alibaba EasyExcel) 性能优异 扩展性强<br />
|
||||
* 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br />
|
||||
* 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br />
|
||||
* 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br />
|
||||
* 部署方式 Docker 容器编排 一键部署业务集群<br />
|
||||
* 国际化 SpringMessage Spring标准国际化方案<br />
|
||||
</p>
|
||||
<p><b>当前版本:</b> <span>v5.4.0</span></p>
|
||||
<p>
|
||||
<el-tag type="danger">¥免费开源</el-tag>
|
||||
</p>
|
||||
<p>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
|
||||
>更新日志</el-button
|
||||
>
|
||||
</p>
|
||||
</el-col>
|
||||
|
||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
||||
<h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2>
|
||||
<p>
|
||||
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
|
||||
<br />
|
||||
* 前端开发框架 Vue3、TS、Element UI<br />
|
||||
* 后端开发框架 Spring Boot<br />
|
||||
* 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br />
|
||||
* 容器框架 Undertow 基于 XNIO 的高性能容器<br />
|
||||
* 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br />
|
||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
||||
* 关系数据库 Oracle 适配 11g 12c<br />
|
||||
* 关系数据库 PostgreSQL 适配 13 14<br />
|
||||
* 关系数据库 SQLServer 适配 2017 2019<br />
|
||||
* 缓存数据库 Redis 适配 6.X 最低 5.X<br />
|
||||
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
||||
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
||||
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br />
|
||||
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
|
||||
* RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br />
|
||||
* 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br />
|
||||
* 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br />
|
||||
* 分布式消息队列 Apache Kafka 高性能高速度<br />
|
||||
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br />
|
||||
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br />
|
||||
* 分布式搜索引擎 ElasticSearch 业界知名<br />
|
||||
* 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br />
|
||||
* 分布式日志中心 ELK 业界成熟解决方案<br />
|
||||
* 分布式监控 Prometheus、Grafana 全方位性能监控<br />
|
||||
* 其余与 Vue 版本一致<br />
|
||||
</p>
|
||||
<p><b>当前版本:</b> <span>v2.4.0</span></p>
|
||||
<p>
|
||||
<el-tag type="danger">¥免费开源</el-tag>
|
||||
</p>
|
||||
<p>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')"
|
||||
>更新日志</el-button
|
||||
>
|
||||
</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider />
|
||||
@ -102,64 +18,6 @@ const goTarget = (url: string) => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
blockquote {
|
||||
padding: 10px 20px;
|
||||
margin: 0 0 20px;
|
||||
font-size: 17.5px;
|
||||
border-left: 5px solid #eee;
|
||||
}
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.col-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
color: #676a6c;
|
||||
overflow-x: hidden;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 10px;
|
||||
font-size: 26px;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 10px;
|
||||
|
||||
b {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.update-log {
|
||||
ol {
|
||||
display: block;
|
||||
list-style-type: decimal;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
padding-inline-start: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -6,44 +6,35 @@
|
||||
<lang-select />
|
||||
</div>
|
||||
<el-form-item v-if="tenantEnabled" prop="tenantId">
|
||||
<el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
|
||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
|
||||
<el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')"
|
||||
style="width: 100%">
|
||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName"
|
||||
:value="item.tenantId"></el-option>
|
||||
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
|
||||
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off"
|
||||
:placeholder="proxy.$t('login.username')">
|
||||
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
:placeholder="proxy.$t('login.password')"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off"
|
||||
:placeholder="proxy.$t('login.password')" @keyup.enter="handleLogin">
|
||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="captchaEnabled" prop="code">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
:placeholder="proxy.$t('login.code')"
|
||||
style="width: 63%"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<el-input v-model="loginForm.code" size="large" auto-complete="off" :placeholder="proxy.$t('login.code')"
|
||||
style="width: 63%" @keyup.enter="handleLogin">
|
||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" class="login-code-img" @click="getCode" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
||||
<!-- <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
||||
<el-form-item style="float: right">
|
||||
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
|
||||
<svg-icon icon-class="wechat" />
|
||||
@ -60,7 +51,7 @@
|
||||
<el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">
|
||||
<svg-icon icon-class="github" />
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item style="width: 100%">
|
||||
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
|
||||
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
|
||||
@ -71,10 +62,6 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>Copyright © 2018-2025 疯狂的狮子Li All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -261,8 +248,10 @@ onMounted(() => {
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
z-index: 1;
|
||||
|
||||
.el-input {
|
||||
height: 40px;
|
||||
|
||||
input {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
Reference in New Issue
Block a user