1016 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="emergency-plan-content">
<!-- 1. 现场指挥部 -->
<section class="plan-section">
<div class="section-header">
<img
src="../../assets/images/modal/弹窗title.png"
alt=""
class="title-icon"
/>
<h3 class="section-title">现场指挥部</h3>
</div>
<div class="section-body">
<div class="form-grid">
<div class="form-item">
<label>指挥长</label>
<el-select
v-model="formData.commander"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option label="陈前" value="陈前" />
<el-option label="王军" value="王军" />
<el-option label="李明" value="李明" />
<el-option label="张伟" value="张伟" />
</el-select>
</div>
<div class="form-item">
<label>副指挥长</label>
<el-select
v-model="formData.viceCommander"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option label="樵继川" value="樵继川" />
<el-option label="刘勇" value="刘勇" />
<el-option label="陈强" value="陈强" />
<el-option label="赵军" value="赵军" />
</el-select>
</div>
</div>
</div>
</section>
<!-- 2. 多路协同处置三级指挥中心 -->
<section class="plan-section">
<div class="section-header">
<img
src="../../assets/images/modal/弹窗title.png"
alt=""
class="title-icon"
/>
<h3 class="section-title">多路协同处置三级指挥中心</h3>
</div>
<div class="section-body">
<div class="form-grid grid-2x2">
<div class="form-item">
<label>交通管控</label>
<el-select
v-model="formData.trafficControl"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option
label="忠县交通巡逻警察大队"
value="忠县交通巡逻警察大队"
/>
<el-option
label="公安交警、交通执法队"
value="公安交警、交通执法队"
/>
<el-option label="交通管理局" value="交通管理局" />
</el-select>
</div>
<div class="form-item">
<label>交通信息发布</label>
<el-select
v-model="formData.infoRelease"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option label="融媒体中心" value="融媒体中心" />
<el-option label="新闻中心" value="新闻中心" />
</el-select>
</div>
<div class="form-item">
<label>人车调拨</label>
<el-select
v-model="formData.vehicleDispatch"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option
label="忠县交通运输综合执法支队"
value="忠县交通运输综合执法支队"
/>
<el-option label="xxx消防队" value="xxx消防队" />
<el-option label="应急救援队" value="应急救援队" />
</el-select>
</div>
<div class="form-item">
<label>人员救援</label>
<el-select
v-model="formData.personnelRescue"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option label="忠县人民医院" value="忠县人民医院" />
<el-option label="xx医院" value="xx医院" />
<el-option label="中心医院" value="中心医院" />
</el-select>
</div>
</div>
</div>
</section>
<!-- 3. 公路抢通方案 -->
<section class="plan-section">
<div class="section-header">
<img
src="../../assets/images/modal/弹窗title.png"
alt=""
class="title-icon"
/>
<h3 class="section-title">公路抢通方案</h3>
</div>
<div class="section-body">
<div class="form-grid grid-2-cols">
<div class="form-item">
<label>抢通方式</label>
<el-select
v-model="formData.clearanceMethod"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option
label="两端对接抢通,必要时开辟工作面"
value="两端对接抢通,必要时开辟工作面"
/>
<el-option label="单端推进抢通" value="单端推进抢通" />
<el-option label="多点同时作业" value="多点同时作业" />
</el-select>
</div>
<div class="form-item">
<label>预计抢通时间</label>
<el-select
v-model="formData.estimatedTime"
class="custom-select"
popper-class="custom-dropdown"
>
<el-option label="6小时" value="6小时" />
<el-option label="8小时" value="8小时" />
<el-option label="12小时" value="12小时" />
<el-option label="24小时" value="24小时" />
</el-select>
</div>
</div>
<div class="plan-steps">
<div v-for="step in clearanceSteps" :key="step.id" class="step-item">
<label class="step-label">{{ step.number }}{{ step.title }}</label>
<el-input
v-model="step.content"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
class="step-content-input"
/>
</div>
</div>
</div>
</section>
<!-- 4. 力量调派方案 -->
<section class="plan-section">
<div class="section-header">
<img
src="../../assets/images/modal/弹窗title.png"
alt=""
class="title-icon"
/>
<h3 class="section-title">力量调派方案</h3>
<button class="add-btn" @click="handleAddPlan">
<span class="add-icon">+</span>
<span>新增</span>
</button>
</div>
<div class="section-body">
<div class="dispatch-plans">
<div
v-for="plan in dispatchPlans"
:key="plan.id"
class="dispatch-card"
>
<button
class="close-btn"
@click="handleDeletePlan(plan.id)"
title="删除"
>
×
</button>
<h4 class="plan-name">
<span class="plan-icon"></span>
基地{{ plan.id }}{{ plan.stationName || "xxxxx名称" }}
</h4>
<div class="resource-grid">
<div
v-for="(resource, index) in plan.resources"
:key="index"
class="resource-item"
>
<span class="resource-label">{{ resource.label }}</span>
<span class="resource-value">{{ resource.value }}</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 5. 后续处治 -->
<section class="plan-section">
<div class="section-header">
<img
src="../../assets/images/modal/弹窗title.png"
alt=""
class="title-icon"
/>
<h3 class="section-title">后续处治</h3>
</div>
<div class="section-body">
<el-input
v-model="followUpText"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
class="follow-up-textarea"
/>
</div>
</section>
</div>
</template>
<script setup>
import { ref, reactive, computed, watch } from "vue";
/**
* Props 定义
*/
const props = defineProps({
stations: {
type: Array,
default: () => [],
},
});
/**
* 可用站点列表(从快速匹配传入)
*/
const availableStations = computed(() => props.stations);
/**
* 表单数据
*/
const formData = reactive({
commander: "陈前",
viceCommander: "樵继川",
trafficControl: "忠县交通巡逻警察大队",
infoRelease: "融媒体中心",
vehicleDispatch: "忠县交通运输综合执法支队",
personnelRescue: "忠县人民医院",
clearanceMethod: "两端对接抢通,必要时开辟工作面",
estimatedTime: "6小时",
});
/**
* 公路抢通方案步骤
*/
const clearanceSteps = reactive([
{
id: 1,
number: "①",
title: "评估封控",
content:
"对现场进行封闭,落实告警阻拦措施;对灾毁周边稳定性进行评估,划定作业区与危险区,设立观察哨,全程监控边坡状态。",
},
{
id: 2,
number: "②",
title: "边坡排险",
content:
"在确保安全的前提下,使用长臂挖掘机或人工在安全绳保护下对坡面上已松动、悬空的岩石和土体进行清除,注意下方暂停作业。",
},
{
id: 3,
number: "③",
title: "梯形清方",
content:
'挖掘机在最前方、负责将塌方体挖松,装载机将土石料装入渣土车,渣土车编队运输,将废料运至指定弃渣场。确保挖掘机、装载机、渣土车数量匹配,形成高效的"挖一装一运"循环。',
},
{
id: 4,
number: "④",
title: "开辟工作面",
content:
"根据抢通和救援要求,利用挖掘机、装载机或无人设备开辟新的工作面,增加作业效率。",
},
{
id: 5,
number: "⑤",
title: "交通疏导",
content:
"清理出足够疏散车辆的临时性通道,临时通道边缘用锥桶或沙袋进行警示和防护,在现场指挥下,放行积压车辆。",
},
{
id: 6,
number: "⑥",
title: "全断面抢通",
content: "将剩余塌方体彻底清理,恢复路面原状。",
},
]);
/**
* 力量调派预案
*/
const dispatchPlans = ref([
{
id: 1,
stationName: "", // 站点名称,从 stations 自动赋值
resources: [
{ label: "轮式挖掘机", value: "1台" },
{ label: "平板拖车", value: "1台" },
{ label: "自卸货车", value: "4台" },
{ label: "工程车", value: "1台" },
{ label: "装载机", value: "1台" },
{ label: "人员", value: "15人" },
{ label: "锥桶", value: "30件" },
{ label: "铁锹", value: "10件" },
{ label: "雪糕筒", value: "50件" },
{ label: "标志标牌", value: "5块" },
{ label: "麻袋、砂石袋等", value: "若干" },
],
},
{
id: 2,
stationName: "",
resources: [
{ label: "轮式挖掘机", value: "1台" },
{ label: "平板拖车", value: "1台" },
{ label: "自卸货车", value: "4台" },
{ label: "工程车", value: "1台" },
{ label: "装载机", value: "15台" },
{ label: "人员", value: "5人" },
{ label: "锥桶", value: "30件" },
{ label: "铁锹", value: "10件" },
{ label: "雪糕筒", value: "50件" },
{ label: "标志标牌", value: "5块" },
{ label: "麻袋、砂石袋等", value: "若干" },
],
},
]);
/**
* 后续处治文本
*/
const followUpText = ref(
"将该处作为重大涉灾隐患点,设置“注意落石、观察通行”等标志,进行提级管控,进行边坡治理或设置监测预警设备。"
);
/**
* 根据站点索引获取站点名称
* @param {number} index - 站点索引从0开始
* @returns {string} 站点名称
*/
const getStationNameByIndex = (index) => {
if (availableStations.value && availableStations.value.length > index) {
return availableStations.value[index].name;
}
return "";
};
/**
* 自动为所有基地分配站点名称
*/
const assignStationNames = () => {
dispatchPlans.value.forEach((plan, index) => {
plan.stationName = getStationNameByIndex(index);
});
};
/**
* 监听站点数据变化,自动分配站点名称
*/
watch(
() => props.stations,
(newStations) => {
console.log("[EmergencyPlanContent] 站点数据变化检测:", newStations);
if (newStations && newStations.length > 0) {
assignStationNames();
console.log("[EmergencyPlanContent] 站点数据更新,自动分配站点名称");
console.log("[EmergencyPlanContent] 当前基地列表:", dispatchPlans.value);
} else {
console.log("[EmergencyPlanContent] 站点数据为空或未定义");
}
},
{ immediate: true, deep: true }
);
/**
* 处理新增预案按钮点击
*/
const handleAddPlan = () => {
// 暂时禁止新增预案
return;
console.log("[EmergencyPlanContent] 点击新增预案");
const newId = Math.max(...dispatchPlans.value.map((p) => p.id)) + 1;
const newIndex = dispatchPlans.value.length;
dispatchPlans.value.push({
id: newId,
stationName: getStationNameByIndex(newIndex),
resources: [
{ label: "轮式挖掘机", value: "1台" },
{ label: "平板拖车", value: "1台" },
{ label: "自卸货车", value: "4台" },
{ label: "工程车", value: "1台" },
{ label: "装载机", value: "15台" },
{ label: "人员", value: "5人" },
{ label: "锥桶", value: "30件" },
{ label: "铁锹", value: "10件" },
{ label: "雪糕筒", value: "50件" },
{ label: "标志标牌", value: "5块" },
{ label: "麻袋、砂石袋等", value: "若干" },
],
});
};
/**
* 处理删除预案
*/
const handleDeletePlan = (id) => {
// 暂时禁止删除预案
return;
console.log("[EmergencyPlanContent] 删除预案", id);
const index = dispatchPlans.value.findIndex((p) => p.id === id);
if (index > -1) {
dispatchPlans.value.splice(index, 1);
// 删除后重新分配站点名称,保持顺序
assignStationNames();
}
};
</script>
<style scoped lang="scss">
@use "@/styles/mixins.scss" as *;
.emergency-plan-content {
padding: 0;
color: var(--text-white);
}
/* 区块样式 */
.plan-section {
margin-bottom: vh(16);
// border: 1px solid rgba(28, 161, 255, 0.3);
border-radius: vw(4);
overflow: hidden;
&:last-child {
margin-bottom: 0;
}
}
/* 区块头部 */
.section-header {
display: flex;
align-items: center;
gap: vw(8);
padding: vh(2) vw(18);
background: #1f497a;
.title-icon {
width: vw(8);
height: vh(32);
object-fit: contain;
}
.section-title {
font-size: fs(18);
font-family: SourceHanSansCN-Bold, sans-serif;
font-weight: bold;
color: var(--text-white);
margin: 0;
}
.add-btn {
margin-left: auto;
padding: vh(6) vw(16);
background: var(--primary-color);
border: none;
border-radius: vw(4);
color: var(--text-white);
font-size: fs(14);
font-family: SourceHanSansCN-Medium, sans-serif;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: vw(6);
.add-icon {
font-size: fs(18);
font-weight: bold;
line-height: 1;
}
&:hover {
background: var(--primary-light);
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
}
}
}
/* 区块内容 */
.section-body {
padding: vh(14) vw(18);
}
/* 表单网格 */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: vw(16) vh(12);
&.grid-2x2 {
grid-template-columns: repeat(2, 1fr);
}
&.grid-2-cols {
grid-template-columns: 1fr 1fr;
}
}
/* 表单项 */
.form-item {
display: flex;
align-items: center;
gap: vw(10);
label {
width: vw(100);
font-size: fs(14);
font-family: SourceHanSansCN-Regular, sans-serif;
color: var(--text-gray);
white-space: nowrap;
flex-shrink: 0;
}
// Element Plus el-select 自定义样式
:deep(.custom-select) {
width: 100%;
background: #052044 !important;
// 选择器容器
.el-select__wrapper {
background: #052044 !important;
box-shadow: none !important;
}
// 输入框包装器
.el-input {
background: #052044 !important;
&__wrapper {
background-color: #052044 !important;
background: #052044 !important;
border: 1px solid rgba(28, 161, 255, 0.3) !important;
border-radius: vw(4);
box-shadow: none !important;
padding: vh(6) vw(12);
transition: none !important;
&:hover {
border-color: var(--primary-color) !important;
background-color: #052044 !important;
background: #052044 !important;
}
&.is-focus,
&.is-focused {
border-color: var(--primary-color) !important;
box-shadow: none !important;
background-color: #052044 !important;
background: #052044 !important;
}
}
&__inner {
color: #fff !important;
font-size: fs(13);
font-family: SourceHanSansCN-Regular, sans-serif;
height: auto;
background-color: transparent !important;
background: transparent !important;
// 强制覆盖 placeholder 颜色,确保选中值为纯白色
&:not(:placeholder-shown) {
color: #fff !important;
opacity: 1 !important;
}
}
}
// 选择器内部的输入框
.el-input {
color: #fff !important;
opacity: 1 !important;
&__inner {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
// 覆盖所有可能的状态
&[readonly] {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
&:disabled {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
}
// 输入框后缀区域
&__suffix {
background-color: transparent !important;
background: transparent !important;
}
// 输入框前缀区域
&__prefix {
background-color: transparent !important;
background: transparent !important;
}
}
// 输入框文本
.el-select__input {
color: #fff !important;
opacity: 1 !important;
}
// 选中的值文本(优先级最高,放在最前)
.el-select__selected-item {
color: #fff !important;
opacity: 1 !important;
}
// placeholder 文本(只针对真正的 placeholder
.el-input__inner::placeholder {
color: rgba(255, 255, 255, 0.5) !important;
}
// 只在没有选中值时显示半透明的 placeholder
.el-select__placeholder.is-transparent {
color: rgba(255, 255, 255, 0.5) !important;
}
// 强制覆盖 input 元素的文本颜色(针对 readonly 状态)
input.el-input__inner {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
// 下拉箭头颜色
.el-select__caret {
color: var(--text-gray) !important;
}
// 清除按钮颜色
.el-select__clear {
color: var(--text-gray) !important;
}
// 选中的标签(多选时)
.el-select__tags {
background: transparent !important;
}
}
}
/* 方案步骤 */
.plan-steps {
margin-top: vh(16);
display: flex;
flex-direction: column;
gap: vh(12);
}
.step-item {
display: flex;
align-items: center;
gap: vw(10);
.step-label {
width: vw(100);
font-size: fs(14);
font-family: SourceHanSansCN-Regular, sans-serif;
color: var(--text-gray);
white-space: nowrap;
flex-shrink: 0;
}
.step-content {
flex: 1;
font-size: fs(13);
font-family: SourceHanSansCN-Regular, sans-serif;
line-height: 1.6;
color: var(--text-white);
padding: vh(8) vw(12);
background: #052044;
border-radius: vw(4);
}
.step-content-input {
flex: 1;
:deep(.el-textarea__inner) {
background: #052044 !important;
border: none !important;
box-shadow: 0 0 0 1px rgba(28, 161, 255, 0.3) inset !important;
border-radius: vw(4);
color: var(--text-white);
font-size: fs(13);
font-family: SourceHanSansCN-Regular, sans-serif;
line-height: 1.6;
padding: vh(8) vw(12);
transition: box-shadow 0.3s ease;
overflow: hidden !important;
// resize: none !important;
&:hover {
box-shadow: 0 0 0 1px var(--primary-color) inset !important;
}
&:focus,
&:focus-visible {
box-shadow: 0 0 0 1px var(--primary-color) inset !important;
outline: none !important;
}
&::placeholder {
color: rgba(255, 255, 255, 0.3);
}
}
}
}
/* 调派预案 */
.dispatch-plans {
display: flex;
flex-direction: column;
gap: vh(12);
}
.dispatch-card {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(28, 161, 255, 0.2);
border-radius: vw(8);
padding: vh(12) vw(14);
position: relative;
.close-btn {
position: absolute;
top: vh(12);
right: vw(14);
width: vw(24);
height: vw(24);
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.3);
background: transparent;
color: rgba(255, 255, 255, 0.6);
font-size: fs(20);
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:hover {
background: rgba(255, 77, 79, 0.2);
border-color: #ff4d4f;
color: #ff4d4f;
transform: rotate(90deg);
}
&:active {
transform: rotate(90deg) scale(0.95);
}
}
.plan-name {
font-size: fs(15);
font-family: SourceHanSansCN-Bold, sans-serif;
font-weight: bold;
color: var(--text-white);
margin: 0 vw(30) vh(10) 0;
.plan-icon {
display: inline-block;
width: 9px;
height: 9px;
border: 2px solid #4fecff;
border-radius: 50%;
margin-right: 4px;
}
}
.resource-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: vw(8) vh(8);
}
.resource-item {
display: flex;
// flex-direction: column;
gap: vh(2);
.resource-label {
font-size: fs(12);
font-family: SourceHanSansCN-Regular, sans-serif;
color: var(--text-gray);
width: vw(100);
}
.resource-value {
font-size: fs(13);
font-family: SourceHanSansCN-Medium, sans-serif;
font-weight: 500;
color: var(--text-white);
}
}
}
/* 后续处治文本 */
.follow-up-text {
font-size: fs(13);
font-family: SourceHanSansCN-Regular, sans-serif;
line-height: 1.8;
color: var(--text-white);
margin: 0;
padding: vh(10) vw(14);
background: #052044;
border-radius: vw(4);
}
.follow-up-textarea {
:deep(.el-textarea__inner) {
background: #052044 !important;
border: none !important;
box-shadow: 0 0 0 1px rgba(28, 161, 255, 0.3) inset !important;
border-radius: vw(4);
color: var(--text-white);
font-size: fs(13);
font-family: SourceHanSansCN-Regular, sans-serif;
line-height: 1.8;
padding: vh(10) vw(14);
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: 0 0 0 1px var(--primary-color) inset !important;
}
&:focus,
&:focus-visible {
box-shadow: 0 0 0 1px var(--primary-color) inset !important;
outline: none !important;
}
&::placeholder {
color: rgba(255, 255, 255, 0.3);
}
}
}
</style>
<style lang="scss">
// 全局样式el-select 输入框背景和文字颜色(强制覆盖)
.custom-select {
.el-input__wrapper {
background-color: #052044 !important;
background: #052044 !important;
}
.el-input {
background-color: #052044 !important;
background: #052044 !important;
color: #fff !important;
opacity: 1 !important;
&__inner {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
// 覆盖所有可能的状态
&[readonly] {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
&:disabled {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
// 强制覆盖 placeholder 颜色,确保选中值为纯白色
&:not(:placeholder-shown) {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
}
}
// 输入框文本
.el-select__input {
color: #fff !important;
opacity: 1 !important;
}
// 选中的值(优先级最高,先定义)
.el-select__selected-item {
color: #fff !important;
opacity: 1 !important;
}
// placeholder 文本(只针对真正的 placeholder
.el-input__inner::placeholder {
color: rgba(255, 255, 255, 0.5) !important;
}
// 只在没有选中值时显示半透明的 placeholder
.el-select__placeholder.is-transparent {
color: rgba(255, 255, 255, 0.5) !important;
}
// 强制覆盖 input 元素的文本颜色(针对 readonly 状态)
input.el-input__inner {
color: #fff !important;
opacity: 1 !important;
-webkit-text-fill-color: #fff !important;
}
}
// 全局样式:下拉面板(挂载在 body 上,需要非 scoped 样式)
.custom-dropdown {
background: #052044 !important;
border: 1px solid rgba(28, 161, 255, 0.3) !important;
// 下拉列表容器
.el-select-dropdown__wrap {
background: #052044 !important;
}
// 下拉列表
.el-select-dropdown__list {
background: #052044 !important;
padding: 0;
}
// 下拉选项
.el-select-dropdown__item {
background: #052044 !important;
color: #fff;
font-size: 13px;
font-family: SourceHanSansCN-Regular, sans-serif;
&:hover {
background: rgba(28, 161, 255, 0.2) !important;
}
&.is-selected {
background: rgba(28, 161, 255, 0.3) !important;
color: #fff;
font-weight: 500;
}
&.is-hovering {
background: rgba(28, 161, 255, 0.2) !important;
}
}
// 空状态文字颜色
.el-select-dropdown__empty {
color: rgba(179, 204, 226, 1);
background: #052044 !important;
}
// 滚动条样式
.el-scrollbar__view {
background: #052044 !important;
}
}
</style>