Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
This commit is contained in:
commit
07948f788c
@ -376,6 +376,10 @@ const getDetailData = async (row) => {
|
|||||||
|
|
||||||
// 打开新增设备弹窗
|
// 打开新增设备弹窗
|
||||||
const openAddEquipmentModel = () => {
|
const openAddEquipmentModel = () => {
|
||||||
|
if (!selectedYHZData.value) {
|
||||||
|
ElMessage.error('请先选择养护站');
|
||||||
|
return;
|
||||||
|
}
|
||||||
model.title = `新增设备`;
|
model.title = `新增设备`;
|
||||||
model.content = AddDialog;
|
model.content = AddDialog;
|
||||||
const extraData = {
|
const extraData = {
|
||||||
|
|||||||
@ -50,7 +50,6 @@
|
|||||||
<div class="form-box">
|
<div class="form-box">
|
||||||
<div class="event-box">
|
<div class="event-box">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="selectedYHZData"
|
|
||||||
type="primary"
|
type="primary"
|
||||||
size="large"
|
size="large"
|
||||||
@click="script.openAddEquipmentModel"
|
@click="script.openAddEquipmentModel"
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
detailData.material?.wzmc
|
detailData.material?.wzmc
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="余量: ">{{
|
<el-descriptions-item label="余量: ">{{
|
||||||
detailData.material?.ye + ' ' + detailData.material?.dw
|
detailData.material?.ye + " " + detailData.material?.dw
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="所属服务站: ">{{
|
<el-descriptions-item label="所属服务站: ">{{
|
||||||
detailData.material?.yhzMc
|
detailData.material?.yhzMc
|
||||||
@ -20,6 +20,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" style="position: relative">
|
<el-col :span="12" style="position: relative">
|
||||||
<el-image
|
<el-image
|
||||||
|
v-if="detailData.photos?.length > 0"
|
||||||
style="
|
style="
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
max-height: 180px;
|
max-height: 180px;
|
||||||
@ -34,6 +35,9 @@
|
|||||||
show-progresss
|
show-progresss
|
||||||
fit="cover"
|
fit="cover"
|
||||||
/>
|
/>
|
||||||
|
<div v-else class="no-photo">
|
||||||
|
<span>暂无图片</span>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -81,4 +85,15 @@ const props = defineProps({
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
}
|
}
|
||||||
|
.no-photo {
|
||||||
|
width: 180px;
|
||||||
|
height: 180px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -376,6 +376,10 @@ const getDetailData = async (row) => {
|
|||||||
|
|
||||||
// 打开新增物资弹窗
|
// 打开新增物资弹窗
|
||||||
const openAddModel = () => {
|
const openAddModel = () => {
|
||||||
|
if(!yhzid.value){
|
||||||
|
ElMessage.error('请先选择养护站');
|
||||||
|
return;
|
||||||
|
}
|
||||||
model.title = `新增物资`;
|
model.title = `新增物资`;
|
||||||
model.content = AddDialog;
|
model.content = AddDialog;
|
||||||
resetForm(); // 重置表单
|
resetForm(); // 重置表单
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-box">
|
<div class="form-box">
|
||||||
<div class="event-box">
|
<div class="event-box">
|
||||||
<el-button v-if="script.yhzid.value" type="primary" size="large" @click="script.openAddModel"
|
<el-button type="primary" size="large" @click="script.openAddModel"
|
||||||
>新增物资</el-button
|
>新增物资</el-button
|
||||||
>
|
>
|
||||||
<el-button type="info" size="large" @click="script.handelExport"
|
<el-button type="info" size="large" @click="script.handelExport"
|
||||||
|
|||||||
@ -0,0 +1,141 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="area-title-block">
|
||||||
|
所属服务站: <span class="title-text">{{ stationName }}</span>
|
||||||
|
</div>
|
||||||
|
<el-form :model="form" class="equipment-form">
|
||||||
|
<!-- 第一行:设备名称、设备大类、设备类型 -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备名称" prop="sbmc">
|
||||||
|
<el-input v-model="form.sbmc" maxlength="20" placeholder="请输入设备名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备大类" prop="sbdl">
|
||||||
|
<InputSelect v-model="form.sbdl" placeholder="请选择" :options="options['sbdl']" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备类型" prop="sblx">
|
||||||
|
<InputSelect v-model="form.sblx" placeholder="请选择" :options="options['sblx']" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 第二行:设备型号、设备经度(只读)、设备纬度(只读) -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备型号" prop="sbxh">
|
||||||
|
<el-input v-model="form.sbxh" placeholder="请输入设备型号" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备经度" prop="jd">
|
||||||
|
<el-input v-model="form.jd" placeholder="自动填充服务站经纬度" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="设备纬度" prop="wd">
|
||||||
|
<el-input v-model="form.wd" placeholder="自动填充服务站经纬度" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 第三行:购置日期、购买费用(万元)、应急设备 -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="购置日期" prop="gzrq">
|
||||||
|
<el-date-picker v-model="form.gzrq" type="date" placeholder="请选择购置日期" style="width: 100%;" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="购买费用(万元)" prop="gmfy">
|
||||||
|
<el-input-number v-model="form.gmfy" :min="0" controls-position="right" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="应急设备" prop="sfyjsb">
|
||||||
|
<el-select v-model="form.sfyjsb" placeholder="请选择">
|
||||||
|
<el-option label="是" value="是" />
|
||||||
|
<el-option label="否" value="否" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 第四行:辐射范围、生产商、纳入市级补助范围 -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="辐射范围" prop="fsfw">
|
||||||
|
<el-input v-model="form.fsfw" placeholder="请输入辐射范围" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="生产商" prop="sccj">
|
||||||
|
<el-input v-model="form.sccj" placeholder="请输入生产商" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="纳入市级补助范围" prop="sfnrsjbz">
|
||||||
|
<el-select v-model="form.sfnrsjbz" placeholder="请选择">
|
||||||
|
<el-option label="是" value="是" />
|
||||||
|
<el-option label="否" value="否" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import InputSelect from "@/component/InputSelect/InputSelect.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
// 养护站数据
|
||||||
|
basicData: {
|
||||||
|
type: [Object, null],
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const options = ref({
|
||||||
|
'sbdl': [
|
||||||
|
{ label: "示例大类1", value: "示例大类1" },
|
||||||
|
{ label: "示例大类2", value: "示例大类2" },
|
||||||
|
],
|
||||||
|
"sblx": [
|
||||||
|
{ label: "示例类型1", value: "示例类型1" },
|
||||||
|
{ label: "示例类型2", value: "示例类型2" },
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const stationName = computed(() => {
|
||||||
|
return props.basicData ? props.basicData.mc : ''
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.area-title-block {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
color: rgb(10, 124, 255);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.equipment-form) {
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail-container">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
label-position="right"
|
||||||
|
label-width="150px"
|
||||||
|
style="max-height: 60vh; overflow-y: auto; padding-right: 50px"
|
||||||
|
>
|
||||||
|
<el-form-item label="所属服务站:">
|
||||||
|
<span>{{ basicData.mc }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="物资名称:">
|
||||||
|
<el-input
|
||||||
|
maxlength="20"
|
||||||
|
show-word-limit
|
||||||
|
v-model="form.material.wzmc"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数量与单位:">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-input
|
||||||
|
v-model="form.material.sl"
|
||||||
|
type="number"
|
||||||
|
placeholder="请输入数量"
|
||||||
|
></el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-select
|
||||||
|
v-model="form.material.dw"
|
||||||
|
filterable
|
||||||
|
allow-create
|
||||||
|
clearable
|
||||||
|
placeholder="选择单位"
|
||||||
|
>
|
||||||
|
<el-option label="个" value="个"></el-option>
|
||||||
|
<el-option label="包" value="包"></el-option>
|
||||||
|
<el-option label="盒" value="盒"></el-option>
|
||||||
|
<el-option label="桶" value="桶"></el-option>
|
||||||
|
<el-option label="箱" value="箱"></el-option>
|
||||||
|
<el-option label="袋" value="袋"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设备经度:">
|
||||||
|
<span>{{ form.material.jd }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设备纬度:">
|
||||||
|
<span>{{ form.material.wd }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
const formRef = ref(null);
|
||||||
|
defineExpose({ formRef });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
basicData:{
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
@ -6,7 +6,7 @@
|
|||||||
label-width="150px"
|
label-width="150px"
|
||||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px"
|
style="max-height: 60vh; overflow-y: auto; padding-right: 50px"
|
||||||
>
|
>
|
||||||
<el-form-item label="人员:">
|
<el-form-item label="负责人:">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="ryxx"
|
v-model="ryxx"
|
||||||
filterable
|
filterable
|
||||||
@ -26,26 +26,23 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="岗位:">
|
<el-form-item label="负责人添加经纬度:">
|
||||||
<el-input v-model="form.gw" />
|
<el-select v-model="form.sfjwd">
|
||||||
</el-form-item>
|
<el-option label="是" value="是"></el-option>
|
||||||
|
<el-option label="否" value="否"></el-option>
|
||||||
<el-form-item label="养护站:">
|
|
||||||
<el-input disabled v-model="yhzdata.mc" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="人员角色:">
|
|
||||||
<el-select v-model="form.ryjs" placeholder="请选择人员角色">
|
|
||||||
<el-option label="负责人" value="1"></el-option>
|
|
||||||
<el-option label="普通工作人员" value="2"></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="站点经纬度:">
|
||||||
|
<el-input v-model="form.jwd" />
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from "vue";
|
import { ref, onMounted, watch } from "vue";
|
||||||
|
import { request } from "@/utils/request";
|
||||||
const formRef = ref(null);
|
const formRef = ref(null);
|
||||||
defineExpose({ formRef });
|
defineExpose({ formRef });
|
||||||
|
|
||||||
@ -54,19 +51,37 @@ const props = defineProps({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
getUserList: {
|
|
||||||
type: Function,
|
|
||||||
default: () => () => {},
|
|
||||||
},
|
|
||||||
yhzdata: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ryxx = ref("");
|
const ryxx = ref("");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const selectOptions = ref([]);
|
const selectOptions = ref([]);
|
||||||
|
|
||||||
|
// 根据用户信息 查询角色列表
|
||||||
|
const getUserList = async (key) => {
|
||||||
|
try {
|
||||||
|
const keyword = key;
|
||||||
|
let url = "";
|
||||||
|
if (keyword) {
|
||||||
|
url = `/snow-ops-platform/yhzry/getUserByKey?key=${keyword}`;
|
||||||
|
} else {
|
||||||
|
url = `/snow-ops-platform/yhzry/getUserByKey?key=`;
|
||||||
|
}
|
||||||
|
const res = await request({
|
||||||
|
url: url,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
return res.data;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 选择人员筛选
|
// 选择人员筛选
|
||||||
const remoteMethod = async (query) => {
|
const remoteMethod = async (query) => {
|
||||||
if (query === "") {
|
if (query === "") {
|
||||||
@ -74,7 +89,7 @@ const remoteMethod = async (query) => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await props.getUserList(query);
|
const res = await getUserList(query);
|
||||||
if (res) {
|
if (res) {
|
||||||
selectOptions.value = res;
|
selectOptions.value = res;
|
||||||
}
|
}
|
||||||
@ -1,37 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="detail-container">
|
|
||||||
<el-form
|
|
||||||
label-position="right"
|
|
||||||
label-width="150px"
|
|
||||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px"
|
|
||||||
>
|
|
||||||
<el-form-item label="人员名称:">
|
|
||||||
<el-input disabled v-model="detailData.xm" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="岗位:">
|
|
||||||
<el-input disabled v-model="detailData.gw" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="手机号码:">
|
|
||||||
<el-input disabled v-model="detailData.sjhm" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="人员角色:">
|
|
||||||
<el-input disabled :value="detailData.ryjs === 1 ? '管理员' : '普通用户'" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="创建时间:">
|
|
||||||
<el-input disabled v-model="detailData.cjsj" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
detailData: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="detail-container">
|
|
||||||
<el-form
|
|
||||||
ref="formRef"
|
|
||||||
label-position="right"
|
|
||||||
label-width="150px"
|
|
||||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px"
|
|
||||||
>
|
|
||||||
<el-form-item label="人员名称:">
|
|
||||||
<el-input disabled v-model="form.xm" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="岗位:">
|
|
||||||
<el-input v-model="form.gw" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="手机号码:">
|
|
||||||
<el-input disabled v-model="form.sjhm" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="人员角色:" prop="ryjs">
|
|
||||||
<el-select v-model="form.ryjs" placeholder="请选择角色">
|
|
||||||
<el-option label="负责人" :value="1" />
|
|
||||||
<el-option label="普通工作人员" :value="2" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="创建时间:">
|
|
||||||
<el-input disabled v-model="form.cjsj" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from "vue";
|
|
||||||
const formRef = ref(null);
|
|
||||||
defineExpose({ formRef });
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
form: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
@ -2,34 +2,84 @@
|
|||||||
<div class="detail-container">
|
<div class="detail-container">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-descriptions title="基础信息" :column="3">
|
<el-descriptions title="基础信息" :column="3">
|
||||||
<el-descriptions-item label="服务站名称">{{
|
<el-descriptions-item label="服务站名称:">{{
|
||||||
basicData.mc
|
basicData.mc
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="服务站经度">{{
|
<el-descriptions-item label="服务站经度:">{{
|
||||||
basicData.jd
|
basicData.jd
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="服务站纬度">{{
|
<el-descriptions-item label="服务站纬度:">{{
|
||||||
basicData.wd
|
basicData.wd
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="设备数">{{}}</el-descriptions-item>
|
<el-descriptions-item label="设备数:">{{
|
||||||
<el-descriptions-item label="物资数">{{}}</el-descriptions-item>
|
basicData.sbsl
|
||||||
<el-descriptions-item label="人员数">{{}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="创建日期">{{}}</el-descriptions-item>
|
<el-descriptions-item label="物资数:">{{
|
||||||
|
basicData.wzsl
|
||||||
|
}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="人员数:">{{
|
||||||
|
basicData.rysl
|
||||||
|
}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="创建日期:">{{
|
||||||
|
basicData.createTime
|
||||||
|
}}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-descriptions title="配置信息" :column="3"> </el-descriptions>
|
<el-descriptions title="配置信息" :column="3"> </el-descriptions>
|
||||||
<el-tabs v-model="activeTab" class="demo-tabs" @tab-click="handleClick">
|
<el-tabs v-model="activeTab" class="demo-tabs" @tab-click="handleClick">
|
||||||
<el-tab-pane label="人员信息" name="people">人员信息</el-tab-pane>
|
<div class="button-container">
|
||||||
<el-tab-pane label="物资信息" name="second">物资信息</el-tab-pane>
|
<el-button type="primary" @click="handleAdd">新增</el-button>
|
||||||
<el-tab-pane label="设备信息" name="third">设备信息</el-tab-pane>
|
</div>
|
||||||
|
<el-tab-pane label="人员信息" name="people">
|
||||||
|
<DynamicTable
|
||||||
|
:dataSource="peopleList"
|
||||||
|
:columns="columns()"
|
||||||
|
:autoHeight="true"
|
||||||
|
:pagination="pagination"
|
||||||
|
></DynamicTable>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="物资信息" name="material">
|
||||||
|
<DynamicTable
|
||||||
|
:dataSource="materialList"
|
||||||
|
:columns="columns()"
|
||||||
|
:autoHeight="true"
|
||||||
|
:pagination="pagination"
|
||||||
|
></DynamicTable>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="设备信息" name="equipment">
|
||||||
|
<DynamicTable
|
||||||
|
:dataSource="equipmentList"
|
||||||
|
:columns="columns()"
|
||||||
|
:autoHeight="true"
|
||||||
|
:pagination="pagination"
|
||||||
|
></DynamicTable>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<MyDialog
|
||||||
|
v-model="modelVisible"
|
||||||
|
:title="model?.title"
|
||||||
|
:dynamicComponent="model?.content"
|
||||||
|
:component-props="model?.props"
|
||||||
|
:onConfirm="model?.onConfirm"
|
||||||
|
:onCancel="model?.onCancel"
|
||||||
|
ref="dialogRef"
|
||||||
|
:width="model?.width"
|
||||||
|
>
|
||||||
|
</MyDialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||||
|
import DynamicTable from "../../component/DynamicTable";
|
||||||
|
import MyDialog from "../../component/MyDialog";
|
||||||
|
import { request } from "@/utils/request";
|
||||||
|
import { render } from "less";
|
||||||
|
import PersonAddDialog from "./component/PersonAddDialog.vue";
|
||||||
|
import MaterialAddDialog from "./component/MaterialAddDialog.vue";
|
||||||
|
import EquipmentAddDialog from "./component/EquipmentAddDialog.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
basicData: {
|
basicData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -37,9 +87,427 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
pageSizes: [10, 20, 50],
|
||||||
|
layout: "prev, pager, next, jumper",
|
||||||
|
onChange: (page, pageSize) => {
|
||||||
|
pagination.current = page;
|
||||||
|
pagination.pageSize = pageSize;
|
||||||
|
if (activeTab.value === "people") {
|
||||||
|
getPeopleList();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}); // 表格分页
|
||||||
|
|
||||||
|
const columns = () => {
|
||||||
|
switch (activeTab.value) {
|
||||||
|
case "people":
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
width: "100px",
|
||||||
|
label: "序号",
|
||||||
|
render: (...args) => {
|
||||||
|
return () => {
|
||||||
|
const actualIndex =
|
||||||
|
(pagination.current - 1) * pagination.pageSize + args[2] + 1;
|
||||||
|
return h("div", {}, actualIndex);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "xm",
|
||||||
|
label: "姓名",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sjhm",
|
||||||
|
label: "手机号",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "人员角色",
|
||||||
|
render: (row) => () => {
|
||||||
|
const role = Number(row.ryjs);
|
||||||
|
const config = {
|
||||||
|
1: { type: "danger", text: "负责人" },
|
||||||
|
2: { type: "success", text: "普通工作人员" },
|
||||||
|
}[role] || { type: "info", text: "未知角色" };
|
||||||
|
|
||||||
|
return h(
|
||||||
|
ElTag,
|
||||||
|
{
|
||||||
|
type: config.type,
|
||||||
|
style: { margin: "2px" },
|
||||||
|
},
|
||||||
|
() => config.text
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
case "material":
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
width: "100px",
|
||||||
|
label: "序号",
|
||||||
|
render: (...args) => {
|
||||||
|
return () => {
|
||||||
|
const actualIndex =
|
||||||
|
(pagination.current - 1) * pagination.pageSize + args[2] + 1;
|
||||||
|
return h("div", {}, actualIndex);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "wzmc",
|
||||||
|
label: "物资名称",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "ye",
|
||||||
|
label: "余量",
|
||||||
|
render: (row) => () => {
|
||||||
|
return h("span", {}, row.ye + " " + row.dw);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "fzr",
|
||||||
|
label: "负责人",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "rkrq",
|
||||||
|
label: "入库日期",
|
||||||
|
render: (row) => () => {
|
||||||
|
return h("span", row.rkrq?.substring(0, 10));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
case "equipment":
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
width: "100px",
|
||||||
|
label: "序号",
|
||||||
|
render: (...args) => {
|
||||||
|
return () => {
|
||||||
|
const actualIndex =
|
||||||
|
(pagination.current - 1) * pagination.pageSize + args[2] + 1;
|
||||||
|
return h("div", {}, actualIndex);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sbmc",
|
||||||
|
label: "设备名称",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sbxh",
|
||||||
|
label: "设备型号",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sbbh",
|
||||||
|
label: "设备编号",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sbdl",
|
||||||
|
label: "设备大类",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "sblx",
|
||||||
|
label: "设备类型",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "gzrq",
|
||||||
|
label: "购置日期",
|
||||||
|
render: (row) => () => {
|
||||||
|
return h("span", row.gzrq?.substring(0, 10));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getPeopleList();
|
||||||
|
});
|
||||||
|
|
||||||
|
const peopleList = ref([]); // 人员列表
|
||||||
|
const materialList = ref([]); // 物资列表
|
||||||
|
const equipmentList = ref([]); // 设备列表
|
||||||
|
|
||||||
const activeTab = ref("people");
|
const activeTab = ref("people");
|
||||||
|
|
||||||
|
// 查询养护站人员列表
|
||||||
|
const getPeopleList = async () => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
yhzid: Number(props.basicData.id),
|
||||||
|
};
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yhzry/list",
|
||||||
|
method: "get",
|
||||||
|
params: data,
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
pagination.total = res.data.total;
|
||||||
|
peopleList.value = res.data.records;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询养护站物资列表
|
||||||
|
const getMaterialList = async () => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
yhzid: Number(props.basicData.id),
|
||||||
|
};
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yjwz/list",
|
||||||
|
method: "get",
|
||||||
|
params: data,
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
pagination.total = res.data.total;
|
||||||
|
materialList.value = res.data.records;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询养护站设备列表
|
||||||
|
const getEquipmentList = async () => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
yhzid: Number(props.basicData.id),
|
||||||
|
};
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yjsb/list",
|
||||||
|
method: "get",
|
||||||
|
params: data,
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
pagination.total = res.data.total;
|
||||||
|
equipmentList.value = res.data.records;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleClick = (tab, event) => {
|
const handleClick = (tab, event) => {
|
||||||
console.log("tab", tab, "event", event);
|
pagination.current = 1;
|
||||||
|
switch (tab.props.name) {
|
||||||
|
case "people":
|
||||||
|
getPeopleList();
|
||||||
|
break;
|
||||||
|
case "material":
|
||||||
|
getMaterialList();
|
||||||
|
break;
|
||||||
|
case "equipment":
|
||||||
|
getEquipmentList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增相关
|
||||||
|
const peopleForm = reactive({});
|
||||||
|
const INIT_FORM_people = {
|
||||||
|
userId: "",
|
||||||
|
ryjs: 1,
|
||||||
|
yhzid: props.basicData.id,
|
||||||
|
sjhm: "",
|
||||||
|
xm: "",
|
||||||
|
sfjwd: "",
|
||||||
|
jwd: "",
|
||||||
|
};
|
||||||
|
const materialForm = reactive({});
|
||||||
|
const INIT_FORM_material = {
|
||||||
|
material: {
|
||||||
|
rkrq: "",
|
||||||
|
rkdw: "",
|
||||||
|
sl: "",
|
||||||
|
dw: "",
|
||||||
|
cfdd: "",
|
||||||
|
fzr: "",
|
||||||
|
lxdh: "",
|
||||||
|
ye: "",
|
||||||
|
qxmc: "",
|
||||||
|
wzmc: "",
|
||||||
|
fzrid: "",
|
||||||
|
yhzid: "",
|
||||||
|
jd: "",
|
||||||
|
wd: "",
|
||||||
|
},
|
||||||
|
photos: [],
|
||||||
|
};
|
||||||
|
const equipmentForm = reactive({});
|
||||||
|
const INIT_FORM_equipment = {
|
||||||
|
rid: "",
|
||||||
|
qxmc: "",
|
||||||
|
sbbh: "",
|
||||||
|
sbdl: "",
|
||||||
|
sbmc: "",
|
||||||
|
sblx: "",
|
||||||
|
sbxh: "",
|
||||||
|
sbwz: "",
|
||||||
|
jd: props.basicData.jd,
|
||||||
|
wd: props.basicData.wd,
|
||||||
|
glry: "",
|
||||||
|
glryid: "",
|
||||||
|
czy: "",
|
||||||
|
czyid: "",
|
||||||
|
gzrq: "",
|
||||||
|
gmfy: "",
|
||||||
|
sbzt: "",
|
||||||
|
sccj: "",
|
||||||
|
sfyjsb: "",
|
||||||
|
sfnrsjbz: "",
|
||||||
|
fsfw: "",
|
||||||
|
yhzid: props.basicData.id,
|
||||||
|
};
|
||||||
|
const modelVisible = ref(false);
|
||||||
|
const model = reactive({
|
||||||
|
title: "",
|
||||||
|
content: null,
|
||||||
|
props: {},
|
||||||
|
onConfirm: () => {},
|
||||||
|
onCancel: () => {},
|
||||||
|
width: "30%",
|
||||||
|
});
|
||||||
|
const handleAdd = () => {
|
||||||
|
switch (activeTab.value) {
|
||||||
|
case "people":
|
||||||
|
model.title = "新增人员";
|
||||||
|
model.content = PersonAddDialog;
|
||||||
|
peopleForm.value = { ...INIT_FORM_people };
|
||||||
|
model.props = {
|
||||||
|
form: peopleForm.value,
|
||||||
|
};
|
||||||
|
model.onConfirm = handleAddPeopleConfirm;
|
||||||
|
model.onCancel = handleCancel;
|
||||||
|
model.width = "30%";
|
||||||
|
modelVisible.value = true;
|
||||||
|
break;
|
||||||
|
case "material":
|
||||||
|
model.title = "新增物资";
|
||||||
|
model.content = MaterialAddDialog;
|
||||||
|
// 重置表单
|
||||||
|
materialForm.material = { ...INIT_FORM_material.material };
|
||||||
|
materialForm.photos = [...INIT_FORM_material.photos];
|
||||||
|
materialForm.material.yhzid = props.basicData.id;
|
||||||
|
materialForm.material.jd = props.basicData.jd;
|
||||||
|
materialForm.material.wd = props.basicData.wd;
|
||||||
|
model.props = {
|
||||||
|
form: materialForm,
|
||||||
|
basicData: props.basicData,
|
||||||
|
};
|
||||||
|
model.onConfirm = handleAddMaterialConfirm;
|
||||||
|
model.onCancel = handleCancel;
|
||||||
|
model.width = "40%";
|
||||||
|
modelVisible.value = true;
|
||||||
|
break;
|
||||||
|
case "equipment":
|
||||||
|
console.log("basicData", toRaw(props.basicData));
|
||||||
|
model.title = "新增设备";
|
||||||
|
model.content = EquipmentAddDialog;
|
||||||
|
// 重置表单
|
||||||
|
equipmentForm.value = { ...INIT_FORM_equipment };
|
||||||
|
model.props = {
|
||||||
|
form: equipmentForm,
|
||||||
|
basicData: props.basicData,
|
||||||
|
};
|
||||||
|
model.onConfirm = handleAddEquipmentConfirm;
|
||||||
|
model.onCancel = handleCancel;
|
||||||
|
model.width = "60%";
|
||||||
|
modelVisible.value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增负责人
|
||||||
|
const handleAddPeopleConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yhzry/add",
|
||||||
|
method: "post",
|
||||||
|
data: toRaw(peopleForm.value),
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
ElMessage.success("新增成功");
|
||||||
|
modelVisible.value = false;
|
||||||
|
getPeopleList();
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增物资
|
||||||
|
const handleAddMaterialConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yjwz/add",
|
||||||
|
method: "post",
|
||||||
|
data: toRaw(materialForm),
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
ElMessage.success("新增成功");
|
||||||
|
modelVisible.value = false;
|
||||||
|
getMaterialList();
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增设备
|
||||||
|
const handleAddEquipmentConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: "/snow-ops-platform/yjsb/add",
|
||||||
|
method: "post",
|
||||||
|
data: {
|
||||||
|
equipment: toRaw(equipmentForm),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.code === "00000") {
|
||||||
|
ElMessage.success("新增成功");
|
||||||
|
modelVisible.value = false;
|
||||||
|
getEquipmentList();
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
ElMessage.error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消
|
||||||
|
const handleCancel = () => {
|
||||||
|
modelVisible.value = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -49,4 +517,10 @@ const handleClick = (tab, event) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
}
|
}
|
||||||
|
.button-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin: 10px 0px 10px 0px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -17,6 +17,7 @@ const model = reactive({
|
|||||||
onCancel: null,
|
onCancel: null,
|
||||||
onConfirm: null,
|
onConfirm: null,
|
||||||
}); // 弹窗内容
|
}); // 弹窗内容
|
||||||
|
const form = reactive({});
|
||||||
const drawer = reactive({
|
const drawer = reactive({
|
||||||
title: '',
|
title: '',
|
||||||
content: null,
|
content: null,
|
||||||
@ -31,6 +32,7 @@ const dialogRef = ref(null); // 弹窗实例
|
|||||||
const drawerType = ref(''); // 抽屉类型
|
const drawerType = ref(''); // 抽屉类型
|
||||||
const drawerRef = ref(null); // 抽屉实例
|
const drawerRef = ref(null); // 抽屉实例
|
||||||
|
|
||||||
|
|
||||||
// 站点类型选项
|
// 站点类型选项
|
||||||
const zdlxOptions = [
|
const zdlxOptions = [
|
||||||
{ label: "服务设施", value: "服务设施" },
|
{ label: "服务设施", value: "服务设施" },
|
||||||
@ -108,6 +110,12 @@ const getYhzDetail = async (row) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 打开新增养护站弹窗
|
||||||
|
const openAddDialog = () => {
|
||||||
|
|
||||||
|
console.log('新增',)
|
||||||
|
};
|
||||||
export default () => {
|
export default () => {
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -181,18 +189,6 @@ export default () => {
|
|||||||
},
|
},
|
||||||
() => "详情"
|
() => "详情"
|
||||||
),
|
),
|
||||||
h(
|
|
||||||
ElButton,
|
|
||||||
{
|
|
||||||
type: "success",
|
|
||||||
link: true,
|
|
||||||
style: "margin-left: 10px;",
|
|
||||||
onClick: async () => {
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => "编辑"
|
|
||||||
),
|
|
||||||
h(
|
h(
|
||||||
ElButton,
|
ElButton,
|
||||||
{
|
{
|
||||||
@ -260,7 +256,7 @@ export default () => {
|
|||||||
drawer,
|
drawer,
|
||||||
dialogRef,
|
dialogRef,
|
||||||
drawerRef,
|
drawerRef,
|
||||||
|
openAddDialog,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="event-box">
|
<div class="event-box">
|
||||||
<el-button type="primary" size="large" @click="openAddDialog"
|
<el-button type="primary" size="large" @click="script.openAddDialog"
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,462 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="root">
|
|
||||||
<div class="event-box">
|
|
||||||
<div class="inline-flex">
|
|
||||||
<label>人员姓名:</label>
|
|
||||||
<el-input v-model="filterData.xm"></el-input>
|
|
||||||
</div>
|
|
||||||
<div class="inline-flex">
|
|
||||||
<el-button type="primary" size="large" @click="openAddModel"
|
|
||||||
>新增人员</el-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-box">
|
|
||||||
<div class="form-content">
|
|
||||||
<DynamicTable
|
|
||||||
:dataSource="yhzryList"
|
|
||||||
:columns="columns"
|
|
||||||
:autoHeight="true"
|
|
||||||
:pagination="pagination"
|
|
||||||
></DynamicTable>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="model-box">
|
|
||||||
<MyDialog
|
|
||||||
v-model="modelVisible"
|
|
||||||
:title="model?.title"
|
|
||||||
:dynamicComponent="model?.content"
|
|
||||||
:component-props="model?.props"
|
|
||||||
:onConfirm="model?.onConfirm"
|
|
||||||
:onCancel="model?.onCancel"
|
|
||||||
ref="dialogRef"
|
|
||||||
:width="model?.width"
|
|
||||||
>
|
|
||||||
</MyDialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { h, ref, onMounted, reactive, watch, toRaw } from "vue";
|
|
||||||
import DynamicTable from "../../component/DynamicTable";
|
|
||||||
import { request } from "@/utils/request";
|
|
||||||
import MyDialog from "../../component/MyDialog";
|
|
||||||
import AddDialog from "./component/addDialog.vue";
|
|
||||||
import EditDialog from "./component/editDialog.vue";
|
|
||||||
import DetailDialog from "./component/detailDialog.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
yhzData: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 养护站ID
|
|
||||||
const yhzId = ref(props.yhzData.id);
|
|
||||||
// 表格过滤条件
|
|
||||||
const filterData = reactive({
|
|
||||||
xm: "", // 姓名
|
|
||||||
});
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
pageSizes: [10, 20, 50],
|
|
||||||
layout: "prev, pager, next, jumper",
|
|
||||||
onChange: (page, pageSize) => {
|
|
||||||
pagination.current = page;
|
|
||||||
pagination.pageSize = pageSize;
|
|
||||||
getyhzryList(filterData);
|
|
||||||
},
|
|
||||||
}); // 表格分页
|
|
||||||
|
|
||||||
// 养护站人员列表
|
|
||||||
const yhzryList = ref([]);
|
|
||||||
|
|
||||||
// 获取养护站人员详情
|
|
||||||
const getDetailData = async (row) => {
|
|
||||||
try {
|
|
||||||
const res = await request({
|
|
||||||
url: `/snow-ops-platform/yhzry/getById?id=${row.id}`,
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (!res || res.code !== "00000") {
|
|
||||||
throw new Error("获取人员详情失败");
|
|
||||||
}
|
|
||||||
if (res.code === "00000") {
|
|
||||||
if (dialogType.value === "detail") {
|
|
||||||
model.title = `人员详情`;
|
|
||||||
model.content = DetailDialog;
|
|
||||||
model.props = {
|
|
||||||
detailData: res.data,
|
|
||||||
};
|
|
||||||
model.onCancel = () => {
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
};
|
|
||||||
model.onConfirm = () => {
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
};
|
|
||||||
model.width = "30%";
|
|
||||||
modelVisible.value = true;
|
|
||||||
}
|
|
||||||
if (dialogType.value === "edit") {
|
|
||||||
model.title = `编辑人员`;
|
|
||||||
model.content = EditDialog;
|
|
||||||
Object.assign(form, res.data);
|
|
||||||
model.props = {
|
|
||||||
detailData: res.data,
|
|
||||||
form: form,
|
|
||||||
};
|
|
||||||
model.onCancel = () => {
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
};
|
|
||||||
model.onConfirm = async () => {
|
|
||||||
await handleEdit();
|
|
||||||
};
|
|
||||||
model.width = "30%";
|
|
||||||
modelVisible.value = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEdit = async () => {
|
|
||||||
try {
|
|
||||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate();
|
|
||||||
console.log("form", toRaw(form));
|
|
||||||
const res = await request({
|
|
||||||
url: "/snow-ops-platform/yhzry/update",
|
|
||||||
method: "POST",
|
|
||||||
data: toRaw(form),
|
|
||||||
});
|
|
||||||
if (res.code === "00000") {
|
|
||||||
ElMessage.success("编辑成功");
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
getyhzryList(filterData);
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log("error", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
prop: "xm",
|
|
||||||
label: "姓名",
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: "gw",
|
|
||||||
label: "岗位",
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: "sjhm",
|
|
||||||
label: "手机号码",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: "cjsj",
|
|
||||||
label: "创建时间",
|
|
||||||
render: (row) => () => {
|
|
||||||
// 解析 ISO 时间字符串
|
|
||||||
const date = new Date(row.cjsj);
|
|
||||||
|
|
||||||
// 格式化为 YYYY-MM-DD HH:mm:ss
|
|
||||||
const format = (n) => n.toString().padStart(2, "0");
|
|
||||||
return h(
|
|
||||||
"div",
|
|
||||||
`${date.getFullYear()}-${format(date.getMonth() + 1)}-${format(
|
|
||||||
date.getDate()
|
|
||||||
)}
|
|
||||||
${format(date.getHours())}:${format(
|
|
||||||
date.getMinutes()
|
|
||||||
)}:${format(date.getSeconds())}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: "ryjs",
|
|
||||||
label: "人员角色",
|
|
||||||
width: 150,
|
|
||||||
render: (row) => () => {
|
|
||||||
const roleConfig = {
|
|
||||||
1: { label: "负责人", color: "#f56c6c" },
|
|
||||||
2: { label: "普通工作人员", color: "#409eff" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const config = roleConfig[row.ryjs] || {
|
|
||||||
label: "未知角色",
|
|
||||||
color: "#909399",
|
|
||||||
};
|
|
||||||
|
|
||||||
return h(
|
|
||||||
ElTag,
|
|
||||||
{
|
|
||||||
style: { "margin-right": "5px" },
|
|
||||||
effect: "dark",
|
|
||||||
type: row.ryjs === 1 ? "danger" : "primary",
|
|
||||||
},
|
|
||||||
() => config.label
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
label: "操作",
|
|
||||||
fixed: "right",
|
|
||||||
width: 150,
|
|
||||||
render: (row) => () =>
|
|
||||||
h("div", { class: "action-btns" }, [
|
|
||||||
h(
|
|
||||||
ElButton,
|
|
||||||
{
|
|
||||||
type: "primary",
|
|
||||||
link: true,
|
|
||||||
onClick: async () => {
|
|
||||||
dialogType.value = "detail";
|
|
||||||
await getDetailData(row);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => "详情"
|
|
||||||
),
|
|
||||||
h(
|
|
||||||
ElButton,
|
|
||||||
{
|
|
||||||
type: "primary",
|
|
||||||
link: true,
|
|
||||||
onClick: async () => {
|
|
||||||
dialogType.value = "edit";
|
|
||||||
await getDetailData(row);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => "编辑"
|
|
||||||
),
|
|
||||||
h(
|
|
||||||
ElButton,
|
|
||||||
{
|
|
||||||
type: "danger",
|
|
||||||
link: true,
|
|
||||||
onClick: async () => {
|
|
||||||
try {
|
|
||||||
await ElMessageBox.confirm("确定要删除该人员吗?", "删除确认", {
|
|
||||||
confirmButtonText: "确定",
|
|
||||||
cancelButtonText: "取消",
|
|
||||||
type: "warning",
|
|
||||||
});
|
|
||||||
const res = await request({
|
|
||||||
url: `/snow-ops-platform/yhzry/delete`,
|
|
||||||
method: "POST",
|
|
||||||
data: {
|
|
||||||
id: row.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (res.code === "00000") {
|
|
||||||
ElMessage.success("删除成功");
|
|
||||||
getyhzryList(filterData);
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => "删除"
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 获取养护站人员列表
|
|
||||||
const getyhzryList = async (filterData) => {
|
|
||||||
try {
|
|
||||||
const data = {
|
|
||||||
yhzid: yhzId.value,
|
|
||||||
xm: filterData?.xm || "",
|
|
||||||
pageNum: pagination.current,
|
|
||||||
pageSize: pagination.pageSize,
|
|
||||||
};
|
|
||||||
const res = await request({
|
|
||||||
url: "/snow-ops-platform/yhzry/list",
|
|
||||||
method: "GET",
|
|
||||||
params: data,
|
|
||||||
});
|
|
||||||
if (res.code === "00000") {
|
|
||||||
yhzryList.value = res.data.records;
|
|
||||||
pagination.total = res.data.total;
|
|
||||||
} else {
|
|
||||||
throw new Error(res.msg);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 分页查询养护站
|
|
||||||
onMounted(async () => {
|
|
||||||
await getyhzryList();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听过滤条件
|
|
||||||
watch(
|
|
||||||
[() => filterData],
|
|
||||||
([newFilterData]) => {
|
|
||||||
getyhzryList(newFilterData);
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 弹窗显示状态
|
|
||||||
const modelVisible = ref(false);
|
|
||||||
const dialogType = ref(""); // 弹窗类型
|
|
||||||
const dialogRef = ref(null); // 弹窗实例
|
|
||||||
|
|
||||||
// 弹窗
|
|
||||||
const model = reactive({
|
|
||||||
title: "",
|
|
||||||
content: null,
|
|
||||||
props: {},
|
|
||||||
onConfirm: () => {},
|
|
||||||
onCancel: () => {},
|
|
||||||
width: "30%",
|
|
||||||
});
|
|
||||||
|
|
||||||
const INIT_FORM = {
|
|
||||||
xm: "",
|
|
||||||
sjhm: "",
|
|
||||||
gw: "",
|
|
||||||
cjsj: "",
|
|
||||||
yhzid: "",
|
|
||||||
ryjs: null, // 人员角色 1-负责人 2-普通工作人员
|
|
||||||
userId: "",
|
|
||||||
}; // 表单初始值
|
|
||||||
const form = reactive({ ...INIT_FORM }); // 表单
|
|
||||||
|
|
||||||
// 根据用户信息 查询角色列表
|
|
||||||
const getUserList = async (key) => {
|
|
||||||
try {
|
|
||||||
const keyword = key;
|
|
||||||
let url = "";
|
|
||||||
if (keyword) {
|
|
||||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=${keyword}`;
|
|
||||||
} else {
|
|
||||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=`;
|
|
||||||
}
|
|
||||||
const res = await request({
|
|
||||||
url: url,
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (res.code === "00000") {
|
|
||||||
return res.data;
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 打开新增人员弹窗
|
|
||||||
const openAddModel = () => {
|
|
||||||
model.title = `新增人员`;
|
|
||||||
model.content = AddDialog;
|
|
||||||
model.width = "30%";
|
|
||||||
Object.assign(form, INIT_FORM);
|
|
||||||
model.props = {
|
|
||||||
form: form,
|
|
||||||
getUserList: getUserList,
|
|
||||||
yhzdata: props.yhzData,
|
|
||||||
};
|
|
||||||
model.onCancel = () => {
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
};
|
|
||||||
model.onConfirm = async () => {
|
|
||||||
try {
|
|
||||||
form.cjsj = new Date()
|
|
||||||
.toLocaleString("sv-SE", { hour12: false })
|
|
||||||
.replace("T", " ");
|
|
||||||
console.log("form", toRaw(form));
|
|
||||||
const res = await request({
|
|
||||||
url: "/snow-ops-platform/yhzry/add",
|
|
||||||
method: "POST",
|
|
||||||
data: toRaw(form),
|
|
||||||
});
|
|
||||||
if (res.code === "00000") {
|
|
||||||
ElMessage.success("新增人员成功");
|
|
||||||
dialogType.value = "";
|
|
||||||
modelVisible.value = false;
|
|
||||||
getyhzryList(filterData);
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error.message);
|
|
||||||
console.log("error", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
modelVisible.value = true;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.root {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.inline-flex {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.inline-flex label {
|
|
||||||
white-space: nowrap; /* 禁止换行 */
|
|
||||||
}
|
|
||||||
.form-box {
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 60px);
|
|
||||||
overflow: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.event-box {
|
|
||||||
width: 100%;
|
|
||||||
height: 60px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 20px;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.form-content {
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 60px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-box {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
67
packages/screen/src/views/cockpit/api/DDT.json
Normal file
67
packages/screen/src/views/cockpit/api/DDT.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Rid": "4126",
|
||||||
|
"Name": "底图",
|
||||||
|
"Attribute": {
|
||||||
|
"rid": 4126,
|
||||||
|
"name": "底图",
|
||||||
|
"layerId": 0,
|
||||||
|
"internalService": 1,
|
||||||
|
"serviceTypeId": "",
|
||||||
|
"serviceTypeName": "",
|
||||||
|
"servicePath": "",
|
||||||
|
"domainService": "",
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "#",
|
||||||
|
"sortValue": 2,
|
||||||
|
"createTime": "2025-05-26T14:44:05.926Z",
|
||||||
|
"dataType": "1",
|
||||||
|
"bootLoad": 0,
|
||||||
|
"internalServiceName": "",
|
||||||
|
"historyServicePath": "",
|
||||||
|
"expandParam": "",
|
||||||
|
"thumbnail": "",
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSubLayer": "",
|
||||||
|
"accessInfo": "",
|
||||||
|
"pcatalog": "DDT",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"Rid": "928",
|
||||||
|
"Name": "重庆三维",
|
||||||
|
"Attribute": {
|
||||||
|
"rid": 928,
|
||||||
|
"name": "重庆三维",
|
||||||
|
"layerId": 0,
|
||||||
|
"internalService": 2,
|
||||||
|
"serviceTypeId": "",
|
||||||
|
"serviceTypeName": "WmsServiceLayer",
|
||||||
|
"servicePath": "/ylzggeoserver/gwc/service/wms?service=WMS&version=1.3.0&request=GetMap&layers=chongqing_yx",
|
||||||
|
"domainService": "",
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "4126",
|
||||||
|
"sortValue": 10,
|
||||||
|
"createTime": "2025-10-18T15:04:46.56008Z",
|
||||||
|
"dataType": "2",
|
||||||
|
"bootLoad": 0,
|
||||||
|
"internalServiceName": "",
|
||||||
|
"historyServicePath": "",
|
||||||
|
"expandParam": "{\"mapUseRange\":[\"2D\"],\"data\":[],\"expandedNode\":false,\"isUseExpandParam\":false,\"mapIndex\":1}",
|
||||||
|
"thumbnail": "",
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSubLayer": "",
|
||||||
|
"accessInfo": "{\"verifyType\":\"usrpwd\",\"tokenName\":\"token\",\"isUseVerification\":false,\"isUseToken\":false,\"verifyParams\":{\"url\":\"\",\"username\":\"\",\"password\":\"\",\"token\":\"\",\"tokenLoginUrl\":\"\",\"requestType\":\"Get\",\"requestParam\":\"\",\"interval\":60,\"rule\":\"\",\"tokenName\":\"\"}}",
|
||||||
|
"pcatalog": "DDT",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [],
|
||||||
|
"SortValue": 0,
|
||||||
|
"ParentId": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SortValue": 0,
|
||||||
|
"ParentId": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
37
packages/screen/src/views/cockpit/api/commonHttp.js
Normal file
37
packages/screen/src/views/cockpit/api/commonHttp.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { request } from '@shared/utils/request'
|
||||||
|
import si from './si.json'
|
||||||
|
import ddt from './DDT.json'
|
||||||
|
|
||||||
|
// 获取业务基础地图
|
||||||
|
export function getBusinessBaseMapDDT() {
|
||||||
|
return [...ddt]
|
||||||
|
// return request({
|
||||||
|
// url: '/snow-ops-platform/dataDirectory/queryCatalog',
|
||||||
|
// method: 'GET',
|
||||||
|
// params: {
|
||||||
|
// pcatalog: 'DDT'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取业务基础地图
|
||||||
|
export function getBusinessBaseMapSI() {
|
||||||
|
return [...si]
|
||||||
|
// return request({
|
||||||
|
// url: '/snow-ops-platform/dataDirectory/queryCatalog',
|
||||||
|
// method: 'GET',
|
||||||
|
// params: {
|
||||||
|
// pcatalog: 'SI'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
return request({
|
||||||
|
url: '/ylzggeoserver/gwc/service/wms?service=WMS&request=GetMap&transparent=true&srs=EPSG%3A3857&format=image%2Fpng&styles=&layers=chongqing_yx&bbox=12053813.612459153%2C3130860.6785608195%2C12210356.646387197%2C3287403.71248886&width=256&height=256',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
196
packages/screen/src/views/cockpit/api/si.json
Normal file
196
packages/screen/src/views/cockpit/api/si.json
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Rid": "922",
|
||||||
|
"Name": "地图服务",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 922,
|
||||||
|
"name": "地图服务",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 0,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": null,
|
||||||
|
"servicePath": null,
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "#",
|
||||||
|
"sortValue": 1,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "1",
|
||||||
|
"bootLoad": 0,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": null,
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": null,
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"Rid": "936",
|
||||||
|
"Name": "三维模型",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 936,
|
||||||
|
"name": "三维模型",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 0,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": null,
|
||||||
|
"servicePath": null,
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "922",
|
||||||
|
"sortValue": 1,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "1",
|
||||||
|
"bootLoad": 0,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": null,
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": null,
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"Rid": "923",
|
||||||
|
"Name": "S107",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 923,
|
||||||
|
"name": "S107",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 2,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": "Cesium3DTileService",
|
||||||
|
"servicePath": "http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/S107/terra_b3dms/tileset.json",
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "936",
|
||||||
|
"sortValue": 1,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "2",
|
||||||
|
"bootLoad": 0,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": "{\"data\":[],\"editUrl\":\"\",\"isUseExpandParam\":false,\"expandedNode\":false,\"mapUseRange\":[\"2D\"]}",
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": "{\"verifyType\":\"usrpwd\",\"tokenName\":\"token\",\"isUseVerification\":false,\"isUseToken\":false,\"verifyParams\":{\"url\":\"\",\"username\":\"\",\"password\":\"\",\"token\":\"\",\"tokenLoginUrl\":\"\",\"requestType\":\"Get\",\"requestParam\":\"\",\"interval\":60,\"rule\":\"\",\"tokenName\":\"\"}}",
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Rid": "927",
|
||||||
|
"Name": "行政区划服务",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 927,
|
||||||
|
"name": "行政区划服务",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 2,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": "WmsServiceLayer",
|
||||||
|
"servicePath": "/ylzggeoserver/cite/wms?service=WMS&version=1.3.0&request=GetMap&layers=cite:base_xzqh_geo",
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "922",
|
||||||
|
"sortValue": 10,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "2",
|
||||||
|
"bootLoad": 1,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": "{\"mapUseRange\":[\"2D\"],\"data\":[],\"expandedNode\":false,\"isUseExpandParam\":false,\"mapIndex\":1}",
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": "{\"verifyType\":\"usrpwd\",\"tokenName\":\"token\",\"isUseVerification\":false,\"isUseToken\":false,\"verifyParams\":{\"url\":\"\",\"username\":\"\",\"password\":\"\",\"token\":\"\",\"tokenLoginUrl\":\"\",\"requestType\":\"Get\",\"requestParam\":\"\",\"interval\":60,\"rule\":\"\",\"tokenName\":\"\"}}",
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Rid": "940",
|
||||||
|
"Name": "管理段路线名称",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 940,
|
||||||
|
"name": "管理段路线名称",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 2,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": "WmsServiceLayer",
|
||||||
|
"servicePath": "/ylzggeoserver/cite/wms?service=WMS&version=1.3.0&request=GetMap&layers=cite:nianbao_2024_3857_lxbq&cql_filter=XZQH_ID%3D%27402880e74a28b152014a28b885c60000%27",
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "922",
|
||||||
|
"sortValue": 16,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "2",
|
||||||
|
"bootLoad": 1,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": "{\"mapUseRange\":[\"2D\"],\"data\":[],\"expandedNode\":false,\"isUseExpandParam\":false,\"mapIndex\":1}",
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": "{\"verifyType\":\"usrpwd\",\"tokenName\":\"token\",\"isUseVerification\":false,\"isUseToken\":false,\"verifyParams\":{\"url\":\"\",\"username\":\"\",\"password\":\"\",\"token\":\"\",\"tokenLoginUrl\":\"\",\"requestType\":\"Get\",\"requestParam\":\"\",\"interval\":60,\"rule\":\"\",\"tokenName\":\"\"}}",
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Rid": "937",
|
||||||
|
"Name": "管理段",
|
||||||
|
"Attribute": {
|
||||||
|
"id": 937,
|
||||||
|
"name": "管理段",
|
||||||
|
"externalService": 0,
|
||||||
|
"internalService": 2,
|
||||||
|
"serviceTypeId": null,
|
||||||
|
"serviceTypeName": "WmsServiceLayer",
|
||||||
|
"servicePath": "/ylzggeoserver/cite/wms?service=WMS&version=1.3.0&request=GetMap&layers=cite:nianbao_2024_3857&cql_filter=XZQH_ID%3D%27402880e74a28b152014a28b885c60000%27",
|
||||||
|
"domainService": null,
|
||||||
|
"status": 0,
|
||||||
|
"parentId": "922",
|
||||||
|
"sortValue": 16,
|
||||||
|
"createTime": null,
|
||||||
|
"dataType": "2",
|
||||||
|
"bootLoad": 1,
|
||||||
|
"internalServiceName": null,
|
||||||
|
"historyServicePath": null,
|
||||||
|
"expandParam": "{\"mapUseRange\":[\"2D\"],\"data\":[],\"expandedNode\":false,\"isUseExpandParam\":false,\"mapIndex\":1}",
|
||||||
|
"thumbnail": null,
|
||||||
|
"showDirectory": 0,
|
||||||
|
"selectSublayer": null,
|
||||||
|
"accessInfo": "{\"verifyType\":\"usrpwd\",\"tokenName\":\"token\",\"isUseVerification\":false,\"isUseToken\":false,\"verifyParams\":{\"url\":\"\",\"username\":\"\",\"password\":\"\",\"token\":\"\",\"tokenLoginUrl\":\"\",\"requestType\":\"Get\",\"requestParam\":\"\",\"interval\":60,\"rule\":\"\",\"tokenName\":\"\"}}",
|
||||||
|
"pcatalog": "SI",
|
||||||
|
"orgCode": "YLZG"
|
||||||
|
},
|
||||||
|
"Children": [],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SortValue": null,
|
||||||
|
"ParentId": null
|
||||||
|
}
|
||||||
|
]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 图例工具栏 -->
|
<!-- 图例工具栏 -->
|
||||||
<LegendToolbar class="legend-toolbar" @marker-toggle="handleLegendMarkerToggle" />
|
<LegendToolbar class="legend-toolbar" :legendKeys="legendKeys" @marker-toggle="handleLegendMarkerToggle" />
|
||||||
|
|
||||||
<!-- 应急力量详情提示框 -->
|
<!-- 应急力量详情提示框 -->
|
||||||
<EmergencyForceTooltip
|
<EmergencyForceTooltip
|
||||||
@ -42,11 +42,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onBeforeUnmount } from 'vue'
|
import { ref, onBeforeUnmount, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import useMapStore from '@/map/stores/mapStore'
|
import useMapStore from '@/map/stores/mapStore'
|
||||||
import { fetchEmergencyForceList } from '@/views/cockpit/api/emergencyForce'
|
import { fetchEmergencyForceList } from '@/views/cockpit/api/emergencyForce'
|
||||||
import { useEmergencyForceInteraction } from '../composables/useEmergencyForceInteraction'
|
import { useEmergencyForceInteraction } from '../composables/useEmergencyForceInteraction'
|
||||||
|
import { useMapBase } from '../composables/useMapBase'
|
||||||
|
import { useMapImageMark } from '../composables/useMapImageMark'
|
||||||
|
|
||||||
import PageHeader from './PageHeader.vue'
|
import PageHeader from './PageHeader.vue'
|
||||||
import WeatherWarning from './WeatherWarning.vue'
|
import WeatherWarning from './WeatherWarning.vue'
|
||||||
@ -58,6 +60,11 @@ import LegendToolbar from './LegendToolbar.vue'
|
|||||||
import EmergencyForceTooltip from './EmergencyForceTooltip.vue'
|
import EmergencyForceTooltip from './EmergencyForceTooltip.vue'
|
||||||
import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png'
|
import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png'
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
// 加载地图业务底图 并 聚焦中心点
|
||||||
|
mapBase.loadBaseData()
|
||||||
|
})
|
||||||
|
|
||||||
// ==================== 常量定义 ====================
|
// ==================== 常量定义 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +93,16 @@ const emergencyForceInteraction = useEmergencyForceInteraction(mapStore, {
|
|||||||
flyDistance: 500
|
flyDistance: 500
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载地图的业务底图与聚焦中心点
|
||||||
|
*/
|
||||||
|
const mapBase = useMapBase(mapStore)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记图hook,搭配lengendToolbar使用, 作用是点击某个图例项时,在地图上显示所有该图例的图
|
||||||
|
*/
|
||||||
|
const mapImageMark = useMapImageMark(mapStore)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应急力量数据加载状态
|
* 应急力量数据加载状态
|
||||||
*/
|
*/
|
||||||
@ -111,6 +128,12 @@ const emergencyForceCache = ref({
|
|||||||
*/
|
*/
|
||||||
const emergencyForceAbortController = ref(null)
|
const emergencyForceAbortController = ref(null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具图标列表通过key关联
|
||||||
|
* key具体有哪些,请根据LegendToolbar.vue中定义的defaultLegendItems
|
||||||
|
*/
|
||||||
|
const legendKeys = ref(['serviceFacility','riskRoad','blockEvent','weatherAlert','emergencyForce'])
|
||||||
|
|
||||||
// ==================== 工具函数 ====================
|
// ==================== 工具函数 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -401,6 +424,9 @@ const renderEmergencyForcePoints = async (entityService, points, markerIcon) =>
|
|||||||
const handleLegendMarkerToggle = async ({ key, active, markerIcon }) => {
|
const handleLegendMarkerToggle = async ({ key, active, markerIcon }) => {
|
||||||
// 只处理应急力量图例项
|
// 只处理应急力量图例项
|
||||||
if (key !== 'emergencyForce') {
|
if (key !== 'emergencyForce') {
|
||||||
|
|
||||||
|
mapImageMark.toggleMark({ key, active, markerIcon })
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,356 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-if="visible && position" class="common-tooltip" :style="{
|
||||||
|
left: `${position.x}px`,
|
||||||
|
top: `${position.y - 20}px`
|
||||||
|
}">
|
||||||
|
<span class="title">{{ title }}</span>
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
|
<button class="close-button" type="button" aria-label="关闭" @click="handleClose">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="tooltip-content">
|
||||||
|
<component v-if="hasData" :is="contentMap[data.mapData.layerId]" :data="data" />
|
||||||
|
|
||||||
|
<!-- 如果没有数据 -->
|
||||||
|
<div v-if="!hasData" class="no-data">
|
||||||
|
暂无详细信息
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-if="loading" class="loading-overlay">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 错误状态 -->
|
||||||
|
<div v-if="error" class="error-message">
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import serviceFacility from './serviceFacility.vue'
|
||||||
|
import riskRoad from './riskRoad.vue'
|
||||||
|
import weatherAlert from './weatherAlert.vue'
|
||||||
|
import blockEvent from './blockEvent.vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应急力量详情提示框组件
|
||||||
|
* 使用 HTML Overlay 方式显示在地图标记点上方
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ==================== Props ====================
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
/**
|
||||||
|
* 是否显示提示框
|
||||||
|
*/
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示框位置(屏幕坐标)
|
||||||
|
* @type {{ x: number, y: number }}
|
||||||
|
*/
|
||||||
|
position: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情数据
|
||||||
|
* @type {{ qxmc?: string, yjllpz?: string, wzQtwz?: string }}
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载状态
|
||||||
|
*/
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误信息
|
||||||
|
*/
|
||||||
|
error: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== State ====================
|
||||||
|
const contentMap = ref({
|
||||||
|
// 养护站内容
|
||||||
|
serviceFacility,
|
||||||
|
// 高海拔道路
|
||||||
|
riskRoad,
|
||||||
|
// 阻断事件
|
||||||
|
blockEvent,
|
||||||
|
// 气象预警
|
||||||
|
weatherAlert,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== Emits ====================
|
||||||
|
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
// ==================== Computed ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有有效数据
|
||||||
|
*/
|
||||||
|
const hasData = computed(() => {
|
||||||
|
return !!props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const title = computed(() => {
|
||||||
|
if (props.data.mapData.layerId === 'serviceFacility') {
|
||||||
|
return '养护站'
|
||||||
|
}
|
||||||
|
if (props.data.mapData.layerId === 'riskRoad') {
|
||||||
|
return '高海拔路段'
|
||||||
|
}
|
||||||
|
if (props.data.mapData.layerId === 'blockEvent') {
|
||||||
|
return '阻断事件'
|
||||||
|
}
|
||||||
|
if (props.data.mapData.layerId === 'weatherAlert') {
|
||||||
|
return '气象预警'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== Methods ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理关闭按钮点击
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/styles/mixins.scss' as *;
|
||||||
|
|
||||||
|
.common-tooltip {
|
||||||
|
// CSS 变量:控制背景图片尺寸和内边距
|
||||||
|
// 注意:修改图片资源时,需要同步更新这些高度值以匹配实际 PNG 尺寸
|
||||||
|
--tooltip-top-height: 68px;
|
||||||
|
--tooltip-bottom-height: 68px;
|
||||||
|
--tooltip-side-padding: 24px;
|
||||||
|
--tooltip-body-padding: 16px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
// 居中并置于标记点上方
|
||||||
|
transform: translate(-50%, calc(-100% - 20px));
|
||||||
|
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 300px;
|
||||||
|
|
||||||
|
// 上下 padding 需要容纳顶部和底部图片 + 内容间距
|
||||||
|
// 左右 padding 保持一致
|
||||||
|
padding: calc(var(--tooltip-top-height)) var(--tooltip-side-padding) calc(var(--tooltip-bottom-height));
|
||||||
|
|
||||||
|
// 三段式可拉伸背景:顶部固定高度、中部可拉伸、底部固定高度
|
||||||
|
background-image:
|
||||||
|
url('@/views/cockpit/assets/emergencyForceTooltip/top.png'),
|
||||||
|
url('@/views/cockpit/assets/emergencyForceTooltip/bottom.png'),
|
||||||
|
url('@/views/cockpit/assets/emergencyForceTooltip/middle.png');
|
||||||
|
|
||||||
|
// 顶部/底部/中部都不重复,中部通过 background-size 拉伸填充
|
||||||
|
background-repeat: no-repeat, no-repeat, no-repeat;
|
||||||
|
|
||||||
|
// 背景定位:顶部居中对齐顶边,底部居中对齐底边
|
||||||
|
// 中部略向上偏移 1px,结合高度 +2px 在上下各覆盖 1px 避免子像素渲染缝隙
|
||||||
|
background-position:
|
||||||
|
center top,
|
||||||
|
center bottom,
|
||||||
|
center calc(var(--tooltip-top-height) - 1px);
|
||||||
|
|
||||||
|
// 背景尺寸:顶部/底部高度固定
|
||||||
|
// 中部填充剩余空间并增加 2px,在上下各多覆盖约 1px 避免间隙
|
||||||
|
background-size:
|
||||||
|
100% var(--tooltip-top-height),
|
||||||
|
100% var(--tooltip-bottom-height),
|
||||||
|
100% calc(100% - var(--tooltip-top-height) - var(--tooltip-bottom-height) + 2px);
|
||||||
|
|
||||||
|
// 移除原有的 border 和 border-radius,使用图片背景
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
// 保留毛玻璃效果和阴影以增强视觉层次
|
||||||
|
// backdrop-filter: blur(12px);
|
||||||
|
// box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
|
||||||
|
// 小箭头(指向标记点)
|
||||||
|
// &::after {
|
||||||
|
// content: '';
|
||||||
|
// position: absolute;
|
||||||
|
// bottom: -10px;
|
||||||
|
// left: 50%;
|
||||||
|
// transform: translateX(-50%);
|
||||||
|
// width: 0;
|
||||||
|
// height: 0;
|
||||||
|
// border-left: 10px solid transparent;
|
||||||
|
// border-right: 10px solid transparent;
|
||||||
|
// border-top: 10px solid rgba(71, 186, 255, 0.4);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
left: 20px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
font-family: PingFangSC, PingFang SC;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
line-height: 22px;
|
||||||
|
text-shadow: 0px 0px 20px #079DFF;
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭按钮 - 仅作为透明点击热区,视觉由背景图中的关闭图标承载
|
||||||
|
.close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 18px;
|
||||||
|
right: 2px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
// 透明化所有视觉元素,仅保留点击功能
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: transparent;
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 1;
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
// 为键盘用户提供可见的焦点轮廓(仅在键盘导航时显示)
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid rgba(255, 255, 255, 0.8);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容区域
|
||||||
|
.tooltip-content {
|
||||||
|
padding-right: 1.5rem; // 为关闭按钮留出空间
|
||||||
|
}
|
||||||
|
|
||||||
|
// 信息项
|
||||||
|
.info-item {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无数据提示
|
||||||
|
.no-data {
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
.loading-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
// 使用半透明背景,让背景图片纹理仍然可见
|
||||||
|
background: rgba(0, 0, 0, 1);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载动画
|
||||||
|
.loading-spinner {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border: 3px solid rgba(71, 186, 255, 0.2);
|
||||||
|
border-top-color: rgba(71, 186, 255, 1);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误信息
|
||||||
|
.error-message {
|
||||||
|
color: #ff6b6b;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: rgba(255, 107, 107, 0.1);
|
||||||
|
border: 1px solid rgba(255, 107, 107, 0.3);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 淡入淡出动画
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, calc(-100% - 10px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, calc(-100% - 30px));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
test
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/styles/mixins.scss' as *;
|
||||||
|
</style>
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import { createVNode, render } from 'vue'
|
||||||
|
import ImageMarkTooltip from './ImageMarkTooltip.vue'
|
||||||
|
|
||||||
|
class ImageMarkTooltipUI {
|
||||||
|
constructor() {
|
||||||
|
this.instance = null
|
||||||
|
this.container = null
|
||||||
|
this.entity = null
|
||||||
|
this.root = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示 tooltip
|
||||||
|
show(options = {}) {
|
||||||
|
// 销毁之前的实例
|
||||||
|
this.close()
|
||||||
|
|
||||||
|
// 创建容器
|
||||||
|
this.container = document.createElement('div')
|
||||||
|
this.container.className = 'tooltip-service-container'
|
||||||
|
this.root = document.querySelector('.cockpit-main')
|
||||||
|
this.root.appendChild(this.container)
|
||||||
|
|
||||||
|
this.entity = options.entity
|
||||||
|
|
||||||
|
// 创建 VNode
|
||||||
|
const vnode = createVNode(ImageMarkTooltip, {
|
||||||
|
visible: true,
|
||||||
|
position: options.position || { x: 0, y: 0 },
|
||||||
|
data: options.data || {},
|
||||||
|
loading: options.loading || false,
|
||||||
|
error: options.error || '',
|
||||||
|
onClose: () => {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 渲染到容器
|
||||||
|
render(vnode, this.container)
|
||||||
|
this.instance = vnode.component
|
||||||
|
return this.instance
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition(position) {
|
||||||
|
if (this.instance) {
|
||||||
|
this.instance.props.position = position
|
||||||
|
this.instance.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 tooltip 内容
|
||||||
|
update(options) {
|
||||||
|
if (this.instance) {
|
||||||
|
this.instance.props = {
|
||||||
|
...this.instance.props,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭 tooltip
|
||||||
|
close() {
|
||||||
|
if (this.container) {
|
||||||
|
render(null, this.container)
|
||||||
|
this.root.removeChild(this.container)
|
||||||
|
this.container = null
|
||||||
|
this.instance = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建单例实例
|
||||||
|
const instance = new ImageMarkTooltipUI()
|
||||||
|
|
||||||
|
export const CommonTooltip = instance
|
||||||
|
|
||||||
|
export const newImageMarkTooltip = () => {
|
||||||
|
return new ImageMarkTooltipUI()
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tool-tip-content">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/styles/mixins.scss' as *;
|
||||||
|
</style>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content" v-if="data">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">名称:</span>
|
||||||
|
<span class="value">{{ data.mc }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">所属区县:</span>
|
||||||
|
<span class="value">{{ data.yjllpz }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">应急物资:</span>
|
||||||
|
<span class="value">{{ data.wz }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/styles/mixins.scss' as *;
|
||||||
|
|
||||||
|
// 信息项
|
||||||
|
.info-item {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
test
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/styles/mixins.scss' as *;
|
||||||
|
</style>
|
||||||
@ -76,6 +76,7 @@ import blockEventMarkerIcon from '../assets/legendTool/阻断事件icon定位.pn
|
|||||||
import emergencyForceIcon from '../assets/legendTool/应急力量icon.png'
|
import emergencyForceIcon from '../assets/legendTool/应急力量icon.png'
|
||||||
import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png'
|
import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png'
|
||||||
import weatherAlertIcon from '../assets/legendTool/气象预警icon.png'
|
import weatherAlertIcon from '../assets/legendTool/气象预警icon.png'
|
||||||
|
import weatherAlertMarkerIcon from '../assets/legendTool/气象预警icon定位.png'
|
||||||
|
|
||||||
// 默认图例项配置(包含普通图标和地图定位图标)
|
// 默认图例项配置(包含普通图标和地图定位图标)
|
||||||
const defaultLegendItems = [
|
const defaultLegendItems = [
|
||||||
@ -84,12 +85,12 @@ const defaultLegendItems = [
|
|||||||
{ key: 'trafficMonitor', label: '交调', icon: trafficMonitorIcon, markerIcon: trafficMonitorMarkerIcon },
|
{ key: 'trafficMonitor', label: '交调', icon: trafficMonitorIcon, markerIcon: trafficMonitorMarkerIcon },
|
||||||
{ key: 'bridge', label: '桥梁', icon: bridgeIcon, markerIcon: bridgeMarkerIcon },
|
{ key: 'bridge', label: '桥梁', icon: bridgeIcon, markerIcon: bridgeMarkerIcon },
|
||||||
{ key: 'tunnel', label: '隧洞', icon: tunnelIcon, markerIcon: tunnelMarkerIcon },
|
{ key: 'tunnel', label: '隧洞', icon: tunnelIcon, markerIcon: tunnelMarkerIcon },
|
||||||
{ key: 'serviceFacility', label: '服务设施', icon: serviceFacilityIcon, markerIcon: serviceFacilityMarkerIcon },
|
{ key: 'serviceFacility', label: '养护站', icon: serviceFacilityIcon, markerIcon: serviceFacilityMarkerIcon },
|
||||||
{ key: 'riskRoad', label: '风险路段', icon: riskRoadIcon, markerIcon: riskRoadMarkerIcon },
|
{ key: 'riskRoad', label: '高海拔路段', icon: riskRoadIcon, markerIcon: riskRoadMarkerIcon },
|
||||||
{ key: 'hazardPoint', label: '涉灾隐患点', icon: hazardPointIcon, markerIcon: hazardPointMarkerIcon },
|
{ key: 'hazardPoint', label: '涉灾隐患点', icon: hazardPointIcon, markerIcon: hazardPointMarkerIcon },
|
||||||
{ key: 'blockEvent', label: '阻断事件', icon: blockEventIcon, markerIcon: blockEventMarkerIcon },
|
{ key: 'blockEvent', label: '阻断事件', icon: blockEventIcon, markerIcon: blockEventMarkerIcon },
|
||||||
{ key: 'emergencyForce', label: '应急力量', icon: emergencyForceIcon, markerIcon: emergencyForceMarkerIcon },
|
{ key: 'emergencyForce', label: '应急力量', icon: emergencyForceIcon, markerIcon: emergencyForceMarkerIcon },
|
||||||
{ key: 'weatherAlert', label: '气象预警', icon: weatherAlertIcon, markerIcon: weatherAlertIcon }
|
{ key: 'weatherAlert', label: '气象预警', icon: weatherAlertIcon, markerIcon: weatherAlertMarkerIcon }
|
||||||
]
|
]
|
||||||
|
|
||||||
// 定义 props
|
// 定义 props
|
||||||
@ -103,6 +104,14 @@ const props = defineProps({
|
|||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key显示对应图例
|
||||||
|
*/
|
||||||
|
legendKeys: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker 数据配置(可选)
|
* Marker 数据配置(可选)
|
||||||
* 如果提供,将在事件中传递完整的 marker 数据
|
* 如果提供,将在事件中传递完整的 marker 数据
|
||||||
@ -135,10 +144,10 @@ const props = defineProps({
|
|||||||
* 兼容旧版:标记点切换回调函数
|
* 兼容旧版:标记点切换回调函数
|
||||||
* @deprecated 推荐使用 @marker-toggle 事件
|
* @deprecated 推荐使用 @marker-toggle 事件
|
||||||
*/
|
*/
|
||||||
onMarkerToggle: {
|
// onMarkerToggle: {
|
||||||
type: Function,
|
// type: Function,
|
||||||
default: null
|
// default: null
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义 emits
|
// 定义 emits
|
||||||
@ -146,6 +155,13 @@ const emit = defineEmits(['marker-toggle', 'clear', 'update:modelValue', 'collap
|
|||||||
|
|
||||||
// 计算图例项配置(支持自定义)
|
// 计算图例项配置(支持自定义)
|
||||||
const computedLegendItems = computed(() => {
|
const computedLegendItems = computed(() => {
|
||||||
|
if(props.legendKeys && props.legendKeys.length > 0) {
|
||||||
|
return props.legendKeys.map(key => {
|
||||||
|
const item = defaultLegendItems.find(item => item.key === key)
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return props.legendItems && props.legendItems.length > 0
|
return props.legendItems && props.legendItems.length > 0
|
||||||
? props.legendItems
|
? props.legendItems
|
||||||
: defaultLegendItems
|
: defaultLegendItems
|
||||||
@ -260,7 +276,6 @@ const handleItemClick = (key) => {
|
|||||||
// 构建并发送事件
|
// 构建并发送事件
|
||||||
const payload = buildPayload(key, newIsActive)
|
const payload = buildPayload(key, newIsActive)
|
||||||
emit('marker-toggle', payload)
|
emit('marker-toggle', payload)
|
||||||
|
|
||||||
// 兼容旧版 props 回调
|
// 兼容旧版 props 回调
|
||||||
if (props.onMarkerToggle) {
|
if (props.onMarkerToggle) {
|
||||||
props.onMarkerToggle(
|
props.onMarkerToggle(
|
||||||
|
|||||||
@ -0,0 +1,99 @@
|
|||||||
|
import { newImageMarkTooltip } from '../components/ImageMarkTooltip'
|
||||||
|
|
||||||
|
// 专门用于绘制图片的api数据类
|
||||||
|
export default class ImageMarkData {
|
||||||
|
key = null
|
||||||
|
markerIcon = null
|
||||||
|
api = null
|
||||||
|
// 提示框实例,当鼠标移入或者点击图例时,需要获取到该实例
|
||||||
|
tooltip = null
|
||||||
|
onResponse = null
|
||||||
|
cacheData = null
|
||||||
|
expiresAt = null
|
||||||
|
abortController = null
|
||||||
|
/**
|
||||||
|
* 60秒内重复点击使用缓存数据,减少服务器压力
|
||||||
|
*/
|
||||||
|
cacheTime = 60 * 1000
|
||||||
|
|
||||||
|
constructor({ api, tooltip, onResponse }) {
|
||||||
|
this.api = api
|
||||||
|
this.response = onResponse
|
||||||
|
// 初始化提示框
|
||||||
|
this.tooltip = tooltip || newImageMarkTooltip()
|
||||||
|
}
|
||||||
|
|
||||||
|
getCache = () => {
|
||||||
|
// 检查缓存是否有效
|
||||||
|
if (
|
||||||
|
this.cacheData?.length &&
|
||||||
|
this.expiresAt > Date.now()
|
||||||
|
) {
|
||||||
|
return this.cacheData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request = async (params) => {
|
||||||
|
// 首先查看缓存是否可用
|
||||||
|
const cacheData = this.getCache()
|
||||||
|
if (cacheData) return cacheData
|
||||||
|
|
||||||
|
const controller = this.createAbortController()
|
||||||
|
const config = {}
|
||||||
|
if (controller) config.signal = controller.signal
|
||||||
|
let res = null
|
||||||
|
try {
|
||||||
|
res = await this.api(params, config)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('请求失败: ', error)
|
||||||
|
} finally {
|
||||||
|
let data = null
|
||||||
|
if (this.response) data = this.response(res)
|
||||||
|
else data = this.commonOnResponse(res)
|
||||||
|
|
||||||
|
this.cacheData = data
|
||||||
|
this.expiresAt = Date.now() + this.cacheTime
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createAbortController = () => {
|
||||||
|
if (typeof AbortController === 'undefined') {
|
||||||
|
console.warn('当前环境不支持 AbortController')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return new AbortController()
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelRequest = () => {
|
||||||
|
if (this.abortController) {
|
||||||
|
try {
|
||||||
|
this.abortController.abort()
|
||||||
|
} catch (error) {
|
||||||
|
this.console.warn('取消请求失败', error)
|
||||||
|
} finally {
|
||||||
|
this.abortController = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用的响应处理
|
||||||
|
commonOnResponse = (res) => {
|
||||||
|
if (res?.success) {
|
||||||
|
res.data = res.data.slice(0, 2)
|
||||||
|
const dataList = res.data.map((item) => {
|
||||||
|
item.mapData = {
|
||||||
|
id: this.key + '-' + item.rid,
|
||||||
|
layerId: this.key,
|
||||||
|
position: [item.jd, item.wd, 0],
|
||||||
|
image: this.markerIcon
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
this.data = dataList
|
||||||
|
return dataList
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
63
packages/screen/src/views/cockpit/composables/useMapBase.js
Normal file
63
packages/screen/src/views/cockpit/composables/useMapBase.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { getBusinessBaseMapDDT, getBusinessBaseMapSI, test } from '@/views/cockpit/api/commonHttp.js'
|
||||||
|
|
||||||
|
// 当前页面的最基础地图服务
|
||||||
|
// 主要是加载地图底图
|
||||||
|
export const useMapBase = (mapStore) => {
|
||||||
|
|
||||||
|
const loadBusinessBaseMapDDT = async () => {
|
||||||
|
const layerService = mapStore.services().layer
|
||||||
|
const res = await getBusinessBaseMapDDT()
|
||||||
|
const data = [...res]
|
||||||
|
mapStore.baseMapGroups = data
|
||||||
|
for (const item of data) {
|
||||||
|
const layers = mapStore.getBaseMapLayersForGroup(item.Attribute?.rid || item.Rid)
|
||||||
|
for (const layerConfig of layers) {
|
||||||
|
const layer = {
|
||||||
|
id: layerConfig.id,
|
||||||
|
type: layerConfig.type,
|
||||||
|
url: layerConfig.url,
|
||||||
|
meta: layerConfig.meta,
|
||||||
|
options: {
|
||||||
|
parameters: {
|
||||||
|
srs: 'EPSG:3857',
|
||||||
|
transparent: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
await layerService.addLayer(layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadBusinessBaseMapLayerSI = async () => {
|
||||||
|
const layerService = mapStore.services().layer
|
||||||
|
const res = await getBusinessBaseMapSI()
|
||||||
|
const data = [...res]
|
||||||
|
mapStore.baseMapGroups = data
|
||||||
|
for (const item of data) {
|
||||||
|
const layers = mapStore.getBaseMapLayersForGroup(item.Attribute?.rid || item.Rid)
|
||||||
|
for (const layerConfig of layers) {
|
||||||
|
const layer = {
|
||||||
|
id: layerConfig.id,
|
||||||
|
type: layerConfig.type,
|
||||||
|
url: layerConfig.url,
|
||||||
|
meta: layerConfig.meta,
|
||||||
|
}
|
||||||
|
await layerService.addLayer(layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadBaseData = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
// loadBusinessBaseMapDDT()
|
||||||
|
// test()
|
||||||
|
loadBusinessBaseMapLayerSI()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadBaseData
|
||||||
|
}
|
||||||
|
}
|
||||||
177
packages/screen/src/views/cockpit/composables/useMapImageMark.js
Normal file
177
packages/screen/src/views/cockpit/composables/useMapImageMark.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { fetchEmergencyForceList } from '@/views/cockpit/api/emergencyForce'
|
||||||
|
|
||||||
|
import ImageMarkData from './ImageMarkData'
|
||||||
|
import * as Cesium from 'cesium'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前业务下的地图服务
|
||||||
|
* 主要是涉及需要调用后端服务获得地图数据
|
||||||
|
* */
|
||||||
|
|
||||||
|
export const useMapImageMark = (mapStore) => {
|
||||||
|
|
||||||
|
// mapStore准备就绪进行初始化
|
||||||
|
mapStore.onReady(() => init())
|
||||||
|
|
||||||
|
// 接口服务映射
|
||||||
|
const imageMarkMap = {
|
||||||
|
serviceFacility: new ImageMarkData({
|
||||||
|
api: fetchEmergencyForceList,
|
||||||
|
}),
|
||||||
|
riskRoad: new ImageMarkData({
|
||||||
|
api: fetchEmergencyForceList,
|
||||||
|
}),
|
||||||
|
blockEvent: new ImageMarkData({
|
||||||
|
api: fetchEmergencyForceList,
|
||||||
|
}),
|
||||||
|
weatherAlert: new ImageMarkData({
|
||||||
|
api: fetchEmergencyForceList,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let entityService
|
||||||
|
let viewer
|
||||||
|
let handler
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
entityService = mapStore.services().entity
|
||||||
|
viewer = mapStore.getViewer()
|
||||||
|
|
||||||
|
// 事件注册
|
||||||
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
|
||||||
|
|
||||||
|
// 点击事件
|
||||||
|
handler.setInputAction(function (event) {
|
||||||
|
const pickedFeature = viewer.scene.pick(event.position);
|
||||||
|
if (pickedFeature?.id) {
|
||||||
|
const entity = pickedFeature.id
|
||||||
|
const data = entity.properties.originalData.getValue()
|
||||||
|
const imageMarkData = imageMarkMap[data.mapData.layerId]
|
||||||
|
imageMarkData.tooltip.show({
|
||||||
|
data,
|
||||||
|
entity,
|
||||||
|
position: getScreenPosition(entity)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||||
|
|
||||||
|
// 帧渲染函数,也就是显示器的每一帧都会执行
|
||||||
|
// 地图拖动与放大的监控,需要更新各个tooltips的位置, 通过消息来通知
|
||||||
|
viewer.scene.postRender.addEventListener(() => {
|
||||||
|
for(const key in imageMarkMap) {
|
||||||
|
const imageMarkData = imageMarkMap[key]
|
||||||
|
const entity = imageMarkData.tooltip.entity
|
||||||
|
if(!entity) continue
|
||||||
|
imageMarkData.tooltip.updatePosition(getScreenPosition(entity))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制各个地图标,例如点击LengendItem的某一项,就会显示对应的图标列表
|
||||||
|
*/
|
||||||
|
const drawImageEntities = async (dataList) => {
|
||||||
|
for (const item of dataList) {
|
||||||
|
const mapData = item.mapData
|
||||||
|
entityService.addBillboard({
|
||||||
|
id: mapData.id,
|
||||||
|
layerId: mapData.layerId,
|
||||||
|
position: mapData.position,
|
||||||
|
image: mapData.image,
|
||||||
|
width: mapData.width || 44,
|
||||||
|
height: mapData.height || 44,
|
||||||
|
clampToGround: true,
|
||||||
|
properties: { originalData: item }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 清除某个图层里的实体
|
||||||
|
*/
|
||||||
|
const clearLayerEntity = (layerId) => {
|
||||||
|
entityService.clearLayerEntities(layerId)
|
||||||
|
const imageMarkData = imageMarkMap[layerId]
|
||||||
|
if (!imageMarkData) return
|
||||||
|
imageMarkData.tooltip.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据图标名称请求后台服务,动态加载图标列表
|
||||||
|
*/
|
||||||
|
const loadDynamicMark = async ({ key, markerIcon, params }) => {
|
||||||
|
const imageMarkData = imageMarkMap[key]
|
||||||
|
if (!imageMarkData) return
|
||||||
|
imageMarkData.markerIcon = markerIcon
|
||||||
|
imageMarkData.key = key
|
||||||
|
const dataList = await imageMarkData.request(params)
|
||||||
|
|
||||||
|
drawImageEntities(dataList)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示/隐藏地图标
|
||||||
|
*/
|
||||||
|
const toggleMark = async ({ key, active, markerIcon, params }) => {
|
||||||
|
const imageMarkData = imageMarkMap[key]
|
||||||
|
|
||||||
|
if (!active) {
|
||||||
|
clearLayerEntity(key)
|
||||||
|
if (imageMarkData) imageMarkData.cancelRequest()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDynamicMark({ key, markerIcon, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得该实体位于屏幕的位置,用于html元素进行定位使用
|
||||||
|
*/
|
||||||
|
const getScreenPosition = (entity) => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const position = entity.position?.getValue(Cesium.JulianDate.now())
|
||||||
|
if (!position) return
|
||||||
|
|
||||||
|
// 处理 clampToGround 实体
|
||||||
|
// 对于使用 CLAMP_TO_GROUND 的 billboard,需要获取实际的地形高度
|
||||||
|
let clampedPosition = position
|
||||||
|
|
||||||
|
// 转换为地理坐标
|
||||||
|
const cartographic = Cesium.Cartographic.fromCartesian(position)
|
||||||
|
|
||||||
|
// 尝试获取地形高度
|
||||||
|
if (viewer.scene.globe) {
|
||||||
|
const height = viewer.scene.globe.getHeight(cartographic)
|
||||||
|
|
||||||
|
// 如果成功获取地形高度,使用地形高度重建位置
|
||||||
|
if (Cesium.defined(height)) {
|
||||||
|
cartographic.height = height
|
||||||
|
clampedPosition = Cesium.Cartographic.toCartesian(cartographic)
|
||||||
|
} else {
|
||||||
|
// 备用方案:尝试使用 clampToHeight
|
||||||
|
const clampedCartesian = viewer.scene.clampToHeight(position)
|
||||||
|
if (clampedCartesian) {
|
||||||
|
clampedPosition = clampedCartesian
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用修正后的位置进行屏幕坐标转换
|
||||||
|
const screenPosition = viewer.scene.cartesianToCanvasCoordinates(clampedPosition)
|
||||||
|
if (screenPosition) {
|
||||||
|
return screenPosition
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新 Tooltip 位置失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
toggleMark
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user