main
徐景良 2026-02-28 09:46:14 +08:00
commit 433d1efab7
22 changed files with 355 additions and 180 deletions

View File

@ -30,3 +30,10 @@ VITE_GLOB_APP_MANAGEMENT_UNIT = 管理单位:临沂市自然资源和规划局
VITE_GLOB_APP_TECHINICAL_SUPPORT = 技术⽀持:山东慧创信息科技有限公司 VITE_GLOB_APP_TECHINICAL_SUPPORT = 技术⽀持:山东慧创信息科技有限公司
VITE_GLOB_APP_VERSIONS = 系统版本V1.0 VITE_GLOB_APP_VERSIONS = 系统版本V1.0
VITE_GLOB_MQTT_URL = wrj.wisestcity.com
VITE_GLOB_MQTT_PORT = 6010
VITE_GLOB_APP_RTMP_URL = rtmp://123.132.248.154:1935
VITE_GLOB_APP_FLV_URL = http://123.132.248.154:1986
VITE_GLOB_SRS_API_URL = http://123.132.248.154:1985

View File

@ -167,7 +167,8 @@
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"vuex": "^4.1.0", "vuex": "^4.1.0",
"xe-utils": "^3.5.14", "xe-utils": "^3.5.14",
"xlsx": "^0.18.5" "xlsx": "^0.18.5",
"@turf/helpers": "^7.2.0"
}, },
"devDependencies": { "devDependencies": {
"@amap/amap-jsapi-loader": "^1.0.1", "@amap/amap-jsapi-loader": "^1.0.1",

View File

@ -8,6 +8,8 @@ enum Api {
AddPreventionplan = '/api/FmPreventionPlan/AddPreventionplan', AddPreventionplan = '/api/FmPreventionPlan/AddPreventionplan',
// 删除预案 // 删除预案
DeletePreventionplan = '/api/FmPreventionPlan/DeletePreventionplan', DeletePreventionplan = '/api/FmPreventionPlan/DeletePreventionplan',
// 根据坐标点获取预案
LoadClueInfoByLngLat = '/api/FmPreventionPlan/LoadClueInfoByLngLat',
} }
export function GetPreventionplanPageList(params) { export function GetPreventionplanPageList(params) {
return defHttp.get({ return defHttp.get({
@ -31,4 +33,10 @@ export function DeletePreventionplan(id) {
return defHttp.post({ return defHttp.post({
url: `${Api.DeletePreventionplan}?id=${id}`, url: `${Api.DeletePreventionplan}?id=${id}`,
}); });
}
export function LoadClueInfoByLngLat(params) {
return defHttp.get({
url: Api.LoadClueInfoByLngLat,
params
});
} }

View File

@ -0,0 +1,8 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
LoadTimeSoltByUserId = '/api/FireManagement/LoadTimeSoltByUserId',
AddOrUpdateTimeSolt = '/api/FireManagement/AddOrUpdateTimeSolt',
}
export const LoadTimeSoltByUserId = (params: { id:number }) => defHttp.get({ url: Api.LoadTimeSoltByUserId, params });
export const AddOrUpdateTimeSolt = (params) => defHttp.post({ url: Api.AddOrUpdateTimeSolt, params });

View File

@ -50,19 +50,20 @@
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">预案名称</div> <div class="plan-label">预案名称</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['planName']" placeholder="请输入预案名称" /> <a-input ref="planName" class="add-plan-input" v-model:value="addPlanData['planName']" placeholder="请输入预案名称" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">预案编号</div> <div class="plan-label">预案编号</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['planCode']" placeholder="请输入预案编号" /> <a-input ref="planCode" class="add-plan-input" v-model:value="addPlanData['planCode']" placeholder="请输入预案编号" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">预案类别</div> <div class="plan-label">预案类别</div>
<div class="plan-content"> <div class="plan-content">
<a-select <a-select
ref="planCategory"
class="add-plan-select" class="add-plan-select"
popupClassName="add-plan-popup-select" popupClassName="add-plan-popup-select"
v-model:value="addPlanData['planCategory']" v-model:value="addPlanData['planCategory']"
@ -75,25 +76,26 @@
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">管理级别</div> <div class="plan-label">管理级别</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['admLevel']" placeholder="请输入管理级别" /> <a-input ref="admLevel" class="add-plan-input" v-model:value="addPlanData['admLevel']" placeholder="请输入管理级别" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">描述</div> <div class="plan-label">描述</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['description']" placeholder="请输入描述" /> <a-input ref="description" class="add-plan-input" v-model:value="addPlanData['description']" placeholder="请输入描述" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">内容</div> <div class="plan-label">内容</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['content']" placeholder="请输入内容" /> <a-input ref="content" class="add-plan-input" v-model:value="addPlanData['content']" placeholder="请输入内容" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">状态</div> <div class="plan-label">状态</div>
<div class="plan-content"> <div class="plan-content">
<a-select <a-select
ref="status"
class="add-plan-select" class="add-plan-select"
popupClassName="add-plan-popup-select" popupClassName="add-plan-popup-select"
v-model:value="addPlanData['status']" v-model:value="addPlanData['status']"
@ -106,13 +108,14 @@
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">写入单元</div> <div class="plan-label">写入单元</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['writeUnit']" placeholder="请输入写入单元" /> <a-input ref="writeUnit" class="add-plan-input" v-model:value="addPlanData['writeUnit']" placeholder="请输入写入单元" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">生效日期</div> <div class="plan-label">生效日期</div>
<div class="plan-content"> <div class="plan-content">
<a-date-picker <a-date-picker
ref="effectiveDate"
v-model:value="addPlanData['effectiveDate']" v-model:value="addPlanData['effectiveDate']"
class="add-plan-date-picker" class="add-plan-date-picker"
popupClassName="add-plan-date-picker-popup" popupClassName="add-plan-date-picker-popup"
@ -125,6 +128,7 @@
<div class="plan-label">到期日期</div> <div class="plan-label">到期日期</div>
<div class="plan-content"> <div class="plan-content">
<a-date-picker <a-date-picker
ref="expiry_date"
v-model:value="addPlanData['expiry_date']" v-model:value="addPlanData['expiry_date']"
class="add-plan-date-picker" class="add-plan-date-picker"
popupClassName="add-plan-date-picker-popup" popupClassName="add-plan-date-picker-popup"
@ -136,13 +140,13 @@
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">负责人</div> <div class="plan-label">负责人</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['responsiblePerson']" placeholder="请输入负责人" /> <a-input ref="responsiblePerson" class="add-plan-input" v-model:value="addPlanData['responsiblePerson']" placeholder="请输入负责人" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
<div class="plan-label">联系方式</div> <div class="plan-label">联系方式</div>
<div class="plan-content"> <div class="plan-content">
<a-input class="add-plan-input" v-model:value="addPlanData['contact']" placeholder="联系方式" /> <a-input ref="contact" class="add-plan-input" v-model:value="addPlanData['contact']" placeholder="联系方式" />
</div> </div>
</div> </div>
<div class="add-plan-item"> <div class="add-plan-item">
@ -156,6 +160,9 @@
<a-button class="add-plan-button">上传附件</a-button> <a-button class="add-plan-button">上传附件</a-button>
</a-upload> </a-upload>
</div> </div>
<div class="add-plan-item">
<a-button ref="geom" class="add-plan-button" @click="getGeom()"></a-button>
</div>
</div> </div>
<div class="add-plan-footer"> <div class="add-plan-footer">
<div class="save-button" @click="save"></div> <div class="save-button" @click="save"></div>
@ -178,6 +185,11 @@
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { uploadFile } from '@/api/demo/files' import { uploadFile } from '@/api/demo/files'
import { getAppEnvConfig } from '@/utils/env' import { getAppEnvConfig } from '@/utils/env'
import { point, polygon as trfPolygon } from '@turf/helpers';
import { WktToGeojson, GeojsonToWkt } from '@/views/demo/layer/geometryHandler';
import { contingencyPlanStore } from '@/store/modules/contingencyplan';
const contingencyPlanStoreVal = contingencyPlanStore();
const chartEditStore = useChartEditStore(); const chartEditStore = useChartEditStore();
let { VITE_GLOB_API_URL } = getAppEnvConfig(); let { VITE_GLOB_API_URL } = getAppEnvConfig();
const props = defineProps({ const props = defineProps({
@ -210,21 +222,38 @@
{ label: '负责人', key: 'responsiblePerson' }, { label: '负责人', key: 'responsiblePerson' },
{ label: '联系方式', key: 'contact' }, { label: '联系方式', key: 'contact' },
] ]
const planName = ref(null)
const planCode = ref(null)
const planCategory = ref(null)
const admLevel = ref(null)
const description = ref(null)
const content = ref(null)
const status = ref(null)
const writeUnit = ref(null)
const effectiveDate = ref(null)
const expiry_date = ref(null)
const responsiblePerson = ref(null)
const contact = ref(null)
const geom = ref(null)
const addPlanItemList = [ const addPlanItemList = [
{ label: '预案名称', key: 'planName' }, { label: '预案名称', key: 'planName', dom: planName },
{ label: '预案编号', key: 'planCode' }, { label: '预案编号', key: 'planCode', dom: planCode },
{ label: '预案类别', key: 'planCategory' }, { label: '预案类别', key: 'planCategory', dom: planCategory },
{ label: '管理级别', key: 'admLevel' }, { label: '管理级别', key: 'admLevel', dom: admLevel },
{ label: '描述', key: 'description' }, { label: '描述', key: 'description', dom: description },
{ label: '内容', key: 'content' }, { label: '内容', key: 'content', dom: content },
{ label: '状态', key: 'status' }, { label: '状态', key: 'status', dom: status },
{ label: '写入单元', key: 'writeUnit' }, { label: '写入单元', key: 'writeUnit', dom: writeUnit },
{ label: '生效日期', key: 'effectiveDate' }, { label: '生效日期', key: 'effectiveDate', dom: effectiveDate },
{ label: '到期日期', key: 'expiry_date' }, { label: '到期日期', key: 'expiry_date', dom: expiry_date },
{ label: '负责人', key: 'responsiblePerson' }, { label: '负责人', key: 'responsiblePerson', dom: responsiblePerson },
{ label: '联系方式', key: 'contact' }, { label: '联系方式', key: 'contact', dom: contact },
{ label: '预案范围', key: 'geom', dom: geom },
] ]
let geojsonLayer: mars3d.layer.GeoJsonLayer let geojsonLayer: mars3d.layer.GeoJsonLayer
let drawLayer;
let graphic;
const lastGraphics = ref<any>([])
const { w, h } = toRefs(props.chartConfig.attr); const { w, h } = toRefs(props.chartConfig.attr);
const { const {
dataset, dataset,
@ -264,14 +293,10 @@
}) })
}); });
const showInfo = async (item) => { const showInfo = async (item) => {
if(!geojsonLayer){ if(!contingencyPlanStoreVal.getLayer()){
geojsonLayer = new mars3d.layer.GeoJsonLayer({ contingencyPlanStoreVal.setLayer()
name: 'fire-plan-layer',
clampToGround: true
})
window.globalMap.addLayer(geojsonLayer);
}else{ }else{
geojsonLayer.clear() contingencyPlanStoreVal.clearData()
} }
if(item.attachment){ if(item.attachment){
const res = await fetch(`${VITE_GLOB_API_URL}/${item.attachment}`) const res = await fetch(`${VITE_GLOB_API_URL}/${item.attachment}`)
@ -280,12 +305,7 @@
return return
} }
const data = await res.json() const data = await res.json()
geojsonLayer.load({ contingencyPlanStoreVal.reloadData(data)
data: data
})
geojsonLayer.flyTo({
scale: 1.5
})
} }
EventBus.emit('ContingencyPlanListToContingencyPlanInfo',item) EventBus.emit('ContingencyPlanListToContingencyPlanInfo',item)
} }
@ -299,6 +319,10 @@
} }
const closeAddPlan = () => { const closeAddPlan = () => {
addPlanDiv.value = false addPlanDiv.value = false
lastGraphics.value.forEach(item => {
drawLayer && drawLayer.removeGraphic(item)
})
drawLayer && drawLayer.stopDraw()
} }
const query = () => { const query = () => {
let params = { let params = {
@ -312,11 +336,33 @@
} }
const save = () => { const save = () => {
let isCheck = true let isCheck = true
addPlanData.value.geom = addAndUpdateWorkArea()
addPlanItemList.forEach(item => { addPlanItemList.forEach(item => {
if(!(addPlanData.value[item.key])){ if(!(addPlanData.value[item.key])){
isCheck = false isCheck = false
message.warning(`${item.label}为空!`) if(['planCategory', 'status'].includes(item.key)){
return const el = item.dom?.value?.$el
const selector = el.querySelector('.ant-select-selector')
selector.style.borderColor = '#ff3939'
}else if(item.key == 'geom'){
const el = item.dom?.value?.$el
el.style.background = '#ff3939'
}else{
const el = item.dom?.value?.$el
el.style.borderColor = '#ff3939'
}
}else{
if(['planCategory', 'status'].includes(item.key)){
const el = item.dom?.value?.$el
const selector = el.querySelector('.ant-select-selector')
selector.style.borderColor = '#00611A'
}else if(item.key == 'geom'){
const el = item.dom?.value?.$el
el.style.background = '#00611A'
}else{
const el = item.dom?.value?.$el
el.style.borderColor = '#00611A'
}
} }
}) })
if(isCheck){ if(isCheck){
@ -328,6 +374,10 @@
message.success('预案添加成功') message.success('预案添加成功')
query() query()
addPlanDiv.value = false addPlanDiv.value = false
lastGraphics.value.forEach(item => {
drawLayer && drawLayer.removeGraphic(item)
})
drawLayer && drawLayer.stopDraw()
}) })
} }
} }
@ -358,6 +408,46 @@
fileList.value = resFileList; fileList.value = resFileList;
}) })
} }
const getGeom = async () => {
lastGraphics.value.forEach(item => {
drawLayer && drawLayer.removeGraphic(item)
})
if(!drawLayer){
drawLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true,
});
window.globalMap.addLayer(drawLayer)
}
graphic = await drawLayer.startDraw({
type: 'polygon',
style: {
color: "#00B569",
opacity: 0.2,
outline: true,
outlineColor: "#00B569",
outlineWidth: 2,
},
});
lastGraphics.value.push(graphic)
console.log('draw',graphic)
}
function addAndUpdateWorkArea(addOrUpdate = 'add') {
if(!graphic){
return ''
}
let graphicJson = graphic.toJSON();
let coordinates = graphicJson.position || graphicJson.positions;
let polygonData: any = [];
let geom = '';
coordinates.push(coordinates[0]);
if (addOrUpdate == 'add') {
polygonData.push(coordinates);
} else {
polygonData = coordinates;
}
geom = GeojsonToWkt(trfPolygon(polygonData).geometry);
return geom
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -12,6 +12,8 @@
/> />
<span class="text">{{ Weather }} °C</span> <span class="text">{{ Weather }} °C</span>
</div> </div>
<div class="wind-speed">
<span style="margin-right: 25px;">{{`风速:${windPower}m/s`}}</span>{{`风向: ${winddirection}`}}</div>
</div> </div>
</template> </template>
@ -38,6 +40,8 @@
const currentTime = ref(dayjs().locale('zh-cn').format('YYYY年M月D日 dddd HH:mm:ss')); const currentTime = ref(dayjs().locale('zh-cn').format('YYYY年M月D日 dddd HH:mm:ss'));
const Weather = ref(''); const Weather = ref('');
const windPower = ref()
const winddirection = ref()
async function getWeather() { async function getWeather() {
try { try {
// //
@ -46,6 +50,8 @@
url: `https://restapi.amap.com/v3/weather/weatherInfo?city=371300&key=ae4fb485fa25f5884b9cd7c1101687c4`, url: `https://restapi.amap.com/v3/weather/weatherInfo?city=371300&key=ae4fb485fa25f5884b9cd7c1101687c4`,
}).then((res) => { }).then((res) => {
Weather.value = res.data.lives[0].temperature; Weather.value = res.data.lives[0].temperature;
windPower.value = res.data.lives[0].windpower;
winddirection.value = res.data.lives[0].winddirection;
if(res.data.lives[0].weather == '阴'){ if(res.data.lives[0].weather == '阴'){
weatherIcon.value = "wi:cloud" weatherIcon.value = "wi:cloud"
}else if(res.data.lives[0].weather == '晴'){ }else if(res.data.lives[0].weather == '晴'){
@ -116,5 +122,15 @@
font-size: v-bind('textSize+"px"'); font-size: v-bind('textSize+"px"');
} }
} }
.wind-speed{
position: absolute;
top: 45px;
left: 30px;
width: 400px;
height: 42px;
margin-left: 10px;
color: v-bind('textColor');
font-size: v-bind('textSize+"px"');
}
</style> </style>

View File

@ -113,7 +113,7 @@
}, 5000); }, 5000);
}); });
// <<<<<<< HEAD //
// const navsClick = function(item,index){ // const navsClick = function(item,index){
// navsIndex.value = index // navsIndex.value = index
// props.chartConfig.request.requestSQLContent.sql = item.sql // props.chartConfig.request.requestSQLContent.sql = item.sql

View File

@ -20,6 +20,9 @@
import { option as configOption } from './config'; import { option as configOption } from './config';
import { eventHandlerHook } from '@/hooks/eventHandler.hook'; import { eventHandlerHook } from '@/hooks/eventHandler.hook';
import { EventBus } from '@/utils/eventBus'; import { EventBus } from '@/utils/eventBus';
import { contingencyPlanStore } from '@/store/modules/contingencyplan';
const contingencyPlanStoreVal = contingencyPlanStore();
const chartEditStore = useChartEditStore(); const chartEditStore = useChartEditStore();
const props = defineProps({ const props = defineProps({
@ -58,6 +61,7 @@
'click', 'click',
val, val,
); );
contingencyPlanStoreVal.clearData()
}; };
const dblclickBtn = (val) => { const dblclickBtn = (val) => {
eventHandlerHook( eventHandlerHook(

View File

@ -425,6 +425,10 @@
import {drcDownTopicReize,eventsTopicSubscribeReize,servicesTopicReize,services_replyTopicReize,} from '@/utils/debugging/events'; import {drcDownTopicReize,eventsTopicSubscribeReize,servicesTopicReize,services_replyTopicReize,} from '@/utils/debugging/events';
import {getRedisUser,addOrUpdateRedisUser,getLockedClients,getTsgzProjectId,applyDroneControl} from '@/api/demo/airportMaintenance'; import {getRedisUser,addOrUpdateRedisUser,getLockedClients,getTsgzProjectId,applyDroneControl} from '@/api/demo/airportMaintenance';
import { airPortStore } from '@/store/modules/airport'; import { airPortStore } from '@/store/modules/airport';
import { LoadClueInfoByLngLat } from '@/api/demo/contingencyplan'
import { contingencyPlanStore } from '@/store/modules/contingencyplan';
const contingencyPlanStoreVal = contingencyPlanStore();
const airPortStoreVal = airPortStore(); const airPortStoreVal = airPortStore();
@ -1682,6 +1686,24 @@
hikversionShow.value = false; hikversionShow.value = false;
changeButton("应急响应") changeButton("应急响应")
let params = {
lng: clueInfo.value.lng,
lat: clueInfo.value.lat,
}
LoadClueInfoByLngLat(params).then(async res => {
if(res.length > 0){
let resultData = res[0]
if(resultData.Attachment){
const res = await fetch(`${VITE_GLOB_API_URL}/${resultData.Attachment}`)
if (!res.ok) {
console.error('下载失败', res.status)
return
}
const data = await res.json()
contingencyPlanStoreVal.reloadData(data)
}
}
})
} }
const changeButton = (type) => { const changeButton = (type) => {

View File

@ -68,6 +68,11 @@ const goflyaddress=(e)=>{
}) })
entityArr.value = [] entityArr.value = []
} }
if(e.state == '离线'){
return message.warning('当前人员离线')
}else if(e.lng == null || e.lat == null || e.lng == 0 || e.lat == 0){
return message.warning('人员位置异常')
}
handlerAddEntity(e) handlerAddEntity(e)
} }
// Entity // Entity

View File

@ -1,4 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_APP_RTMP_URL, VITE_GLOB_APP_FLV_URL, VITE_GLOB_SRS_API_URL } = getAppEnvConfig();
export const airPortStore = defineStore({ export const airPortStore = defineStore({
id: 'airport', id: 'airport',
@ -17,8 +19,11 @@ export const airPortStore = defineStore({
video_id: null, video_id: null,
}, },
liveInfo: { liveInfo: {
rtmp: 'rtmp://wrj.wisestcity.com:6019/live/', rtmp: `${VITE_GLOB_APP_RTMP_URL}/live/`,
url: 'https://wrj.wisestcity.com:6012/live/', url: `${VITE_GLOB_APP_FLV_URL}/live/`,
getUrl: `${VITE_GLOB_SRS_API_URL}/`,
// rtmp: 'rtmp://175.27.168.120:6019/live/',
// url: 'http://175.27.168.120:6012/live/',
// rtmp: 'rtmp://box.wisestcity.com:1935/live/', // rtmp: 'rtmp://box.wisestcity.com:1935/live/',
// url: 'http://box.wisestcity.com:8081/live/', // url: 'http://box.wisestcity.com:8081/live/',
// rtmp: 'http://wrj.wisestcity.com:5005/rtc/v1/whip/?app=live&stream=', // rtmp: 'http://wrj.wisestcity.com:5005/rtc/v1/whip/?app=live&stream=',

View File

@ -0,0 +1,35 @@
import { defineStore } from 'pinia';
import * as mars3d from 'mars3d';
interface ContingencyPlanState {
contingencyPlanLayer: mars3d.layer.GeoJsonLayer | null
}
export const contingencyPlanStore = defineStore({
id: 'contingencyPlan',
state: ():ContingencyPlanState => ({
contingencyPlanLayer: null,
}),
actions: {
setLayer() {
this.contingencyPlanLayer = new mars3d.layer.GeoJsonLayer({
name: 'fire-plan-layer',
clampToGround: true
})
window.globalMap.addLayer(this.contingencyPlanLayer);
},
clearData(){
this.contingencyPlanLayer?.clear()
},
reloadData(data){
this.contingencyPlanLayer?.load({
data: data
})
this.contingencyPlanLayer?.flyTo({
scale: 1.5
})
},
getLayer(){
return this.contingencyPlanLayer
}
}
})

View File

@ -40,6 +40,11 @@ export function getAppEnvConfig() {
VITE_GLOB_APP_TECHINICAL_SUPPORT, VITE_GLOB_APP_TECHINICAL_SUPPORT,
VITE_GLOB_APP_VERSIONS, VITE_GLOB_APP_VERSIONS,
VITE_GLOB_API_URL_SITUATION, VITE_GLOB_API_URL_SITUATION,
VITE_GLOB_MQTT_URL,
VITE_GLOB_MQTT_PORT,
VITE_GLOB_APP_RTMP_URL,
VITE_GLOB_APP_FLV_URL,
VITE_GLOB_SRS_API_URL,
VITE_GLOB_FILE_PREVIEW, VITE_GLOB_FILE_PREVIEW,
VITE_GLOB_GEOSERVER_BASE_URL, VITE_GLOB_GEOSERVER_BASE_URL,
VITE_GLOB_COFFEE_API_URL, VITE_GLOB_COFFEE_API_URL,
@ -63,6 +68,11 @@ export function getAppEnvConfig() {
VITE_GLOB_FILE_PREVIEW, VITE_GLOB_FILE_PREVIEW,
VITE_GLOB_GEOSERVER_BASE_URL, VITE_GLOB_GEOSERVER_BASE_URL,
VITE_GLOB_COFFEE_API_URL, VITE_GLOB_COFFEE_API_URL,
VITE_GLOB_MQTT_URL,
VITE_GLOB_MQTT_PORT,
VITE_GLOB_APP_RTMP_URL,
VITE_GLOB_APP_FLV_URL,
VITE_GLOB_SRS_API_URL,
}; };
} }

View File

@ -3,6 +3,8 @@ import { useMessage } from '@/hooks/web/useMessage';
import { getRedisUser, addOrUpdateRedisUser } from '@/api/demo/airportMaintenance'; import { getRedisUser, addOrUpdateRedisUser } from '@/api/demo/airportMaintenance';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { timestampToFormattedDate } from '@/utils/index'; import { timestampToFormattedDate } from '@/utils/index';
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_MQTT_URL, VITE_GLOB_MQTT_PORT } = getAppEnvConfig();
const userStore = useUserStore(); const userStore = useUserStore();
const userInfo = userStore.getUserInfo; const userInfo = userStore.getUserInfo;
@ -12,9 +14,9 @@ const { createMessage } = useMessage();
const seizeClientId = 'mqtt_client_1581F8HGX254V00A0BUY_seize'; const seizeClientId = 'mqtt_client_1581F8HGX254V00A0BUY_seize';
const connection = { const connection = {
protocol: 'ws', protocol: 'ws',
host: 'wrj.wisestcity.com', host: VITE_GLOB_MQTT_URL,
// server less服务器只有两种协议mqtts: 8883; wss: 8084 // server less服务器只有两种协议mqtts: 8883; wss: 8084
port: 6010, port: VITE_GLOB_MQTT_PORT,
endpoint: '/mqtt', endpoint: '/mqtt',
// for more options, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options // for more options, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
clean: true, clean: true,

View File

@ -15,7 +15,7 @@ export const columns: BasicColumn[] = [
{ {
title: '审核状态', title: '审核状态',
dataIndex: 'state', dataIndex: 'state',
width: 80, width: 90,
customRender: ({ record }) => { customRender: ({ record }) => {
const status = record.state; const status = record.state;
let color = ''; let color = '';
@ -36,10 +36,12 @@ export const columns: BasicColumn[] = [
{ {
title: '负责人', title: '负责人',
dataIndex: 'director', dataIndex: 'director',
width: 150,
}, },
{ {
title: '负责人电话', title: '负责人电话',
dataIndex: 'phone', dataIndex: 'phone',
width: 130,
}, },
]; ];

View File

@ -1,35 +1,17 @@
<template> <template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit"> <BasicModal v-bind="$attrs" @register="registerModal" title='编辑' @ok="handleSubmit">
<BasicForm @register="registerForm"> <BasicForm @register="registerForm">
<template #areaId="{ model, field }">
<a-tree-select
show-search
style="width: 100%"
v-model:value="model[field]"
:tree-data="treeData"
:field-names="{ label: 'name', value: 'id' }"
placeholder="请选择"
allow-clear
multiple
/>
</template>
<template #time="{ model, field }"> <template #time="{ model, field }">
<div> <div>
<div class="flex mt-1" v-for="(item, index) in timeslot" :key="index">
<a-time-picker <a-time-picker
placeholder="开始时间" placeholder="开始时间"
@change="(time, timeString) => beginTimeChange(time, timeString, index)" v-model:value="timeSlot.beginTime"
v-model:value="item.beginTime"
/> />
~ ~
<a-time-picker <a-time-picker
placeholder="结束时间" placeholder="结束时间"
@change="(time, timeString) => endTimeChange(time, timeString, index)" v-model:value="timeSlot.endTime"
v-model:value="item.endTime"
/> />
<CloseCircleOutlined style="margin-left: 10px" @click="delTime(index)" />
</div>
<a-button type="primary" style="margin-top: 10px" @click="addTime"></a-button>
</div> </div>
</template> </template>
</BasicForm> </BasicForm>
@ -43,16 +25,19 @@
import { CloseCircleOutlined } from '@ant-design/icons-vue'; import { CloseCircleOutlined } from '@ant-design/icons-vue';
import { addRole, updateRole, getDeptList } from '@/api/demo/system'; import { addRole, updateRole, getDeptList } from '@/api/demo/system';
import { useMessage } from '@/hooks/web/useMessage'; import { useMessage } from '@/hooks/web/useMessage';
import moment from 'moment'; import dayjs from 'dayjs';
import { AddOrUpdateTimeSolt } from '@/api/demo/forestranger'
import { message } from 'ant-design-vue';
const { createMessage } = useMessage(); const { createMessage } = useMessage();
const treeData: any = ref([]); const timeSlot: any = ref({
const timeslot: any = ref([]); beginTime: '',
const timeList: any = ref([]); endTime: '',
});
const updateData = ref({})
defineOptions({ name: 'DeptModal' }); defineOptions({ name: 'DeptModal' });
onMounted(() => { onMounted(() => {
getTreeList();
}); });
const emit = defineEmits(['success', 'register']); const emit = defineEmits(['success', 'register']);
@ -66,74 +51,53 @@
}); });
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
isUpdate.value = data.isUpdate
updateData.value = data.data
resetFields(); resetFields();
setModalProps({ confirmLoading: false }); setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate; setFieldsValue({
...data.data,
if (unref(isUpdate)) { });
setFieldsValue({ if(data.data.timeSlotData){
...data.record, let timeSlotList = data.data.timeSlotData.timeSlot.split('-')
}); timeSlot.value.beginTime = dayjs(timeSlotList[0], 'HH:mm:ss')
timeSlot.value.endTime = dayjs(timeSlotList[1], 'HH:mm:ss')
}else{
timeSlot.value.beginTime = null
timeSlot.value.endTime = null
} }
}); });
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
async function handleSubmit() { async function handleSubmit() {
try { try {
const values = await validate(); const values = await validate();
let query = values; console.log('values',values)
// console.log('updateData.value',updateData.value)
if (!unref(isUpdate)) { let query
const data = await addRole(query); if(isUpdate.value){
if (data) { query = {
setModalProps({ confirmLoading: true }); id: updateData.value.timeSlotData.id,
// TODO custom api createId: updateData.value.id,
closeModal(); timeSlot: `${dayjs(timeSlot.value.beginTime).format('HH:mm:ss')}-${dayjs(timeSlot.value.endTime).format('HH:mm:ss')}`
emit('success');
return createMessage.success('新增成功');
} else {
return createMessage.error('新增失败');
} }
}else{
query = {
createId: updateData.value.id,
timeSlot: `${dayjs(timeSlot.value.beginTime).format('HH:mm:ss')}-${dayjs(timeSlot.value.endTime).format('HH:mm:ss')}`
}
}
const data = await AddOrUpdateTimeSolt(query);
if (data) {
setModalProps({ confirmLoading: true });
closeModal();
emit('success');
return createMessage.success('编辑成功');
} else { } else {
const data = await updateRole(query); return createMessage.error('编辑失败');
if (data) {
setModalProps({ confirmLoading: true });
// TODO custom api
closeModal();
emit('success');
return createMessage.success('编辑成功');
} else {
return createMessage.error('编辑失败');
}
} }
} finally { } finally {
setModalProps({ confirmLoading: false }); setModalProps({ confirmLoading: false });
} }
} }
const getTreeList = async () => {
getDeptList().then((res) => {
treeData.value = res;
});
};
const delTime = (index) => {
timeslot.value.splice(index, 1);
timeList.value.splice(index, 1);
};
const addTime = () => {
timeslot.value.push({
beginTime: '',
endTime: '',
});
timeList.value.push({
beginTime: '',
endTime: '',
});
};
const beginTimeChange = (time, timeString, index) => {
timeList.value[index].beginTime = timeString;
};
const endTimeChange = (time, timeString, index) => {
timeList.value[index].endTime = timeString;
};
</script> </script>

View File

@ -41,40 +41,19 @@ export const formSchema: FormSchema[] = [
{ {
field: 'name', field: 'name',
label: '人员姓名', label: '人员姓名',
required: true,
component: 'Input', component: 'Input',
componentProps: {
disabled: true,
},
}, },
{ {
field: 'account', field: 'account',
label: '账号/手机号', label: '账号/手机号',
required: true,
component: 'Input', component: 'Input',
},
{
field: 'sex',
component: 'RadioGroup',
label: '人员性别',
colProps: {
span: 8,
},
componentProps: { componentProps: {
options: [ disabled: true,
{
label: '男',
value: 0,
},
{
label: '女',
value: 1,
},
],
}, },
}, },
{
field: 'areaId',
label: '所属机构',
slot: 'areaId',
},
{ {
field: 'time', field: 'time',
label: '打卡时间', label: '打卡时间',

View File

@ -13,6 +13,7 @@
import { BasicTable, useTable } from '@/components/Table'; import { BasicTable, useTable } from '@/components/Table';
import { getRoleListByPage, deleteRole } from '@/api/demo/system'; import { getRoleListByPage, deleteRole } from '@/api/demo/system';
import { LoadTimeSoltByUserId } from '@/api/demo/forestranger'
import { useMessage } from '@/hooks/web/useMessage'; import { useMessage } from '@/hooks/web/useMessage';
import { useModal } from '@/components/Modal'; import { useModal } from '@/components/Modal';
@ -72,15 +73,23 @@
}); });
} }
function handleEdit() { async function handleEdit() {
let rows = getSelectRows(); let rows = getSelectRows();
if (rows.length == 0) { if (rows.length == 0) {
return createMessage.warn('请勾选一个角色进行编辑'); return createMessage.warn('请勾选一个角色进行编辑');
} }
const record = rows[0]; const record = rows[0];
let params = {
id: record.id
}
let result = await LoadTimeSoltByUserId(params)
let data = {
...record,
timeSlotData: result
}
openRoleModal(true, { openRoleModal(true, {
record, data,
isUpdate: true, isUpdate: result? true: false,
}); });
} }

View File

@ -13,8 +13,8 @@
/> />
<div class="form-button"> <div class="form-button">
<a-button type="primary" @click="getTaskList"></a-button> <a-button type="primary" @click="getTaskList"></a-button>
<a-button type="primary" @click="toStatic"></a-button> <!-- <a-button type="primary" @click="toStatic"></a-button>
<a-button type="primary" @click="toInspection"></a-button> <a-button type="primary" @click="toInspection"></a-button> -->
</div> </div>
</div> </div>
<div class="table-data"> <div class="table-data">

View File

@ -11,26 +11,17 @@
<a-divider orientation="left">打卡点信息</a-divider> <a-divider orientation="left">打卡点信息</a-divider>
<a-descriptions class="margin-top" :column="1" :size="'mini'" border> <a-descriptions class="margin-top" :column="1" :size="'mini'" border>
<a-descriptions-item> <a-descriptions-item>
<template v-slot:label> <BankOutlined style="margin-right: 20px;"/>
<BankOutlined /> <span style="color: rgba(0,0,0,0.6);">{{ itemData.pointname }}</span>
打卡点名称
</template>
{{ itemData.pointname }}
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item> <a-descriptions-item>
<template v-slot:label> <HistoryOutlined style="margin-right: 20px;"/>
<HistoryOutlined /> <span style="color: rgba(0,0,0,0.6);">{{ itemData.createtime }}</span>
创建时间
</template>
{{ itemData.createtime }}
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item> <a-descriptions-item>
<template v-slot:label> <EnvironmentOutlined style="margin-right: 20px;"/>
<EnvironmentOutlined /> <span style="color: rgba(0,0,0,0.6);">{{ itemData.lng }},&nbsp;&nbsp;{{ itemData.lat }}</span>
打卡点位置
</template>
{{ itemData.lng }},{{ itemData.lat }}&nbsp;&nbsp;
<!-- <el-button type="primary" size="mini" round icon="el-icon-location-outline" @click="lookClockInfo(currentClockInfo)"></el-button> --> <!-- <el-button type="primary" size="mini" round icon="el-icon-location-outline" @click="lookClockInfo(currentClockInfo)"></el-button> -->
</a-descriptions-item> </a-descriptions-item>
</a-descriptions> </a-descriptions>

View File

@ -74,6 +74,7 @@
import { useMessage } from '@/hooks/web/useMessage'; import { useMessage } from '@/hooks/web/useMessage';
import { getPatrolPointByTimeSubsection } from '@/api/firegrid/patrol'; import { getPatrolPointByTimeSubsection } from '@/api/firegrid/patrol';
import { getDeptList } from '@/api/demo/system'; import { getDeptList } from '@/api/demo/system';
import { message } from 'ant-design-vue';
const { createMessage } = useMessage(); const { createMessage } = useMessage();
defineOptions({ name: 'DeptModal' }); defineOptions({ name: 'DeptModal' });
@ -92,7 +93,8 @@
// //
title: '巡检列表', title: '巡检列表',
// //
dataSource: [], api: getPointUserOnLine,
// dataSource: [],
// BasicColumn[] // BasicColumn[]
columns: InspectionColumns, columns: InspectionColumns,
rowKey: 'id', rowKey: 'id',
@ -108,6 +110,17 @@
handleSearchInfoFn(info) { handleSearchInfoFn(info) {
return info; return info;
}, },
beforeFetch: (params) => {
return {
...params,
...formState
}
},
afterFetch: (data) => {
onlineInfo.online = data.online;
onlineInfo.offline = data.offline;
return data.userinfo
},
actionColumn: { actionColumn: {
width: 120, width: 120,
title: '操作', title: '操作',
@ -117,6 +130,11 @@
}, },
}); });
const toPosition = (row) => { const toPosition = (row) => {
if(row.state == '离线'){
return message.warning('当前人员离线')
}else if(row.lng == null || row.lat == null || row.lng == 0 || row.lat == 0){
return message.warning('人员位置异常')
}
const lnglat = [row.lng, row.lat]; const lnglat = [row.lng, row.lat];
EventBus.emit('inspectionMoldeMap', lnglat); EventBus.emit('inspectionMoldeMap', lnglat);
}; };
@ -185,18 +203,17 @@
} }
const formState: FormState = reactive({ const formState: FormState = reactive({
isonline: '全部', isonline: '全部',
page: 1,
limit: 10,
}); });
const getLine = () => { const getLine = () => {
getPointUserOnLine(formState).then((res) => { reload()
res.items.userinfo.forEach((item) => { // getPointUserOnLine(formState).then((res) => {
item.onLineTime = friendlyDate(item.onLineTime); // res.items.userinfo.forEach((item) => {
}); // item.onLineTime = friendlyDate(item.onLineTime);
onlineInfo.online = res.items.online; // });
onlineInfo.offline = res.items.offline; // onlineInfo.online = res.items.online;
setTableData(res.items.userinfo); // onlineInfo.offline = res.items.offline;
}); // setTableData(res.items.userinfo);
// });
}; };
const friendlyDate = (time) => { const friendlyDate = (time) => {
if (time > 60) { if (time > 60) {
@ -206,7 +223,7 @@
} }
}; };
onMounted(() => { onMounted(() => {
getLine(); // getLine();
getTree(); getTree();
}); });
</script> </script>

View File

@ -37,7 +37,7 @@
</div> </div>
<div class="count-item-title"> 全部巡查总数 </div> <div class="count-item-title"> 全部巡查总数 </div>
<div class="count-item-value"> <div class="count-item-value">
{{ allData.xunchazongshu? allData.xunchazongshu.toFixed(4): 0 }} <span class="unit">千米</span> {{ allData.xunchazongshu? allData.xunchazongshu.toFixed(2): 0 }} <span class="unit">千米</span>
</div> </div>
</div> </div>