Compare commits

...

2 Commits

Author SHA1 Message Date
dyf
15719b4a27 Merge pull request '设备类型添加图片' (#27) from liubiao/dyf-vue-ui:main into main
Reviewed-on: #27
2026-01-12 11:20:17 +08:00
a1b3d03a0c 设备类型添加图片 2026-01-12 10:22:41 +08:00
6 changed files with 1316 additions and 65 deletions

View File

@ -6,8 +6,8 @@ VITE_APP_ENV = 'development'
# 开发环境
# VITE_APP_BASE_API = 'http://139.224.253.23:8000'
VITE_APP_BASE_API = 'https://www.cnxhyc.com/jq'
#VITE_APP_BASE_API = 'http://192.168.110.56:8000'
# VITE_APP_BASE_API = 'https://www.cnxhyc.com/jq'
VITE_APP_BASE_API = 'http://192.168.110.57:8000'
#代永飞接口
# VITE_APP_BASE_API = 'http://457102h2d6.qicp.vip:24689'

View File

@ -8,7 +8,7 @@ VITE_APP_ENV = 'https://www.cnxhyc.com'
# VITE_APP_ENV = 'https://fuyuanshen.com/backend-fys'
# 应用访问路径 晶全1
VITE_APP_CONTEXT_PATH = '/jingquan/'
VITE_APP_CONTEXT_PATH = '/'
# 高德地图Key
VITE_AMAP_KEY='84a12a692ae378effdf741e16d584cd3'
@ -23,7 +23,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
# 生产环境 晶全3 代理访问
VITE_APP_BASE_API = '/jq'
VITE_APP_BASE_API = 'https://www.cnxhyc.com/jq'
# 生产环境 富源晟3
#VITE_APP_BASE_API = '/backend-fys'

View File

@ -6,7 +6,12 @@
<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" />
<script src="https://webapi.amap.com/maps?v=2.0&key=90bc158992feb8ccd0145e168cab1307&plugin=AMap.CircleEditor"></script>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: "4239900f4fb7b2569df651ac814a28de",
};
</script>
<script src="https://webapi.amap.com/maps?v=2.0&key=78c36a1e251a95f1a21a9e5ea7a1331c&plugin=AMap.CircleEditor"></script>
<title>物联网管理平台</title>
<!--[if lt IE 11
]><script>

View File

@ -17,7 +17,10 @@ export const addDeviceType = (data: any): AxiosPromise<deviceTypeVO[]> => {
return request({
url: '/api/deviceType/add',
method: 'post',
data: data
data: data,
headers:{
'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
}
});
};
@ -26,6 +29,9 @@ export const updateDeviceType = (data: any): AxiosPromise<deviceTypeVO[]> => {
return request({
url: '/api/deviceType/update',
method: 'put',
headers:{
'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
},
data
})
}
@ -34,6 +40,7 @@ export const deleteDeviceType = (ids: any): AxiosPromise<deviceTypeVO[]> => {
return request({
url: '/api/deviceType/delete',
method: 'delete',
data: ids
})
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<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">
@ -24,14 +23,10 @@
<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-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-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>
@ -42,8 +37,7 @@
<el-table-column label="型号名称" align="center" prop="typeName" />
<el-table-column label="类型code" align="center" prop="appModelDictionary">
<template #default="scope">
{{appmodelDictionaryOptions.find(item => item.dictValue === String(scope.row.appModelDictionary))?.dictLabel
}}
{{ appmodelDictionaryOptions.find((item) => item.dictValue === String(scope.row.appModelDictionary))?.dictLabel }}
</template>
</el-table-column>
<el-table-column label="是否支持蓝牙" align="center" prop="isSupportBle">
@ -81,14 +75,11 @@
</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" />
<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-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">
@ -101,14 +92,12 @@
<el-col :span="24">
<el-form-item label="路由跳转" prop="appModelDictionary">
<el-select v-model="form.appModelDictionary" placeholder="请选择" @change="handlePcRouteChange">
<el-option v-for="item in appmodelDictionaryOptions" :key="item.dictCode" :label="item.dictLabel"
:value="item.dictValue" />
<el-option v-for="item in appmodelDictionaryOptions" :key="item.dictCode" :label="item.dictLabel" :value="item.dictValue" />
</el-select>
</el-form-item>
<el-form-item label="pc路由跳转" prop="pcModelDictionary" style="display: none;">
<el-form-item label="pc路由跳转" prop="pcModelDictionary" style="display: none">
<el-select v-model="form.pcModelDictionary" placeholder="请选择">
<el-option v-for="item in pcmodelDictionaryOptions" :key="item.dictCode" :label="item.dictLabel"
:value="item.dictValue" />
<el-option v-for="item in pcmodelDictionaryOptions" :key="item.dictCode" :label="item.dictLabel" :value="item.dictValue" />
</el-select>
</el-form-item>
</el-col>
@ -147,6 +136,22 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="设备图片" prop="devicePic">
<input type="file" id="fileTypeImg" accept="image/*" style="display: none" />
<div class="devicePic typeImgContent" v-if="form.devicePic">
<img class="img" :src="form.devicePic" />
<div class="mask center" @click.stop="DropImg(form)">
<el-icon class="avatar-uploader-icon"><Delete /></el-icon>
</div>
</div>
<div class="devicePic typeImgAdd center" v-else @click.stop="AddImg(form)">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@ -164,7 +169,23 @@ import { deviceTypeQuery } from '@/api/equipmentManagement/deviceType/types';
import { getDicts } from '@/api/system/dict/data';
import { to } from 'await-to-js';
import { ComponentInternalInstance, getCurrentInstance, onMounted, reactive, ref, toRefs } from 'vue';
import { ElDialog, ElForm, ElFormItem, ElInput, ElRow, ElCol, ElButton, ElCard, ElSelect, ElOption, ElDatePicker, ElTable, ElTableColumn, ElTooltip, ElSwitch } from 'element-plus';
import {
ElDialog,
ElForm,
ElFormItem,
ElInput,
ElRow,
ElCol,
ElButton,
ElCard,
ElSelect,
ElOption,
ElDatePicker,
ElTable,
ElTableColumn,
ElTooltip,
ElSwitch
} from 'element-plus';
interface deviceTypeVO {
id: string | number;
typeName: string;
@ -176,9 +197,9 @@ interface deviceTypeVO {
communicationMode: number;
createTime: string;
createByName: string;
devicePic: string;
}
interface DeviceTypeForm extends deviceTypeVO {
}
interface DeviceTypeForm extends deviceTypeVO {}
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const deviceTypeList = ref<deviceTypeVO[]>();
const loading = ref(true);
@ -190,9 +211,11 @@ const total = ref(0);
const queryFormRef = ref<InstanceType<typeof ElForm>>();
const userFormRef = ref<InstanceType<typeof ElForm>>();
const formDialogRef = ref<InstanceType<typeof ElDialog>>();
const loadingIng = ref(false)
const loadingIng = ref(false);
const appmodelDictionaryOptions = ref<any[]>([]);
const pcmodelDictionaryOptions = ref<any[]>([]);
var fileC = null;
var uploadFile=false;
const dialog = reactive<DialogOption>({
visible: false,
title: ''
@ -207,7 +230,7 @@ const initFormData: DeviceTypeForm = {
communicationMode: 0,
id: '',
createTime: '',
createByName: '',
createByName: ''
};
const initData = {
@ -215,28 +238,20 @@ const initData = {
queryParams: {
pageNum: 1,
pageSize: 10,
typeName: '',
typeName: ''
},
rules: {
typeName: [
{ required: true, message: '请输入设备类型名称', trigger: 'blur' },
],
appModelDictionary: [
{ required: true, message: '请选择类型code', trigger: 'blur' },
],
locateMode: [
{ required: true, message: '请选择定位方式', trigger: 'blur' },
],
communicationMode: [
{ required: true, message: '请选择通讯方式', trigger: 'blur' },
],
typeName: [{ required: true, message: '请输入设备类型名称', trigger: 'blur' }],
appModelDictionary: [{ required: true, message: '请选择类型code', trigger: 'blur' }],
locateMode: [{ required: true, message: '请选择定位方式', trigger: 'blur' }],
communicationMode: [{ required: true, message: '请选择通讯方式', trigger: 'blur' }]
}
};
const data = reactive<{
form: DeviceTypeForm,
queryParams: deviceTypeQuery,
rules: any
form: DeviceTypeForm;
queryParams: deviceTypeQuery;
rules: any;
}>(initData);
const { queryParams, form, rules } = toRefs(data);
@ -252,11 +267,11 @@ const getList = async () => {
const getDict = async () => {
const res = await getDicts('app_model_dictionary');
appmodelDictionaryOptions.value = res.data;
}
};
const pcgetDict = async () => {
const res = await getDicts('pc_model_dictionary');
pcmodelDictionaryOptions.value = res.data;
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
@ -270,13 +285,9 @@ const resetQuery = () => {
};
// PC路由变化时同步对应APP路由
const handlePcRouteChange = (pcDictValue: string) => {
const selectedPcItem = appmodelDictionaryOptions.value.find(
item => item.dictValue === pcDictValue
);
const selectedPcItem = appmodelDictionaryOptions.value.find((item) => item.dictValue === pcDictValue);
if (!selectedPcItem) return;
const matchedAppItem = pcmodelDictionaryOptions.value.find(
item => item.dictLabel === selectedPcItem.dictLabel
);
const matchedAppItem = pcmodelDictionaryOptions.value.find((item) => item.dictLabel === selectedPcItem.dictLabel);
if (matchedAppItem) {
form.value.pcModelDictionary = matchedAppItem.dictValue;
} else {
@ -287,13 +298,15 @@ const handlePcRouteChange = (pcDictValue: string) => {
/** 删除按钮操作 */
const handleDelete = async (row?: deviceTypeVO) => {
const deviceTypeIds = row ? [row.id] : ids.value.map(item => item.id);
const typeNames = row ? row.typeName : ids.value.map(item => item.typeName).join(',');
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + typeNames + '"的数据项?', '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}) as any);
const deviceTypeIds = row ? [row.id] : ids.value.map((item) => item.id);
const typeNames = row ? row.typeName : ids.value.map((item) => item.typeName).join(',');
const [err] = await to(
proxy?.$modal.confirm('是否确认删除"' + typeNames + '"的数据项?', '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}) as any
);
if (!err) {
await api.deleteDeviceType(deviceTypeIds);
await getList();
@ -350,7 +363,7 @@ const submitForm = () => {
if (valid) {
loadingIng.value = true;
try {
const payload = {
let payload = {
...form.value,
appModelDictionary: form.value.appModelDictionary,
pcModelDictionary: form.value.pcModelDictionary,
@ -358,7 +371,27 @@ const submitForm = () => {
locateMode: Number(form.value.locateMode),
communicationMode: Number(form.value.communicationMode)
};
form.value.id ? await api.updateDeviceType(payload) : await api.addDeviceType(payload);
let formData = new FormData();
let keys=Object.keys(payload);
keys.forEach(key=>{
if(key!=='devicePic'){
if(payload[key]!==null && payload[key]!==undefined){
formData.append(key,payload[key]);
}
}
});
if(uploadFile && fileC && fileC.files.length){
formData.append('file',fileC.files[0]);
}
//如果要上传文件就用formData,不上传使用payload
form.value.id ? await api.updateDeviceType(formData) : await api.addDeviceType(formData);
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
@ -369,6 +402,25 @@ const submitForm = () => {
});
};
//删除图片
function DropImg(item) {
ElMessageBox.confirm('删除后不可恢复,您确认要删除吗?', '提醒', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
form.value.devicePic = null;
})
.catch(() => {});
}
//选择图片
function AddImg(item) {
uploadFile=false;
initControl();
fileC.click();
}
/**
* 关闭用户弹窗
*/
@ -386,9 +438,106 @@ const resetForm = () => {
form.value.id = '';
};
function initControl() {
if (fileC) {
fileC.value="";
return;
}
fileC = document.getElementById('fileTypeImg');
fileC.addEventListener('change', function () {
if (this.files.length) {
let file = this.files[0];
if (file.type.indexOf('image/') === 0) {
let reader = new FileReader();
reader.onload = function (e) {
uploadFile=true;
form.value.devicePic = e.target.result;
};
reader.onerror = function () {
console.log('读取文件失败!');
};
reader.readAsDataURL(file);
} else {
// form.value.devicePic = null;
}
} else {
// form.value.devicePic = null;
}
});
}
onMounted(() => {
getList(); // 初始化列表数据
getDict();
pcgetDict() //pc跳转
pcgetDict(); //pc跳转
});
</script>
<style>
.devicePic {
width: 120px;
height: 120px;
border-radius: 6px;
box-sizing: border-box;
overflow: hidden;
}
.typeImgContent {
background-color: #ffffff;
border: 1px solid rgb(220, 223, 230);
position: relative;
}
.typeImgContent .img {
width: 100%;
height: 100%;
object-fit: contain;
position: absolute;
top: 0px;
left: 0px;
z-index: 0;
padding: 10px;
}
.center {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: center;
}
.typeImgAdd {
background-color: #fafafa;
border: 1px dashed rgb(205, 208, 214);
font-size: 30px;
cursor: pointer;
}
.mask {
background-color: #1c1c1c80;
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
width: 0px;
height: 0px;
cursor: pointer;
overflow: hidden;
color: #ff0000;
font-size: 25px;
}
.typeImgContent:hover .mask {
width: 100%;
height: 100%;
}
</style>