设备功能调整

This commit is contained in:
zy 2025-11-15 19:25:50 +08:00
parent 3bb794c240
commit b1e3b2c232
33 changed files with 11154 additions and 11668 deletions

View File

@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = /
# 跨域代理,您可以配置多个 ,请注意,没有换行符
VITE_PROXY = [["/jeecgboot","http://192.168.2.110:9999"],["/upload","http://192.168.2.110:3300/upload"]]
#VITE_PROXY = [["/jeecgboot","https://zh.sxzooh.com"],["/upload","http://192.168.2.111:3300/upload"]]
#VITE_PROXY = [["/jeecgboot","https://fxnsp.sxcooh.com"],["/upload","http://192.168.2.111:3300/upload"]]
# 控制台不输出
VITE_DROP_CONSOLE = false
@ -16,7 +16,7 @@ VITE_GLOB_API_URL=/jeecgboot
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://192.168.2.110:9999
#VITE_GLOB_DOMAIN_URL=https://zh.sxzooh.com
#VITE_GLOB_DOMAIN_URL=https://fxnsp.sxcooh.com
# 接口前缀
VITE_GLOB_API_URL_PREFIX=

View File

@ -21,9 +21,9 @@ VITE_GLOB_API_URL=/lh-api
#后台接口全路径地址(必填)
#VITE_GLOB_DOMAIN_URL=http://192.168.2.111:9999/jeecg-boot
#测试环境
#VITE_GLOB_DOMAIN_URL=https://zy.sxzooh.com/zh-api
#VITE_GLOB_DOMAIN_URL=https://fxnsp.sxcooh.com/lh-api
#正式环境
VITE_GLOB_DOMAIN_URL=https://hjmyjc.sxcooh.com/zh-api
VITE_GLOB_DOMAIN_URL=http://fxnsp.zgzhny.com/lh-api
# 接口父路径前缀
VITE_GLOB_API_URL_PREFIX=

View File

@ -1,6 +1,10 @@
// @ts-check
const { defineConfig } = require('eslint-define-config');
module.exports = defineConfig({
"globals": {
"AMap": "true",
"AMapUI":"true",
},
root: true,
env: {
browser: true,

View File

@ -42,6 +42,8 @@
"@qiaoqiaoyun/drag-free": "^1.0.2",
"@vue/runtime-core": "^3.2.33",
"@vue/shared": "^3.2.33",
"@vuemap/vue-amap": "^2.1.17",
"@vuemap/vue-amap-loca": "^2.1.2",
"@vueuse/core": "^8.3.0",
"@vueuse/shared": "^8.3.0",
"@zxcvbn-ts/core": "^2.0.1",

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 KiB

After

Width:  |  Height:  |  Size: 231 KiB

View File

@ -1,5 +1,6 @@
import type { Component } from 'vue';
import type { ComponentType } from './types/index';
import MapSelect2 from '/@/components/MapSelect/MapSelect.vue';
/**
* Component list, register here to setting it in the form
@ -65,6 +66,7 @@ import JCusTag from './jeecg/components/JCusTag.vue'
const componentMap = new Map<ComponentType, Component>();
componentMap.set('MapSelect', MapSelect2);
componentMap.set('Time', Time);
componentMap.set('Input', Input);
componentMap.set('InputGroup', Input.Group);

View File

@ -152,4 +152,5 @@ export type ComponentType =
| 'linkRecordSelect'
| 'RangeTime'
| 'JCusTag'
| 'MapSelect'
| 'JRangeNumber';

View File

@ -0,0 +1,431 @@
<template>
<div>
<div class="selector-box">
<div>
<Icon icon="tdesign:location-1"></Icon>
<a-button :disabled="disabled" v-if="defaultPoint.length == 0" type="link" @click="showMapSelector">选择地址</a-button>
<a-button :disabled="disabled" v-else type="link" @click="showMapSelector">
经度{{ defaultPoint[0] }}
纬度{{ defaultPoint[1] }}
</a-button>
<!-- <a-input type="hidden" v-model:value="defaultPoint"/>-->
</div>
<!-- 清空坐标按钮 -->
<!-- <CompassOutlined v-if="defaultPoint.length != 0 && !disabled"/>-->
<!-- <i v-if="defaultPoint.length != 0 && !disabled" class="close-icon" type="iconai54" @click="clearLocation"/>-->
</div>
<BasicModal
:title="'选择地址'"
:canFullscreen="true"
@register="registerModal"
:width="1300"
:minHeight="600"
:showOkBtn="true"
:showCancelBtn="true"
destroyOnClose
@ok="save"
>
<!-- <a-modal title="选择地址" :visible="isShowMap" width="1300px" @ok="save" @cancel="closeModal2" :canFullscreen="true">-->
<!-- <a-row class="m-b-10">-->
<!-- <a-col :span="15">-->
<!-- </a-col>-->
<!-- <a-col :span="9">-->
<!-- </a-col>-->
<!-- </a-row>-->
<div class="search_box">
<div>
<a-input id="search" v-model:value="searchKey" placeholder="请输入地址" @input="doSearch" @blur="inputBlur" @focus="inputFocus"></a-input>
<div class="tip-box beauty-scroll" id="searchTip" v-show="resultShow"></div>
</div>
<a-button type="link" @click="resetMap">重置</a-button>
</div>
<div class="mapContainer m-b-10">
<el-amap v-if="isInit" :key="key" class="amap-box" :amap-manager="amapManager" :vid="'amap-vue' + key"
:zoom="zoom" :plugin="plugin" :center="center" :events="events" @init="init" @click="click">
<!-- 标记 -->
<el-amap-marker v-for="(marker, index) in markers" :position="marker"
:key="index"></el-amap-marker>
</el-amap>
<div class="hiddenGaode"></div>
</div>
<div class="footer">
<p>当前地址为{{ address }}</p>
<p>经纬度({{ lng }},{{ lat }})</p>
</div>
<!-- </a-modal>-->
</BasicModal>
</div>
</template>
<script lang="ts">
/**
* 高德地图选点组件
* 可搜索地址
* 2024.1.8 by.wgx
* 传入value,例如: :value="123.234234,543.44234234"
* */
import {defineComponent, ref, watch, nextTick} from 'vue';
import {ElAmap, useCitySearch, lazyAMapApiLoaderInstance} from '@vuemap/vue-amap';
import {BasicModal, useModal, useModalInner} from "/@/components/Modal";
// import VueAMap from '@vuemap/vue-amap';
export default defineComponent( {
name: 'MapSelect',
components: {BasicModal,},
props: {
//
value: {
type: String,
},
//
disabled: {
type: Boolean,
default: false
}
},
emits: ['options-change', 'change', 'update:value', 'input'],
setup(props, { emit }) {//debugger
// vue-amap : https://vue-amap.guyixi.cn/zh-cn/base/amap.html#%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7
const defaultPoint = ref ([]);
const key = ref ('id-'+ new Date().getTime());
const isShowMap = ref (false); //
const address = ref (''); //
const searchKey = ref<string>(''); //
const markers = ref ([defaultPoint.value]); //
const center = ref (defaultPoint.value); //
const zoom = ref (12); //
const lng = ref ( 0); //
const lat = ref (0); //
const isInit = ref(false);
const resultShow = ref(false);
let _this = this;
let amapManager = null;
var searchObj = null;
//
const events = ref({});
const [registerModal, {openModal, closeModal}] = useModal(async () => {
//
});
watch(() => props.value,
(n,o) => loadRoot(n,o),
{ deep: true, immediate: true }
);
function loadRoot(n, o){
// debugger
// console.log('', 'n - ' + n, 'o - ' + o);
if(n == '' || !n){//
n = '112.530016,37.810319';
}
if(n){
let split = n.value?n.value.split(','):n.split(',');
if(split && split.length > 1) {
defaultPoint.value = split;
}
}
}
//
const plugin = [{
//
pName: 'Geolocation',
events: {init: (o) => {},}
},{
//
pName: 'ToolBar',
events: {}
},{
//
pName: 'PlaceSearch',
events: {}
}
];
function initPoint(){
if(defaultPoint.value.length <= 0){// IP
useCitySearch().then(res => {
const {getLocalCity} = res;
getLocalCity().then(cityResult => {
// debugger
defaultPoint.value = cityResult.bounds.getCenter().toArray();
console.log('cityResult: ', cityResult);
isInit.value = true;
resetMap()
})
})
}else{
isInit.value = true;
resetMap()
}
}
//
function init(map){
//debugger
amapManager = map;
map.plugin(['AMap.Geocoder', 'AMap.PlaceSearch'], () => {
initSearch();
console.log('地图初始化完毕: ', map.getCenter())
});
//resetMap();
}
function doSearch(v){console.log(searchKey.value);if(searchObj){searchObj.search(v.target.value, function(r){});}}
function inputFocus(){resultShow.value = true;}
function inputBlur(){/*resultShow.value = false;*/}
//
function initSearch() {
const placeSearch = new AMap.PlaceSearch({
pageSize: 5, //
pageIndex: 1, //
citylimit: false, //
map: amapManager, //
panel: "searchTip", //
autoFitView: true, //使 Marker
});
placeSearch.on('listElementClick', function(res){
console.log(res)
})
placeSearch.on('selectChanged', function(res){
console.log(res)
resultShow.value = false;
})
placeSearch.on('markerClick', function(res){
console.log(res)
})
searchObj = placeSearch;
// AMapUI.loadUI(['misc/PoiPicker'], function (PoiPicker) {
// var poiPicker = new PoiPicker({
// input: 'search',
// placeSearchOptions: {
// map: amapManager,
// pageSize: 10
// },
// suggestContainer: 'searchTip',
// searchResultsContainer: 'searchTip'
// })
// // poi
// poiPicker.on('poiPicked', function (poiResult) {//debugger
// poiPicker.hideSearchResults();
// // poiPicker.clearSearchResults()
// let source = poiResult.source
// let poi = poiResult.item
// if (source !== 'search') {
// poiPicker.searchByKeyword(poi.name)
// } else {
// markers.value = []
// let lng2 = poi.location.lng
// let lat2 = poi.location.lat
// let address2 = poi.cityname + poi.adname + poi.name
// center.value = [lng2, lat2]
// markers.value.push([lng2, lat2])
// lng.value = lng2
// lat.value = lat2
// address.value = address2
// searchKey.value = address2
// }
// })
// })
}
//
function getAddress(lng, lat) {
// debugger
let geocoder = new AMap.Geocoder({
radius: 1000,
extensions: 'all',
});
return new Promise((resolve) => {
geocoder.getAddress([lng, lat], function (status, result) {
if (status === 'complete' && result.info === 'OK') {
if (result && result.regeocode) {
resolve(result.regeocode);
}
}
});
});
}
//
function resetMap() {
searchKey.value = '';
if(isInit.value){//debugger
let tempPos = defaultPoint.value;
center.value = tempPos;
markers.value = [tempPos];
lng.value = tempPos[0];
lat.value = tempPos[1];
searchKey.value = '';
//
setTimeout(() => {
getAddress(lng.value, lat.value).then(res => {
address.value = res.formattedAddress;
});
}, 1000);
}
}
//
function showMapSelector() {
isShowMap.value = true;
openModal();
nextTick(() => {
initPoint()
// resetMap();
})
}
//
function click(e) {
resultShow.value = false;
markers.value = [];
let {lng: lng2, lat: lat2} = e.lnglat;
lng.value = lng2;
lat.value = lat2;
center.value = [lng2, lat2];
markers.value.push([lng2, lat2]);
getAddress(lng2, lat2).then(res => {address.value = res.formattedAddress;});
}
//
function save() {
change({
address: address.value,
location: [lng.value, lat.value]
})
closeModal2();
}
//
function clearLocation() {
change({
address: '',
location: []
})
}
//
function change(res) {
emit('input', res.location[0] + ',' + res.location[1]);
emit('change', res.location[0] + ',' + res.location[1]);
emit('update:value', res.location[0] + ',' + res.location[1]);
// debugger
}
// 退
function closeModal2() {
searchKey.value = '';
isShowMap.value = false;
resultShow.value = false;
isInit.value = false;
key.value = 'id-'+ new Date().getTime();
closeModal();
}
return {
key,
isShowMap, //
address, //
searchKey, //
markers, //
center, //
zoom, //
lng, //
lat, //
amapManager, //
events, //
plugin, //
_this,
isInit,
defaultPoint,
resultShow,
showMapSelector,
clearLocation,
click,
closeModal2,
save,
init,
resetMap,
doSearch,
inputBlur,
inputFocus,
registerModal
}
}
});
</script>
<style scoped lang="less">
.search_box{
width: 100%;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
>div{
width: 70%;
}
}
.footer {
position: absolute;
bottom: 5px;
width: 100%;
>p{
width: 70%;
margin: 10px auto;
}
}
.mapContainer {
width: 100% !important;
//height: 500px;
min-height: 400px;
height: 78%;
margin: 0 auto;
position: absolute;
}
.m-b-10{
margin-bottom: 10px;
}
p {
margin: 0;
}
.tip-box {
max-width: 90%;
max-height: 900px;
position: absolute;
top: 58px;
overflow-y: scroll;
background-color: #fff;
z-index: 20001;
}
.selector-box {
min-width: 300px;
max-width: 420px;
padding: 0 10px;
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #d9d9d9;
background-color: #fff;
> div {
display: flex;
justify-content: flex-start;
align-items: center;
}
}
.close-icon {
color: rgba(0, 0, 0, .25);
}
.hiddenGaode{
position: relative;
height: 20px;
bottom: 20px;
background-color: #ffffff;
z-index: 999;
}
</style>

View File

@ -0,0 +1,311 @@
<template>
<!-- 地图轨迹回放 -->
<a-modal title="轨迹回放" :visible="true" width="1500px" @cancel="closeWindow" :footer="null" :mask="true" :maskClosable="false">
<div class="container2">
<el-amap v-if="showMap" :key="key" class="amap-box" :amap-manager="amapManager" :vid="'amap-vue' + key" :viewMode="viewMode"
:zoom="20" :plugin="plugin" :center="center" :events="events" @init="init" @click="mapClick">
</el-amap>
<div class="machImg" v-if="currentImg">
<!-- <a-image :width="'100%'" :height="'100%'" class="img" :src="https://image.huidatech.cn/c10801e4f-10801e4f-h601-0-1718143953.jpg"/>-->
<a-image :width="'100%'" :height="'100%'" class="img" :src="currentImg"/>
</div>
<div class="input-card" style="text-align: center">
<h4>控制台</h4>
<div class="input-item" style="margin-bottom: 3px;">
<div>
<a-button type="primary" class="btn" @click="tosgo" shape="round">
<template #icon><PoweroffOutlined /></template>
{{moveStatus==0?'开始':moveStatus==1?'暂停':'继续'}}</a-button>
<a-button type="primary" danger class="btn" @click="stopAnimation" shape="round">停止</a-button>
</div>
<div style="margin-top: 10px;text-align: center;">
<a-radio-group v-model:value="speed" button-style="solid" @change="speedChange">
<a-radio-button value="200">0.5倍速</a-radio-button>
<a-radio-button value="100" checked>1倍速</a-radio-button>
<a-radio-button value="50">2倍速</a-radio-button>
<a-radio-button value="30">3倍速</a-radio-button>
</a-radio-group>
</div>
</div>
<!-- <div class="input-item">-->
<!-- <input type="button" class="btn" value="继续" id="resume" @click="resumeAnimation"/>-->
<!-- <input type="button" class="btn" value="停止" id="stop" @click="stopAnimation"/>-->
<!-- </div>-->
</div>
</div>
</a-modal>
</template>
<script lang="ts">
import {defineComponent, ref, watch, nextTick} from 'vue';
import {ElAmap, useCitySearch, lazyAMapApiLoaderInstance} from '@vuemap/vue-amap';
// vue-amap : https://vue-amap.guyixi.cn/zh-cn/base/amap.html#%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7
export default defineComponent( {
name: 'MapTrajectory',
props: {
//
value: {
type: Array,
default: ref([])
},
imgs: {
type: Array,
default: ref([])
},
},
emits: ['success'],
setup(props, { emit }) {//debugger
const defaultPoint = ref([]);
const center = ref([116.478935,39.997761]);
const showMap = ref(true);
const key = ref ('id-'+ new Date().getTime());
const zoom = ref (20); //
const viewMode = ref ('3D'); //
const speed = ref('100')
let _this = this;
let amapManager = null;
const moveStatus = ref(0)
// const currentImg = ref('https://image.huidatech.cn/c10801e4f-10801e4f-h601-0-1718143953.jpg');
const currentImg = ref(null);
let closeWindow = function (){stopAnimation();amapManager.destroy();showMap.value = false;emit('success');}
//
let nnn = 0;
//
let maxN = 0;
//
const events = ref({});
var marker, lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];
if(props.value && props.value.length > 0){
lineArr = props.value;
}
maxN = lineArr.length;
//
const plugin = [ ];
//
function init(map){
//debugger
props.imgs.map(item => {
for(var i = 0,n = props.value.length;i<n;i++){
let v = props.value[i];
if(v[0] == item.lng && v[1] == item.lat){
item._count = i;
break;
}
}
})
console.log(props.imgs , '图片数量'+props.imgs.length);
console.log(props.value , '坐标数量'+props.value.length);
amapManager = map;
center.value = lineArr[0];
map.plugin(['AMap.MoveAnimation'], () => {
console.log('地图初始化完毕: ', map.getCenter())
var satellite = new AMap.TileLayer.Satellite();
map.addLayer(satellite);
var googleLayer = new AMap.TileLayer({
tileSize: 256,
errorUrl: '',
getTileUrl: 'https://map.snkoudai.com/maps/vt/lyrs=y&hl=zh-CN&gl=cn&scale=1&x=[x]&y=[y]&z=[z]',
zIndex: 2,
zooms: [16, 22],
opacity: 1,
})
googleLayer.setMap(map);
marker = new AMap.Marker({
position: lineArr[0],
// icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
offset: new AMap.Pixel(-16, -16),
icon: new AMap.Icon ({
image: "https://manage.ilhzn.cn/zh-api/sys/common/static/temp/20241228154040_824e4981dff456b1bb8889.png",//
imageSize: [40, 40],
size: [40, 40], //
}),
});
marker.setMap(map);
//
var polyline = new AMap.Polyline({
path: lineArr,
showDir:true,
strokeColor: "#28F", //线
// strokeOpacity: 1, //线
strokeWeight: 6, //线
// strokeStyle: "solid" //线
});
polyline.setMap(map);
var passedPolyline = new AMap.Polyline({
map: map,
strokeColor: "#AF5", //线
strokeWeight: 6, //线
});
marker.on('moving', function (e) {//
passedPolyline.setPath(e.passedPath);
let position = e.target.getPosition();
map.setCenter(position,true)
// console.log(nnn, maxN)
// console.log(speed.value)
// if(nnn >= maxN){
// moveStatus.value = 0;
// }
});
marker.on('moveend', function (e) {//
// console.log('moveend')
if(props.imgs.length > 0){
for(var i = 0, n = props.imgs.length; i < n; i++){
let img = props.imgs[i];
if(img.url && img._count == nnn){
// console.log('')
currentImg.value = img.url;
break;
}
}
}
nnn ++;
});
marker.on('movealong', function (e) {//
console.log('动画结束movealong', e)
moveStatus.value = 0;
});
});
// map.setFitView();
}
let speedChange = function (v) {
if(moveStatus.value == 1){
// resumeAnimation();
// startAnimation();
}
startAnimation();
}
let tosgo = function (){
//moveStatus.value 012
if(moveStatus.value == 0){
startAnimation();
} else if(moveStatus.value == 1) {
pauseAnimation();
} else if(moveStatus.value == 2) {
resumeAnimation();
}
}
let startAnimation = function () {
marker.moveAlong(lineArr, {
//
duration: (index, lnglat) =>{ return speed.value},//
// JSAPI2.0 moveAlong
autoRotation: true,
});
moveStatus.value = 1;nnn = 0;
};
let pauseAnimation = function () {
marker.pauseMove();
moveStatus.value = 2
};
let resumeAnimation = function () {
marker.resumeMove();
moveStatus.value = 1;
};
let stopAnimation = function () {
marker.stopMove();
moveStatus.value = 0;
nnn = 0;
};
let mapClick = function (v) {
console.log(v)
};
return {
amapManager, //
events, //
plugin, //
_this,
init,
center,
key,
zoom,
mapClick,
closeWindow,
viewMode,
moveStatus,
stopAnimation,
tosgo,
currentImg,
showMap,
speed,
speedChange
}
}
});
</script>
<style scoped lang="less">
.container2 {
width: 100%;
height: 800px;
margin: 0px auto;
margin-bottom: 10px;
}
.input-card .btn{
margin-right: 1.2rem;
width: 9rem;
}
.input-card .btn:last-child{
margin-right: 0;
}
.input-card {
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border-radius: .25rem;
width: 22rem;
border-width: 0;
border-radius: 0.4rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
position: absolute;
bottom: 1rem;
right: 1rem;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 0.75rem 1.25rem;
}
.machImg{
max-width: 400px;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border-radius: .25rem;
width: 22rem;
border-width: 0;
border-radius: 0.4rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
position: absolute;
bottom: 1rem;
left: 1rem;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 0;
}
:deep(.amap-logo),
:deep(.amap-copyright) {
display: none !important;
}
</style>

View File

@ -56,6 +56,38 @@ import {
Rate,
} from 'ant-design-vue';
// 高德地图
import VueAMap, { initAMapApiLoader } from '@vuemap/vue-amap';
import VueAMapLoca from '@vuemap/vue-amap-loca';
// // import VueAMapExtra from '@vuemap/vue-amap-extra';
import '@vuemap/vue-amap/dist/style.css';
// 高德地图初始化
initAMapApiLoader({
key: '688058527e8c53988d9113867cf2cabe', //高德key by.wgx
securityJsCode: '1a5a3a53ffd31e2180d71b20732f87b8', // 新版key需要配合安全密钥使用
Loca: {
version: '2.0.0',
}, // 如果需要使用loca组件库需要加载Loca
plugin: [
"AMap.Autocomplete", //输入提示插件
"AMap.PlaceSearch", //POI搜索插件
"AMap.Scale", //右下角缩略图插件 比例尺
"AMap.OverView", //地图鹰眼插件
"AMap.ToolBar", //地图工具条
"AMap.MapType", //类别切换控件,实现默认图层与卫星图、实施交通图层之间切换的控制
"AMap.PolyEditor", //编辑 折线多,边形
"AMap.CircleEditor", //圆形编辑器插件
"AMap.Geolocation", //定位控件,用来获取和展示用户主机所在的经纬度位置
"AMap.AMapUI", //定位控件,用来获取和展示用户主机所在的经纬度位置
"AMap.Geocoder", //定位控件,用来获取和展示用户主机所在的经纬度位置
],
AMapUI: { // 是否加载 AMapUI缺省不加载, 文档: https://lbs.amap.com/api/amap-ui/intro
"version": '1.1', // AMapUI 缺省 1.1
"plugins":[], // 需要加载的 AMapUI ui插件
},
Geocoder: {},
});
const compList = [AntButton.Group, Icon, AIcon, JUploadButton];
export function registerGlobComp(app: App) {
@ -64,6 +96,8 @@ export function registerGlobComp(app: App) {
});
app
.use(VueAMap)
.use(VueAMapLoca)
.use(Select)
.use(Alert)
.use(Button)

View File

@ -13,7 +13,9 @@ enum Api {
exportXls = '/appmana/survDeviceDeploy/exportXls',
getYsToken = '/appmana/bigScreen/stationInfoWithCamera',
getValveStatus = '/appmana/survDeviceDeploy/getValveStatus',
sendDeviceCmd= '/appmana/survDeviceDeploy/sendDeviceCmd'
sendDeviceCmd= '/appmana/survDeviceDeploy/sendDeviceCmd',
initDevice = '/appmana/survDeviceDeploy/initDevice',
getDeviceData='/appmana/fDictDeviceDetail/getDeviceData',
}
/**
@ -103,4 +105,32 @@ export const getValveStatus = (params) => {
*/
export const sendDeviceCmd = (params) => {
return defHttp.post({ url: Api.sendDeviceCmd ,params}, { isTransformResponse: false });
}
}
/**
*
* @param params
* @param handleSuccess
*/
export const deviceInit = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认初始化',
content: '该操作会删除当前已配置的指标,是否继续',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.post({url: Api.initDevice, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
*/
export const getDeviceData = (params) => defHttp.get({ url: Api.getDeviceData, params }, { isTransformResponse: false });

View File

@ -7,8 +7,13 @@ export const columns: BasicColumn[] = [
{
title: '设备名称',
align: "center",
dataIndex: 'deviceName'
dataIndex: 'deployDes'
},
// {
// title: '设备名称',
// align: "center",
// dataIndex: 'deviceName'
// },
{
title: '设备部署编号',
align: "center",
@ -21,7 +26,7 @@ export const columns: BasicColumn[] = [
customRender: ({ text }) => {
if (!text || text == '') {
return '无';
}
}
},
},
{
@ -33,7 +38,7 @@ export const columns: BasicColumn[] = [
return '正常';
} else if (text == '1') {
return '停机';
}
}
},
},
{
@ -45,7 +50,7 @@ export const columns: BasicColumn[] = [
return '已通电';
} else if (text == '2') {
return '未通电';
}
}
},
},
// {

View File

@ -108,7 +108,7 @@
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns } from './SurvDeviceDeploy.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './SurvDeviceDeploy.api';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl,deviceInit} from './SurvDeviceDeploy.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import SurvDeviceDeployModal from './components/SurvDeviceDeployModal.vue'
import ControlModal from './components/ControlModal.vue'
@ -118,7 +118,7 @@
import { useDrawer } from '/@/components/Drawer';
import ZhiBiaoList from './components/ZhiBiaoList.vue';
//drawer
const [registerDrawer, { openDrawer }] = useDrawer();
const formRef = ref();
@ -171,7 +171,7 @@
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
@ -179,7 +179,7 @@
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
@ -187,21 +187,21 @@
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
@ -217,7 +217,7 @@
id: record.id,
});
}
/**
* 球阀控制
@ -229,13 +229,21 @@
});
}
/**
* 初始化设备
*/
async function handleInit(record: Recordable) {
await deviceInit({ ids: record.id }, handleSuccess);
}
/**
* 操作栏
*/
function getTableAction(record) {
if(record.deployType =="water_orient" || record.deployType =="water_live"){
if(record.deployType =="water_orient" || record.deployType =="water_live"){
return [
{
label: '编辑',
@ -262,23 +270,46 @@
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
if(record.deployType == 'air'||record.deployType == 'soil'||record.deployType == '6_water'){
return [
{
label: '初始化设备',
onClick: handleInit.bind(null, record),
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
placement: "leftBottom",
confirm: handleDelete.bind(null, record),
}
}
}
]
]
}
else{
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
}
/**
@ -287,7 +318,7 @@
function searchQuery() {
reload();
}
/**
* 重置
*/
@ -297,7 +328,7 @@
//
reload();
}

View File

@ -16,6 +16,7 @@ enum Api {
itemSave = '/appmana/scEquZhibiao/add',
itemEdit = '/appmana/scEquZhibiao/edit',
zhiBiaoItemCheck ='/appmana/scEquZhibiao/zhiBiaoItemCheck',
allpolution = '/appmana/scEquZhibiao/getPollutionDict'
}
/**
@ -116,4 +117,10 @@ export const deleteItem = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
};
/**
*
* @param params
*/
export const polutionList = (params) => defHttp.get({ url: Api.allpolution, params });

View File

@ -2,7 +2,7 @@ import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { zhiBiaoItemCheck } from './ScEquZhibiao.api';
import { zhiBiaoItemCheck,polutionList} from './ScEquZhibiao.api';
//列表数据
@ -158,6 +158,18 @@ export const itemFormSchema: FormSchema[] = [
];
},
},
{
label: '实体字段',
field: 'entityField',
required: true,
component: 'ApiSelect',
componentProps: {
mode: 'single',
api: polutionList,
labelField: 'description',
valueField: 'code',
},
},
{
label: '低阈值',
field: 'valLow',
@ -180,9 +192,11 @@ export const itemFormSchema: FormSchema[] = [
label: '大屏显示',
field: 'zhibiaoType',
component: 'JDictSelectTag',
defaultValue : '1',
componentProps: {
type: 'radioButton',
dictCode: 'yn',
stringToNumber :false,
},
},
{
@ -196,6 +210,22 @@ export const itemFormSchema: FormSchema[] = [
required: false,
component: 'InputNumber',
},
{
label: '创建时间',
field: 'createTime',
component: 'Input',
componentProps: {
disabled: true,
}
},
{
label: '更新时间',
field: 'updateTime',
component: 'Input',
componentProps: {
disabled: true,
}
},
];
@ -238,4 +268,4 @@ export const dictItemSearchFormSchema: FormSchema[] = [
field: 'name',
component: 'Input',
},
];
];

View File

@ -2,26 +2,54 @@
<a-spin :spinning="confirmLoading">
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-row>
<a-col :span="24">
<a-form-item label="设备类型" v-bind="validateInfos.deviceCode" >
<ApiSelect
:api="getDeviceList"
showSearch
v-model:value="formData.deviceCode"
optionFilterProp="label"
resultField="list"
labelField="deviceName"
valueField="deviceCode"
placeholder="请选择"
:disabled="disabled"
/>
</a-form-item>
</a-col>
<!-- <a-col :span="24">-->
<!-- <a-form-item label="设备类型" v-bind="validateInfos.deviceCode" >-->
<!-- <ApiSelect-->
<!-- :api="getDeviceList"-->
<!-- showSearch-->
<!-- v-model:value="formData.deviceCode"-->
<!-- optionFilterProp="label"-->
<!-- resultField="list"-->
<!-- labelField="deviceName"-->
<!-- valueField="deviceCode"-->
<!-- placeholder="请选择"-->
<!-- :disabled="disabled"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="24">
<a-form-item label="设备部署编号" v-bind="validateInfos.deployCode">
<a-input v-model:value="formData.deployCode" placeholder="请输入设备部署编号" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备名称" v-bind="validateInfos.deployDes">
<a-input v-model:value="formData.deployDes" placeholder="请输入设备名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备类型" v-bind="validateInfos.cateId">
<j-tree-select
v-model:value="formData.cateId"
placeholder="请选择设备"
dict="surv_dict_device_cate,CATE_NAME,ID"
pidField="parent_id"
pidValue="0"
condition='{"IS_ENABLE":1}'
:disabled="disabled"
@change="onDevicechange"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="厂家及规格" v-bind="validateInfos.deviceCode">
<a-select :disabled="disabled" placeholder="请选择厂家及规格" v-model:value="formData.deviceCode">
<a-select-option v-for="item in formData.deviceData" :key="item.id" :value="item.id">
{{ item.deviceManufacturer }}-{{ item.deviceName }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="所属站点" v-bind="validateInfos.stationCode">
<ApiSelect
@ -37,6 +65,13 @@
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="经纬度" v-bind="validateInfos.deviceLonglat">
<mapselect v-model:value="formData.deviceLonglat" placeholder="请选择经纬度" :disabled="disabled"></mapselect>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="运行状态" v-bind="validateInfos.runStatus">
<!-- <a-input v-model:value="formData.runStatus" placeholder="请输入运行状态;0=正常1=停机" :disabled="disabled"></a-input> -->
@ -57,11 +92,11 @@
<a-col :span="24">
<a-form-item label="部署类型" v-bind="validateInfos.deployType">
<JDictSelectTag type="select" v-model:value="formData.deployType" dictCode="surv_device_type" placeholder="请选择部署类型" />
</a-form-item>
</a-col>
<!-- <a-col :span="24">-->
<!-- <a-form-item label="部署类型" v-bind="validateInfos.deployType">-->
<!-- <JDictSelectTag type="select" v-model:value="formData.deployType" dictCode="surv_device_type" placeholder="请选择部署类型" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="24">
<a-form-item label="设备分组" v-bind="validateInfos.groupId">
@ -80,11 +115,7 @@
</a-col>
<a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.deployDes">
<a-input v-model:value="formData.deployDes" placeholder="请输入备注" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备链接" v-bind="validateInfos.deviceUrl">
<a-input v-model:value="formData.deviceUrl" placeholder="摄像头时为m3u8地址" :disabled="disabled"></a-input>
@ -129,11 +160,12 @@
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.deployDes">
<a-input v-model:value="formData.deployDes" placeholder="请输入备注" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<!-- <a-col :span="24">-->
<!-- <a-form-item label="备注" v-bind="validateInfos.deployDes">-->
<!-- <a-input v-model:value="formData.deployDes" placeholder="请输入备注" :disabled="disabled"></a-input>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="24">
<a-form-item label="ip地址" v-bind="validateInfos.ipAddr">
@ -165,6 +197,7 @@
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="部署图片" v-bind="validateInfos.deployPic">
<JImageUpload :fileMax="3" v-model:value="formData.deployPic" :disabled="disabled"></JImageUpload>
@ -193,7 +226,7 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../SurvDeviceDeploy.api';
import { saveOrUpdate ,getDeviceData} from '../SurvDeviceDeploy.api';
import { getDeviceList } from '../../device/SurvDeviceInfo.api';
import { getStationList } from '../../station/SurvStationInfo.api';
import { getGroupList } from '../../equgroup/ScEquGroup.api';
@ -202,6 +235,8 @@
import {ApiSelect} from '/@/components/Form/index';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
import mapselect from '/@/components/MapSelect/MapSelect.vue';
import { JTreeSelect } from '/@/components/Form';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
@ -230,6 +265,7 @@
deployDes: '',
deviceUrl: '',
deviceCode:'',
cateId: '',
sortNo: undefined,
deployType:'',
xyId:'',
@ -243,6 +279,9 @@
valveStatus:'',
deviceReverseIotUrl:'',
deviceIotUrl:'',
deviceLatitude: '',
deviceLongitude: '',
deviceLonglat: '112.502657,33.073635',//
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
@ -255,6 +294,8 @@
// stationCode: [{ required: true, message: '', trigger: 'blur' }],
deployType: [{ required: true, message: '部署类型不能为空', trigger: 'blur' }],
// xyId: [{ required: true, message: '', trigger: 'blur' }],
cateId: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
deployDes: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });
@ -271,6 +312,14 @@
return props.formDisabled;
});
async function onDevicechange(selectvalue) {
await getDeviceData({ cateId: selectvalue, isEnable: 1 }).then((res) => {
if (res.success) {
formData.deviceData = res.result;
formData.deviceCode = '';
}
});
}
/**
* 新增
@ -289,6 +338,11 @@
resetFields();
//
entrylistShow(record.xyId);
getDeviceData({ cateId: record.cateId, isEnable: 1 }).then((res) => {
if (res.success) {
formData.deviceData = res.result;
}
});
//scContExe
// record.scContExe=null;
delete (record as any).scContExe

View File

@ -0,0 +1,67 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/fDictCity/list',
tree = '/appmana/fDictCity/tree',
save='/appmana/fDictCity/add',
edit='/appmana/fDictCity/edit',
deleteOne = '/appmana/fDictCity/delete',
deleteBatch = '/appmana/fDictCity/deleteBatch',
importExcel = '/appmana/fDictCity/importExcel',
exportXls = '/appmana/fDictCity/exportXls',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
export const tree = (params) =>
defHttp.get({url: Api.tree, params});
/**
*
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@ -0,0 +1,119 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
//列表数据
export const columns: BasicColumn[] = [
{
title: '城市名称',
align: 'left',
dataIndex: 'areaName'
},
// {
// title: '父ID',
// align: 'center',
// dataIndex: 'parentId'
// },
{
title: '缩写首字母',
align: 'center',
dataIndex: 'pinyin'
},
{
title: '级别',
align: 'center',
dataIndex: 'level'
},
{
title: '经度',
align: 'center',
dataIndex: 'lng'
},
{
title: '纬度',
align: 'center',
dataIndex: 'lat'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '城市名称',
field: 'areaName',
component: 'Input',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入城市名称!'},
];
},
},
{
label: '父ID',
field: 'parentId',
component: 'Input',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入父ID!'},
];
},
},
{
label: '缩写首字母',
field: 'pinyin',
component: 'Input',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入缩写首字母!'},
];
},
},
{
label: '级别',
field: 'level',
component: 'InputNumber',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入级别!'},
];
},
},
{
label: '经度',
field: 'lng',
component: 'InputNumber',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入经度!'},
];
},
},
{
label: '纬度',
field: 'lat',
component: 'InputNumber',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入纬度!'},
];
},
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
/**
* formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据这里需要单独处理formSchema
return formSchema;
}

View File

@ -0,0 +1,164 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
<!-- <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>-->
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>-->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{text}">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<FDictCityModal @register="registerModal" @success="handleSuccess"></FDictCityModal>
</div>
</template>
<script lang="ts" name="farmdict-fDictCity" setup>
import {ref, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import {useModal} from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage'
import FDictCityModal from './components/FDictCityModal.vue'
import {columns, searchFormSchema} from './FDictCity.data';
import {list, tree, deleteOne, batchDelete, getImportUrl,getExportUrl} from './FDictCity.api';
import { downloadFile } from '/@/utils/common/renderUtils';
const checkedKeys = ref<Array<string | number>>([]);
//model
const [registerModal, {openModal}] = useModal();
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '字典-全国城市',
rowKey: 'id',
isTreeTable: true,
pagination: false,
showIndexColumn: true,
api: tree,
columns,
canResize:false,
useSearchForm: false,
showActionColumn: false,
actionColumn: {
width: 140,
fixed:'right'
},
},
exportConfig: {
name:"字典-全国城市",
url: getExportUrl,
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '编辑',
onClick: handleEdit.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
]
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,71 @@
<template>
<div style="min-height: 400px">
<BasicForm @register="registerForm"></BasicForm>
<div style="width: 100%;text-align: center" v-if="!formDisabled">
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button>
</div>
</div>
</template>
<script lang="ts">
import {BasicForm, useForm} from '/@/components/Form/index';
import {computed, defineComponent} from 'vue';
import {defHttp} from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
import {getBpmFormSchema} from '../FDictCity.data';
import {saveOrUpdate} from '../FDictCity.api';
export default defineComponent({
name: "FDictCityForm",
components:{
BasicForm
},
props:{
formData: propTypes.object.def({}),
formBpm: propTypes.bool.def(true),
},
setup(props){
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
labelWidth: 150,
schemas: getBpmFormSchema(props.formData),
showActionButtonGroup: false,
baseColProps: {span: 24}
});
const formDisabled = computed(()=>{
if(props.formData.disabled === false){
return false;
}
return true;
});
let formData = {};
const queryByIdUrl = '/appmana/fDictCity/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
params.id=props.formData.dataId;
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//
await setFieldsValue(formData);
//
await setProps({disabled: formDisabled.value})
}
async function submitForm() {
let data = getFieldsValue();
let params = Object.assign({}, formData, data);
console.log('表单数据', params)
await saveOrUpdate(params, true)
}
initFormData();
return {
registerForm,
formDisabled,
submitForm,
}
}
});
</script>

View File

@ -0,0 +1,66 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../FDictCity.data';
import {saveOrUpdate} from '../FDictCity.api';
// Emits
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
//
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: {span: 24}
});
//
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
}
//
setProps({ disabled: !data?.showFooter })
});
//
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//
await saveOrUpdate(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number){
width: 100%
}
:deep(.ant-calendar-picker){
width: 100%
}
</style>

View File

@ -0,0 +1,76 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/fDictDeviceCate/list',
tree = '/appmana/fDictDeviceCate/tree',
save='/appmana/fDictDeviceCate/add',
edit='/appmana/fDictDeviceCate/edit',
deleteOne = '/appmana/fDictDeviceCate/delete',
deleteBatch = '/appmana/fDictDeviceCate/deleteBatch',
importExcel = '/appmana/fDictDeviceCate/importExcel',
exportXls = '/appmana/fDictDeviceCate/exportXls',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
export const tree = (params) =>
defHttp.get({url: Api.tree, params});
/**
*
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}

View File

@ -0,0 +1,121 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '设备种类名称',
align: "center",
dataIndex: 'cateName'
},
{
title: '种类图片',
align: "center",
dataIndex: 'catePic',
customRender: ({ text }) => {
if(!text){
return text;
}
return render.renderImage({text});
},
},
{
title: '上级类型',
align: "center",
dataIndex: 'parentName',
customRender: ({ text }) => {
if (!text) {
return '无';
} else {
return text;
}
}
},
{
title: '是否启用',
align: "center",
dataIndex: 'isEnable',
customRender: ({ text }) => {
const color = text == '1' ? 'green' : text == '0' ? 'red' : 'gray';
return render.renderTag(render.renderDict(text, 'yn'), color);
},
},
{
title: '创建时间',
align: "center",
dataIndex: 'createTime'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
field: 'cateName',
label: '类型名称',
component: 'Input',
colProps: { span: 6 },
},
{
label: '上级类型',
field: 'parentId',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'surv_dict_device_cate,CATE_NAME,ID',
placeholder: '请选择类型',
stringToNumber: false,
},
colProps: { span: 6 },
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '设备种类名称',
field: 'cateName',
component: 'Input',
},
{
label: '种类图片',
field: 'catePic',
component: 'Input',
},
{
label: '父类ID',
field: 'parentId',
component: 'Input',
},
{
label: '备注',
field: 'cateRemark',
component: 'Input',
},
{
label: '是否启用',
field: 'isEnable',
component: 'InputNumber',
},
{
label: '租户号',
field: 'tenantId',
component: 'Input',
},
{
label: '乐观锁',
field: 'reVision',
component: 'InputNumber',
},
{
label: '逻辑删除',
field: 'isDel',
component: 'InputNumber',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];

View File

@ -0,0 +1,214 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{text}">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<FDictDeviceCateModal ref="registerModal" @success="handleSuccess"></FDictDeviceCateModal>
</div>
</template>
<script lang="ts" name="farm-fDictDeviceCate" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns,searchFormSchema } from './FDictDeviceCate.data';
import { list, tree,deleteOne, batchDelete, getImportUrl, getExportUrl } from './FDictDeviceCate.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import FDictDeviceCateModal from './components/FDictDeviceCateModal.vue'
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '设备种类字典',
api: tree,
columns,
canResize:false,
showIndexColumn :false,
useSearchForm: false,
formConfig: {
schemas: searchFormSchema,
autoSubmitOnEnter:true,
},
actionColumn: {
width: 120,
fixed: 'right',
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "设备种类字典",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: { span: 24 },
sm: { span: 7 },
});
const wrapperCol = reactive({
xs: { span: 24 },
sm: { span: 16 },
});
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust{
width: calc(50% - 15px);
min-width: 100px !important;
}
.query-group-split-cust{
width: 30px;
display: inline-block;
text-align: center
}
}
</style>

View File

@ -0,0 +1,175 @@
<template>
<a-spin :spinning="confirmLoading">
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-row>
<a-col :span="24">
<a-form-item label="设备种类名称" v-bind="validateInfos.cateName">
<a-input v-model:value="formData.cateName" placeholder="请输入设备种类名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="上级类型" v-bind="validateInfos.parentId">
<JDictSelectTag v-model:value="formData.parentId" placeholder="请选择上级" dictCode="surv_dict_device_cate,CATE_NAME,ID,parent_id='0'" ></JDictSelectTag>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="部署类型大类" v-bind="validateInfos.deployCate">
<JDictSelectTag v-model:value="formData.deployCate" placeholder="请选择部署类型大类" dictCode="surv_device_cate" ></JDictSelectTag>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="部署类型" v-bind="validateInfos.deployType">
<JDictSelectTag v-model:value="formData.deployType" placeholder="请选择部署类型" dictCode="surv_device_type" ></JDictSelectTag>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="次级部署类型" v-bind="validateInfos.deploySecondaryType">
<a-input v-model:value="formData.deploySecondaryType" placeholder="请输入次级部署类型" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.cateRemark">
<a-input v-model:value="formData.cateRemark" placeholder="请输入备注" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否启用" v-bind="validateInfos.isEnable">
<JDictSelectTag type="radio" v-model:value="formData.isEnable" stringToNumber="false" dictCode="dict_item_status" placeholder="选择状态" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="种类图片" v-bind="validateInfos.catePic">
<JImageUpload :fileMax="1" v-model:value="formData.catePic" :disabled="disabled"></JImageUpload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../FDictDeviceCate.api';
import { Form } from 'ant-design-vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
import JSelectMultiple from '/@/components/Form/src/jeecg/components/JSelectMultiple.vue'
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: ()=>{} },
formBpm: { type: Boolean, default: true }
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
cateName: '',
catePic: '',
parentId: '0',
deployCate:'',
deployType:'',
deploySecondaryType:'',
cateRemark: '',
isEnable: 1,
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = {
cateName: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
catePic: [{ required: true, message: '图片不能为空', trigger: 'blur' }],
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });
//
const disabled = computed(()=>{
if(props.formBpm === true){
if(props.formData.disabled === false){
return false;
}else{
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
//
Object.assign(formData, record);
});
}
/**
* 提交数据
*/
async function submitForm() {
//
await validate();
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
min-height: 500px !important;
overflow-y: auto;
padding: 24px 24px 24px 24px;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<a-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<FDictDeviceCateForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></FDictDeviceCateForm>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import FDictDeviceCateForm from './FDictDeviceCateForm.vue'
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style>
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>

View File

@ -0,0 +1,72 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/fDictDeviceDetail/list',
save='/appmana/fDictDeviceDetail/add',
edit='/appmana/fDictDeviceDetail/edit',
deleteOne = '/appmana/fDictDeviceDetail/delete',
deleteBatch = '/appmana/fDictDeviceDetail/deleteBatch',
importExcel = '/appmana/fDictDeviceDetail/importExcel',
exportXls = '/appmana/fDictDeviceDetail/exportXls',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
*
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}

View File

@ -0,0 +1,144 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '设备种类',
align: "center",
dataIndex: 'cateName'
},
{
title: '设备型号',
align: "center",
dataIndex: 'deviceModel'
},
{
title: '设备名称',
align: "center",
dataIndex: 'deviceName'
},
{
title: '生产厂家',
align: "center",
dataIndex: 'deviceManufacturer'
},
{
title: '创建时间',
align: "center",
dataIndex: 'createTime'
},
{
title: '是否启用',
align: "center",
dataIndex: 'isEnable',
customRender: ({ text }) => {
const color = text == '1' ? 'green' : text == '0' ? 'red' : 'gray';
return render.renderTag(render.renderDict(text, 'yn'), color);
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
field: 'deviceManufacturer',
label: '生产厂家',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'surv_dict_device_detail,DEVICE_MANUFACTURER,DEVICE_MANUFACTURER',
placeholder: '请选择生产厂家',
stringToNumber: false,
},
colProps: { span: 6 },
},
{
label: '上级类型',
field: 'cateId',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'surv_dict_device_cate,CATE_NAME,ID',
placeholder: '请选择类型',
stringToNumber: false,
},
colProps: { span: 6 },
},
{
field: 'deviceName',
label: '设备名称',
component: 'Input',
colProps: { span: 6 },
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '设备种类ID',
field: 'cateId',
component: 'Input',
},
{
label: '次级种类ID',
field: 'cateSecondId',
component: 'Input',
},
{
label: '设备型号',
field: 'deviceModel',
component: 'Input',
},
{
label: '生产厂家',
field: 'deviceManufacturer',
component: 'Input',
},
{
label: '设备图标',
field: 'deviceIcon',
component: 'Input',
},
{
label: '监测项(监测类设备填入);数组,存放监测项',
field: 'survItem',
component: 'Input',
},
{
label: '设备代号',
field: 'deviceCode',
component: 'Input',
},
{
label: '设备名称',
field: 'deviceName',
component: 'Input',
},
{
label: '设备简称',
field: 'deviveShortName',
component: 'Input',
},
{
label: '租户号',
field: 'tenantId',
component: 'Input',
},
{
label: '乐观锁',
field: 'reVision',
component: 'InputNumber',
},
{
label: '逻辑删除',
field: 'isDel',
component: 'InputNumber',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];

View File

@ -0,0 +1,214 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{text}">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<FDictDeviceDetailModal ref="registerModal" @success="handleSuccess"></FDictDeviceDetailModal>
</div>
</template>
<script lang="ts" name="farm-fDictDeviceDetail" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns ,searchFormSchema} from './FDictDeviceDetail.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './FDictDeviceDetail.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import FDictDeviceDetailModal from './components/FDictDeviceDetailModal.vue'
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '设备明细字典',
api: list,
columns,
canResize:false,
useSearchForm: true,
formConfig: {
schemas: searchFormSchema,
autoSubmitOnEnter:true,
},
actionColumn: {
width: 120,
fixed: 'right',
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "设备明细字典",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: { span: 24 },
sm: { span: 7 },
});
const wrapperCol = reactive({
xs: { span: 24 },
sm: { span: 16 },
});
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust{
width: calc(50% - 15px);
min-width: 100px !important;
}
.query-group-split-cust{
width: 30px;
display: inline-block;
text-align: center
}
}
</style>

View File

@ -0,0 +1,243 @@
<template>
<a-spin :spinning="confirmLoading">
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-row>
<a-col :span="24">
<a-form-item label="设备名称" v-bind="validateInfos.deviceName">
<a-input v-model:value="formData.deviceName" placeholder="请输入设备名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备种类" v-bind="validateInfos.cateId">
<j-tree-select
v-model:value="formData.cateId"
placeholder="请选择设备"
dict="surv_dict_device_cate,CATE_NAME,ID"
pidField="parent_id"
pidValue="0"
condition='{"IS_ENABLE":1}'
:disabled="disabled"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备简称" v-bind="validateInfos.deviveShortName">
<a-input v-model:value="formData.deviveShortName" placeholder="请输入设备简称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备代号" v-bind="validateInfos.deviceCode">
<a-input v-model:value="formData.deviceCode" placeholder="请输入设备代号" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备型号" v-bind="validateInfos.deviceModel">
<a-input v-model:value="formData.deviceModel" placeholder="请输入设备型号" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="生产厂家" v-bind="validateInfos.deviceManufacturer">
<a-input v-model:value="formData.deviceManufacturer" placeholder="请输入生产厂家" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="对接协议" v-bind="validateInfos.deviceProtocol">
<JDictSelectTag type="select" v-model:value="formData.deviceProtocol" dictCode="iot_protocol" placeholder="请选择对接协议" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="协议类型" v-bind="validateInfos.protocolType">
<JDictSelectTag type="select" v-model:value="formData.protocolType" dictCode="iot_protocol_type" placeholder="请选择协议类型" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备说明" v-bind="validateInfos.deviceDes">
<a-textarea v-model:value="formData.deviceDes" placeholder="请输入设备说明" :disabled="disabled"></a-textarea>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="监测项(监测类设备)" v-bind="validateInfos.survItem">
<a-input v-model:value="formData.survItem" placeholder="请输入监测项" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否启用" v-bind="validateInfos.isEnable">
<JDictSelectTag type="radio" v-model:value="formData.isEnable" stringToNumber="false" dictCode="yn" placeholder="选择状态" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否支持抓图" v-bind="validateInfos.isSupportCapture">
<JDictSelectTag type="radio" v-model:value="formData.isSupportCapture" stringToNumber="false" dictCode="yn" placeholder="选择是否支持抓图" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否支持数据分析" v-bind="validateInfos.isSupportAnalysis">
<JDictSelectTag type="radio" v-model:value="formData.isSupportAnalysis" stringToNumber="false" dictCode="yn" placeholder="选择是否支持数据分析" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否支持坐标定位" v-bind="validateInfos.isSupportPosition">
<JDictSelectTag type="radio" v-model:value="formData.isSupportPosition" stringToNumber="false" dictCode="yn" placeholder="选择是否支持坐标定位" :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="设备图标" v-bind="validateInfos.deviceIcon">
<JImageUpload :fileMax="1" v-model:value="formData.deviceIcon" :disabled="disabled"></JImageUpload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="默认部署图" v-bind="validateInfos.defaultDeployPic">
<JImageUpload :fileMax="1" v-model:value="formData.defaultDeployPic" :disabled="disabled"></JImageUpload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="默认地图图标" v-bind="validateInfos.defaultMapIcon">
<JImageUpload :fileMax="1" v-model:value="formData.defaultMapIcon" :disabled="disabled"></JImageUpload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../FDictDeviceDetail.api';
import { Form } from 'ant-design-vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
import {JTreeSelect} from '/@/components/Form';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: ()=>{} },
formBpm: { type: Boolean, default: true }
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
cateId: '',
deviceModel: '',
deviceManufacturer: '',
deviceProtocol:'',
deviceIcon: '',
defaultDeployPic: '',
defaultMapIcon: '',
survItem: '',
deviceCode: '',
deviceName: '',
deviveShortName: '',
tenantId: '',
reVision: undefined,
isDel: undefined,
isEnable:1,
isSupportCapture:0,
isSupportAnalysis:0,
isSupportPosition:0
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = {
deviceName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
cateId: [{ required: true, message: '设备种类不能为空', trigger: 'blur' }],
deviceManufacturer: [{ required: true, message: '生产厂家不能为空', trigger: 'blur' }],
deviceModel: [{ required: true, message: '设备型号不能为空', trigger: 'blur' }],
deviceProtocol: [{ required: true, message: '请选择对接协议', trigger: 'blur' }],
protocolType: [{ required: true, message: '请选择协议类型', trigger: 'blur' }],
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });
//
const disabled = computed(()=>{
if(props.formBpm === true){
if(props.formData.disabled === false){
return false;
}else{
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
//
Object.assign(formData, record);
});
}
/**
* 提交数据
*/
async function submitForm() {
//
await validate();
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
console.log('asdasdasd',formData.deviceProtocol)
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
min-height: 500px !important;
overflow-y: auto;
padding: 24px 24px 24px 24px;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<a-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<FDictDeviceDetailForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></FDictDeviceDetailForm>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import FDictDeviceDetailForm from './FDictDeviceDetailForm.vue'
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style>
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>

View File

@ -20,7 +20,7 @@
const tabListTitle = [
{
key: 'tab1',
tab: '重要污染物监测曲线',
tab: '趋势分析',
},
// {
// key: 'tab2',