HTML form readonly SELECT tag/input

题意

HTML表单只读SELECT标签/输入框

问题背景:

According to HTML specs, the select tag in HTML doesn't have a readonly attribute, only a disabled attribute. So if you want to keep the user from changing the dropdown, you have to use disabled.

根据HTML规范,HTML中的select标签没有readonly属性,只有disabled属性。所以,如果你想防止用户更改下拉菜单,必须使用disabled。

The only problem is that disabled HTML form inputs don't get included in the POST / GET data.

唯一的问题是,禁用的HTML表单输入不会包含在POST/GET数据中。

What's the best way to emulate the readonly attribute for a select tag, and still get the POST data?

模拟select标签的readonly属性并仍然获取POST数据的最佳方法是什么?

问题解决:

You should keep the select element disabled but also add another hidden input with the same name and value.

你应该保持select元素为禁用状态,但同时添加另一个具有相同名称和值的隐藏输入框。

If you reenable your SELECT, you should copy its value to the hidden input in an onchange event and disable (or remove) the hidden input.

如果你重新启用SELECT,应该在onchange事件中将其值复制到隐藏输入框,并禁用(或移除)隐藏输入框。

Here is a demo:

这是示例:

$('#mainform').submit(function() {
    $('#formdata_container').show();
    $('#formdata').html($(this).serialize());
    return false;
});

$('#enableselect').click(function() {
    $('#mainform input[name=animal]')
        .attr("disabled", true);
    
    $('#animal-select')
        .attr('disabled', false)
    	.attr('name', 'animal');
    
    $('#enableselect').hide();
    return false;
});
#formdata_container {
    padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
    <form id="mainform">
        <select id="animal-select" disabled="true">
            <option value="cat" selected>Cat</option>
            <option value="dog">Dog</option>
            <option value="hamster">Hamster</option>
        </select>
        <input type="hidden" name="animal" value="cat"/>
        <button id="enableselect">Enable</button>
        
        <select name="color">
            <option value="blue" selected>Blue</option>
            <option value="green">Green</option>
            <option value="red">Red</option>
        </select>

        <input type="submit"/>
    </form>
</div>

<div id="formdata_container" style="display:none">
    <div>Submitted data:</div>
    <div id="formdata">
    </div>
</div>

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>总订单完成状况</title> <style> :root{ --bg:#f5faff; --panel:#fff; --border:#cce7ff; --primary:#3ca9ff; --primary-dark:#0077e6; --primary-light:#e6f4ff; --text:#003366; --text-light:#0077e6; --shadow:rgba(60,169,255,.12); } body{margin:0;background:var(--bg);font-family:"Segoe UI",Arial,"PingFang SC","Microsoft YaHei",sans-serif} .status-container{max-width:98%;margin:22px auto;background:var(--panel);border:1px solid var(--border);padding:22px 18px 30px 18px;border-radius:12px;box-shadow:0 6px 30px var(--shadow);position:relative} .status-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;background:var(--bg)} .status-header h3{color:var(--text-light);letter-spacing:2px} .status-header .btns{display:flex;gap:12px} .btn{padding:7px 18px;border:none;border-radius:4px;font-size:15px;cursor:pointer;background:var(--primary);color:#fff;transition:background .2s} .btn:hover{background:var(--primary-dark)} .btn.modify{background:var(--primary-light);color:var(--text)} .btn.modify:hover{background:var(--primary-dark);color:#fff} .search-box{display:flex;align-items:center;gap:8px} .search-box input{height:32px;border:1px solid var(--primary);border-radius:4px;padding:0 10px;font-size:14px;background:#fff;color:var(--text)} table{width:100%;border-collapse:collapse;font-size:14px;color:var(--text)} thead{background-color:var(--primary-light);color:var(--text)} th,td{border:1px solid var(--border);padding:9px 7px;text-align:center} th{background:var(--primary-light);color:var(--text)} tr:nth-child(even){background:var(--bg)} .tag{border-radius:10px;padding:2px 10px;font-size:13px;display:inline-block} .tag-success{background:#d0ffd0;color:#006100} .tag-danger{background:#ffecec;color:#c00000;cursor:pointer} td:last-child{white-space:nowrap;min-width:120px} /* 弹窗 */ .modal-mask{position:fixed;left:0;top:0;width:100%;height:100%;background:rgba(0,119,230,.2);z-index:999;display:none} .modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);background:#fff;min-width:360px;border-radius:8px;box-shadow:0 8px 32px rgba(60,169,255,.15);padding:22px;z-index:1000;display:none} .modal-title{font-weight:bold;font-size:1.18rem;color:var(--primary-dark);margin-bottom:19px} .modal-form-row{margin-bottom:13px;display:flex;align-items:center} .modal-form-row label{width:86px;color:var(--text-light);font-size:14px} .modal-form-row input,.modal-form-row select{flex:1;height:28px;padding:0 7px;border:1px solid var(--primary);border-radius:4px;background:var(--bg);color:var(--text)} .modal-btns{text-align:right;margin-top:18px} .modal-btns .btn{margin-left:12px;background:var(--primary)} /* 分页 */ .pager-box{display:flex;align-items:center;gap:8px;position:absolute;right:22px;bottom:-80px;background:var(--primary-light);padding:6px 10px;border-radius:6px;box-shadow:0 2px 8px var(--shadow);font-size:14px;color:var(--text-light)} .pager-label input{width:46px;height:24px;text-align:center;border:1px solid var(--primary);border-radius:4px;margin:0 4px;background:#fff;color:var(--text-light)} </style> </head> <body> <div class="status-container"> <div class="status-header"> <h3>总订单完成状况</h3> <div class="btns"> <div class="search-box"> <input type="text" id="searchInput" placeholder="订单编号、产品名称...关键词查询"> <button class="btn" onclick="searchOrders()">查询</button> </div> <button class="btn" onclick="openAddModal()">增加</button> </div> </div> <table> <thead> <tr> <th>序号</th><th>销售类型</th><th>订单编号</th><th>产品编号</th><th>产品名称</th> <th>订单数量</th><th>GTM要求交期</th><th>订单评审出货日期</th> <th>电子料齐套</th><th>组装料齐套</th> <th>SMT累计出货</th><th>SMT欠订单数</th><th>SMT工厂</th> <th>组装累计出货</th><th>组装欠订单数</th><th>组装工厂</th> <th>结单状况</th><th>备注</th><th>操作</th> </tr> </thead> <tbody id="orderTableBody"><tr><td colspan="19">加载中...</td></tbody> </table> <div id="pagerBox" class="pager-box"> <button class="btn" id="btnPrev" onclick="prevPage()">上一页</button> <label class="pager-label"> 第<input type="number" id="pageInput" min="1" max="1" value="1" onkeydown="if(event.key==='Enter') jumpToPage()">页 / 共<span id="totalPages">1</span>页 </label> <button class="btn" id="btnNext" onclick="nextPage()">下一页</button> <button class="btn modify" onclick="jumpToPage()">跳转</button> </div> </div> <!-- 订单弹窗 --> <div class="modal-mask" id="modalMask"></div> <div class="modal" id="modalBox"> <div class="modal-title" id="modalTitle">新增订单</div> <form id="modalForm"> <div class="modal-form-row"><label>销售类型</label><input name="saleType" required></div> <div class="modal-form-row"><label>订单编号</label><input name="orderNo" required></div> <div class="modal-form-row"><label>产品编号</label><input name="productNo" required></div> <div class="modal-form-row"><label>产品名称</label><input name="productName" required></div> <div class="modal-form-row"><label>订单数量</label><input type="number" name="orderQuantity" required></div> <div class="modal-form-row"><label>GTM交期</label><input type="date" name="gtmDueDate"></div> <div class="modal-form-row"><label>评审出货日期</label><input type="date" name="reviewShipDate"></div> <div class="modal-form-row"><label>电子料齐套</label> <select name="materialElectronic"><option value="1">齐套</option><option value="0">未齐套</option></select></div> <div class="modal-form-row"><label>组装料齐套</label> <select name="materialAssembly"><option value="1">齐套</option><option value="0">未齐套</option></select></div> <div class="modal-form-row"><label>SMT累计出货</label><input type="number" name="smtShippedQty"></div> <div class="modal-form-row"><label>SMT欠订单数</label><input type="number" name="smtOwedQty"></div> <div class="modal-form-row"><label>SMT工厂</label><input name="smtFactory"></div> <div class="modal-form-row"><label>组装累计出货</label><input type="number" name="assemblyShippedQty"></div> <div class="modal-form-row"><label>组装欠订单数</label><input type="number" name="assemblyOwedQty"></div> <div class="modal-form-row"><label>组装工厂</label><input name="assemblyFactory"></div> <div class="modal-form-row"><label>接单状况</label><input name="receiveStatus"></div> <div class="modal-form-row"><label>备注</label><input name="remark"></div> <div class="modal-btns"> <button type="button" class="btn" onclick="closeModal()">取消</button> <button type="submit" class="btn modify" id="modalSubmitBtn">保存</button> </div> </form> </div> <!-- 通用 BOM 详情弹窗 --> <div class="modal-mask" id="bomModalMask"></div> <div class="modal" id="bomModalBox"> <div class="modal-title" id="bomModalTitle">BOM 齐套详情</div> <form id="bomModalForm"> <input type="hidden" id="bomType"> <input type="hidden" id="bomOrderNo"> <div class="modal-form-row"> <label>BOM 版本</label> <select id="bomVersionSelect" required></select> </div> <!-- 物料编码 --> <div class="modal-form-row"> <label>物料编码</label> <input type="text" id="materialCode" required placeholder="请输入物料编码"> </div> <!-- 物料名称 --> <div class="modal-form-row"> <label>物料名称</label> <input type="text" id="materialName" required placeholder="如:贴片电阻"> </div> <!-- 规格 --> <div class="modal-form-row"> <label>规格</label> <input type="text" id="specification" placeholder="如:0603 1KΩ ±1%"> </div> <!-- 技术参数 --> <div class="modal-form-row"> <label>技术参数</label> <input type="text" id="technicalParam" placeholder="如:阻值范围/温度系数"> </div> <!-- 参数值 --> <div class="modal-form-row"> <label>参数值</label> <input type="text" id="paramValue" placeholder="如:1KΩ/±100ppm/℃"> </div> <!-- 用量 --> <div class="modal-form-row"> <label>用量</label> <input type="number" id="quantity" required min="1" placeholder="单个产品所需数量"> </div> <!-- 制造商 --> <div class="modal-form-row"> <label>制造商</label> <input type="number" id="manufacturerSelect" required min="1" placeholder="单个产品所需数量"> </div> <!-- 制造商料号 --> <div class="modal-form-row"> <label>制造商料号</label> <input type="text" id="mpn" required placeholder="如:RC0603FR-071KL"> </div> <div class="modal-btns"> <button type="button" class="btn" onclick="closeBomModal()">取消</button> <button type="submit" class="btn modify">保存</button> </div> </form> </div> <!-- 电子料齐套弹窗 --> <div class="modal-mask" id="eBomModalMask"></div> <div class="modal" id="eBomModalBox"> <div class="modal-title">电子料齐套详情</div> <form id="eBomModalForm"> <div class="modal-form-row"><label>订单编号</label><input id="eBomOrderNo" readonly></div> <div class="modal-form-row"><label>BOM版本</label><select id="eBomVersionSelect" required></select></div> <div class="modal-form-row"><label>订单数量</label><input type="number" id="eBomOrderQty" min="1" required></div> <div class="modal-btns"> <button type="button" class="btn" onclick="closeEBomModal()">取消</button> <button type="submit" class="btn modify">保存</button> </div> </form> </div> <script> let editingId = null, allOrders = [], currentPage = 1, totalPages = 1; const eBomQtyCache = {}; // 已录入电子料齐套数量缓存 async function request(url, method='GET', body=null){ const res = await fetch(url, { method, headers: body ? {'Content-Type':'application/json'} : {}, body: body ? JSON.stringify(body) : undefined }); return res.json(); } async function loadOrders(keyword, page){ const tbody=document.getElementById('orderTableBody'); tbody.innerHTML='<tr><td colspan="19">加载中...</td></tr>'; try{ let url=`/api/orders?page=${page}&size=10`; if(keyword) url+=`&keyword=${encodeURIComponent(keyword)}`; const data=await request(url); allOrders=data.records; renderOrders(data.records); currentPage=data.current; totalPages=data.pages; updatePager(); }catch(e){ tbody.innerHTML='<tr><td colspan="19">加载失败</td></tr>'; } } function renderOrders(data){ const tbody=document.getElementById('orderTableBody'); if(!data.length){ tbody.innerHTML='<tr><td colspan="19">暂无数据</td></tr>'; return; } tbody.innerHTML=data.map(r=>` <tr> <td>${r.id}</td><td>${r.saleType||'-'}</td><td>${r.orderNo||'-'}</td><td>${r.productNo||'-'}</td><td>${r.productName||'-'}</td> <td>${r.orderQuantity??'-'}</td><td>${r.gtmDueDate||'-'}</td><td>${r.reviewShipDate||'-'}</td> <!-- 电子料齐套列:未齐套可点击 --> <td> <span class="tag ${r.materialElectronic?'tag-success':'tag-danger'}" style="cursor:${r.materialElectronic?'default':'pointer'}" onclick="${!r.materialElectronic?`openEBomDetailModal('${r.orderNo}',${r.orderQuantity||0})`:''}"> ${r.materialElectronic?'齐套':'未齐套'} </span> <button class="btn modify" style="font-size:12px;padding:2px 8px" onclick="openEBomDetailTable('${r.orderNo}')">详情</button> </td> <!-- 组装料齐套列:保持原状 --> <td> <span class="tag ${r.materialAssembly?'tag-success':'tag-danger'}"> ${r.materialAssembly?'齐套':'未齐套'} </span> <button class="btn modify" style="font-size:12px;padding:2px 8px" onclick="openBomDetail('assembly','${r.orderNo}',${r.orderQuantity||0})"> 详情 </button> </td> <td>${r.smtShippedQty??'-'}</td><td>${r.smtOwedQty??'-'}</td><td>${r.smtFactory||'-'}</td> <td>${r.assemblyShippedQty??'-'}</td><td>${r.assemblyOwedQty??'-'}</td><td>${r.assemblyFactory||'-'}</td> <td>${r.receiveStatus||'-'}</td><td>${r.remark||'-'}</td> <td> <button class="btn modify" onclick="openEditModal(${r.id})">修改</button> <button class="btn" style="margin-left:6px;background:#f56c6c" onclick="deleteOrder(${r.id})">删除</button> </td> </tr>`).join(''); } function searchOrders(){loadOrders(document.getElementById('searchInput').value.trim(),1);} function updatePager(){ const p=document.getElementById('pageInput'); p.max=totalPages; p.value=currentPage; document.getElementById('totalPages').textContent=totalPages; document.getElementById('btnPrev').disabled=currentPage<=1; document.getElementById('btnNext').disabled=currentPage>=totalPages; } function jumpToPage(){ const v=parseInt(document.getElementById('pageInput').value,10); if(v>=1&&v<=totalPages) loadOrders(document.getElementById('searchInput').value.trim(),v); } function prevPage(){if(currentPage>1) loadOrders(document.getElementById('searchInput').value.trim(),currentPage-1);} function nextPage(){if(currentPage<totalPages) loadOrders(document.getElementById('searchInput').value.trim(),currentPage+1);} /* 订单弹窗 */ function openAddModal(){editingId=null;resetModal('新增订单');} function openEditModal(id){ editingId=id; const r=allOrders.find(r=>r.id===id); resetModal('修改订单',r); } function resetModal(title,data={}){ document.getElementById('modalTitle').textContent=title; const f=document.getElementById('modalForm'); f.reset(); for(const k in data) if(f[k]!==undefined) f[k].value=data[k]; document.getElementById('modalMask').style.display='block'; document.getElementById('modalBox').style.display='block'; } function closeModal(){ document.getElementById('modalMask').style.display='none'; document.getElementById('modalBox').style.display='none'; } document.getElementById('modalMask').onclick=closeModal; document.getElementById('modalForm').onsubmit=async e=>{ e.preventDefault(); const fd=new FormData(e.target); const data=Object.fromEntries(fd); data.materialElectronic=data.materialElectronic==='1'; data.materialAssembly=data.materialAssembly==='1'; ['orderQuantity','smtShippedQty','smtOwedQty','assemblyShippedQty','assemblyOwedQty'] .forEach(k=>{if(data[k])data[k]=Number(data[k]);}); try{ const url=editingId?`/api/orders/${editingId}`:'/api/orders'; const meth=editingId?'PUT':'POST'; await request(url,meth,data); closeModal(); loadOrders('',currentPage); }catch{alert('保存失败');} }; async function deleteOrder(id){ if(!confirm(`确定删除订单 ${id} 吗?`)) return; try{ await request(`/api/orders/${id}`,'DELETE'); loadOrders(document.getElementById('searchInput').value.trim(),currentPage); }catch{alert('删除失败');} } /* ========= 通用 BOM 弹窗 ========= */ function openBomDetail(type, orderNo, orderQty){ document.getElementById('bomType').value = type; // electronic / assembly document.getElementById('bomOrderNo').value = orderNo; document.getElementById('bomModalTitle').textContent = (type === 'electronic' ? '电子料' : '组装料') + '齐套详情'; /* 拉取或初始化数据 */ fetchBomDetail(type, orderNo).then(data=>{ fillBomModal(data, orderQty); document.getElementById('bomModalMask').style.display='block'; document.getElementById('bomModalBox').style.display='block'; }); } async function fetchBomDetail(type, orderNo){ // 调用后端接口,返回 {bomVersion, orderQty, needQty, oweQty} const res = await request(`/api/bom_detail/${type}/${orderNo}`); return res || {}; } function fillBomModal(data, orderQty){ /* 版本下拉 */ const sel=document.getElementById('bomVersionSelect'); sel.innerHTML=''; const versions = JSON.parse(localStorage.getItem('eBomVersions')||'[]'); versions.forEach(v=>{ const opt=document.createElement('option'); opt.value=opt.textContent=v; if(v===data.bomVersion) opt.selected=true; sel.appendChild(opt); }); document.getElementById('bomOrderQty').value = data.orderQty ?? orderQty; document.getElementById('bomNeedQty').value = data.needQty ?? 0; document.getElementById('bomOweQty').value = data.oweQty ?? 0; } function closeBomModal(){ document.getElementById('bomModalMask').style.display='none'; document.getElementById('bomModalBox').style.display='none'; } document.getElementById('bomModalMask').onclick = closeBomModal; /* 保存 */ document.getElementById('bomModalForm').addEventListener('submit', async e=>{ e.preventDefault(); const type = document.getElementById('bomType').value; const orderNo= document.getElementById('bomOrderNo').value; const payload = { bomVersion : document.getElementById('bomVersionSelect').value, orderQty : Number(document.getElementById('bomOrderQty').value), needQty : Number(document.getElementById('bomNeedQty').value), oweQty : Number(document.getElementById('bomOweQty').value) }; try{ await request(`/api/bom_detail/${type}/${orderNo}`, 'POST', payload); alert('保存成功'); closeBomModal(); }catch{ alert('保存失败'); } }); /* 电子料齐套弹窗 */ function openEBomDetailModal(orderNo,orderQty){ document.getElementById('eBomOrderNo').value=orderNo; const cached=eBomQtyCache[orderNo]||0; document.getElementById('eBomOrderQty').value=cached; document.getElementById('eBomOrderQty').min=cached; const sel=document.getElementById('eBomVersionSelect'); sel.innerHTML=''; const versions=JSON.parse(localStorage.getItem('eBomVersions')||'[]'); if(!versions.length){alert('请先打开“电子料 BOM 明细”页面以同步 BOM 版本数据');return;} versions.forEach(v=>{ const opt=document.createElement('option'); opt.value=opt.textContent=v; sel.appendChild(opt); }); document.getElementById('eBomModalMask').style.display='block'; document.getElementById('eBomModalBox').style.display='block'; } function closeEBomModal(){ document.getElementById('eBomModalMask').style.display='none'; document.getElementById('eBomModalBox').style.display='none'; } document.getElementById('eBomModalMask').onclick=closeEBomModal; document.getElementById('eBomModalForm').addEventListener('submit',async e=>{ e.preventDefault(); const orderNo=document.getElementById('eBomOrderNo').value.trim(); const bomVersion=document.getElementById('eBomVersionSelect').value; const qty=Number(document.getElementById('eBomOrderQty').value); const cached=eBomQtyCache[orderNo]||0; if(qty<cached){alert('订单数量只能增加,不能减少!');return;} try{ await request('/api/electronic_bom_detail','POST',{orderNo,bomVersion,orderQty:qty}); eBomQtyCache[orderNo]=qty; alert('保存成功'); closeEBomModal(); }catch{alert('保存失败');} }); loadOrders('',1); </script> </body> </html>能不能给我当点击未齐套时页面跳转的具体流程,当我单击详情时该怎么实现页面跳转
最新发布
07-20
<template> <template v-if="videoPlayList.length"> <template v-for="(item, index) in videoPlayList"> <VideosPlay :data="item" :index="index" /> </template> </template> <div class="box"> <div class="top-select"> <el-select v-model="selectedLayer" placeholder="影像图层" class="select-1" :show-arrow="false" clearable @change="handleLayerChange" @clear="clearLayer" > <el-option v-for="(item, index) in layers" :key="item.id" :label="item.title" :value="item.id" /> </el-select> <el-select v-model="baseMap" placeholder="矢量地图" :show-arrow="false" class="select-2" @change="handleBaseMapChange" value-key="id" multiple collapse-tags > <el-option v-for="item in baseMapList" :key="item.name" :label="item.name" :value="item" /> </el-select> <el-select v-model="selectedTile" placeholder="实景三维" class="select-2" @change="handle3dSwitchChange" multiple collapse-tags :show-arrow="false" value-key="id" > <el-option v-for="tile in tileList" :key="tile.id" :label="tile.title" :value="tile" /> </el-select> <el-select v-model="selectedCommunity" placeholder="动态监测" class="select-3" @change="handleCommunityChange" :show-arrow="false" > <el-option v-for="community in communityList" :key="community.name" :label="community.name" :value="community.name" /> </el-select> </div> </div> <!-- 坐标系转换弹窗 --> <el-dialog v-model="showCoordinateModal" title="坐标系转换" width="400px" @close="resetCoordinateForm" > <el-form :model="coordForm" label-width="100px"> <!-- 源坐标系下拉菜单 --> <el-form-item label="源坐标系"> <el-select v-model="coordForm.source" placeholder="请选择源坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <!-- 目标坐标系下拉菜单 --> <el-form-item label="目标坐标系"> <el-select v-model="coordForm.target" placeholder="请选择目标坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <el-form-item label="经度"> <el-input v-model.number="coordForm.lng" placeholder="输入经度" clearable ></el-input> </el-form-item> <el-form-item label="纬度"> <el-input v-model.number="coordForm.lat" placeholder="输入纬度" clearable ></el-input> </el-form-item> <el-form-item label="转换结果"> <el-input :value="coordForm.result" readonly placeholder="转换结果将显示在这里" ></el-input> </el-form-item> </el-form> <template #footer> <el-button @click="showCoordinateModal = false">取消</el-button> <el-button type="primary" @click="convertCoordinates">转换</el-button> </template> </el-dialog> </template> <script setup lang="ts"> import { onMounted, ref, onUnmounted } from "vue"; import { $prototype } from "../../main.ts"; import { getVeidoDetail } from "@/service/index"; import { ElMessage } from "element-plus"; import MVTImageryProvider from "mvt-imagery-provider"; import "/public/lib/video/mpegts/mpegts.js"; import "/public/img/div-graphic/divGraphic.css"; import { vectorLayes } from "@/config/index.ts"; import VideosPlay from "@/components/video/index.vue"; import { RefreshLeft } from "@element-plus/icons-vue"; var viewer: any; const selectedLayer = ref("baseImagery"); const selectedTile = ref([]); const selectedCommunity = ref(""); const baseMap = ref([]); const videoPlayList = ref([]); const addedTilesets = ref<Record<string, Cesium.Cesium3DTileset[]>>({}); const addedMvtLayers = ref<Record<string, Cesium.ImageryLayer[]>>({}); // 坐标系转换相关 const showCoordinateModal = ref(false); const coordForm = ref({ source: "", // 源坐标系 target: "", // 目标坐标系 lng: 0, // 经度 lat: 0, // 纬度 result: "" // 转换结果 }); const layers = [ { id: "baseImagery", title: "卫星" }, { id: "zhuzhou_beidou:GF01", title: "高分1号卫星遥感影像" }, { id: "zhuzhou_beidou:GF02", title: "高分2号卫星遥感影像" }, { id: "zhuzhou_beidou:GF06", title: "高分6号卫星遥感影像" }, { id: "zhuzhou_beidou:GF07", title: "高分7号卫星遥感影像" }, { id: "zhuzhou_beidou:lkyx", title: "渌口区影像" }, ]; const tileList = [ { id: "tile1", url: [ "http://124.232.190.30:9000/proxy/pk1725973637070/map/3dmode/20220312-1302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973591120/map/3dmode/20220312-1301/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973529125/map/3dmode/2022022101/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973404863/map/3dmode/2022011302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973226672/map/3dmode/20220312/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952405569/map/3dmode/20220221/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952315227/map/3dmode/20220220/tileset.json", ], title: "会展中心", }, { id: "tile2", url: [ "http://124.232.190.30:9000/proxy/pk1725804650206/map/3dmode/hhhg/tileset.json", ], title: "园区", }, ]; const communityList = [ { name: "铁塔视频" }, ]; const baseMapList = [ { id: "geomeg", name: "基础地图", url: "http://124.232.190.30:3011//yjy_pbf/{z}/{x}/{y}.pbf", type: "fill" }, { id: "lukou_farmland", name: "耕地", url: "http://124.232.190.30:9059/lukou_farmland/{z}/{x}/{y}", type: "fill" }, { id: "lukou_ecology", name: "生态", url: "http://124.232.190.30:9059/lukou_ecology/{z}/{x}/{y}", type: "fill" }, { id: "natural_", name: "自然区", url: "http://124.232.190.30:9059/natural_/{z}/{x}/{y}", type: "fill" }, { id: "lushui_river", name: "渌水流域", url: "http://124.232.190.30:9059/lushui_river/{z}/{x}/{y}", type: "fill" }, { id: "mishui_river", name: "洣水流域", url: "http://124.232.190.30:9059/mishui_river/{z}/{x}/{y}", type: "fill" }, ]; const sprite = "http://124.232.190.67:5432/sprite/sprite"; const glyphs = "http://124.232.190.67:5432/font/mapbox_glyphs/{fontstack}/{range}.pbf"; const baseMapUrl = "http://124.232.190.30:3011//yjy_pbf/layers.json"; // 坐标系转换工具类 const CoordinateConverter = { a: 6378245.0, ee: 0.006693421622965943, // 判断是否在国内 outOfChina(lng: number, lat: number): boolean { return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271); }, // 纬度转换 transformLat(x: number, y: number): number { let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; return ret; }, // 经度转换 transformLng(x: number, y: number): number { let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; return ret; }, // WGS84转GCJ02 wgs84ToGcj02(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); return [lng + dLng, lat + dLat]; }, // GCJ02转WGS84 gcj02ToWgs84(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); const mgLat = lat + dLat; const mgLng = lng + dLng; return [lng * 2 - mgLng, lat * 2 - mgLat]; }, // GCJ02转BD09 gcj02ToBd09(lng: number, lat: number): [number, number] { const x = lng; const y = lat; const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006]; }, // BD09转GCJ02 bd09ToGcj02(lng: number, lat: number): [number, number] { const x = lng - 0.0065; const y = lat - 0.006; const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta), z * Math.sin(theta)]; }, // WGS84转BD09 wgs84ToBd09(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.wgs84ToGcj02(lng, lat); return this.gcj02ToBd09(gcjLng, gcjLat); }, // BD09转WGS84 bd09ToWgs84(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.bd09ToGcj02(lng, lat); return this.gcj02ToWgs84(gcjLng, gcjLat); } }; // 执行坐标系转换 function convertCoordinates() { const { source, target, lng, lat } = coordForm.value; // 验证输入 if (!source || !target) { ElMessage.warning('请选择源坐标系和目标坐标系'); return; } if (source === target) { ElMessage.info('源坐标系与目标坐标系相同,无需转换'); coordForm.value.result = `经度: ${lng.toFixed(6)}, 纬度: ${lat.toFixed(6)}`; return; } if (!lng || !lat || isNaN(lng) || isNaN(lat)) { ElMessage.warning('请输入有效的经纬度'); return; } if (lng < -180 || lng > 180 || lat < -90 || lat > 90) { ElMessage.warning('经纬度超出有效范围'); return; } // 执行转换 let result: [number, number] = [0, 0]; switch (true) { case source === "WGS84" && target === "GCJ02": result = CoordinateConverter.wgs84ToGcj02(lng, lat); break; case source === "GCJ02" && target === "WGS84": result = CoordinateConverter.gcj02ToWgs84(lng, lat); break; case source === "GCJ02" && target === "BD09": result = CoordinateConverter.gcj02ToBd09(lng, lat); break; case source === "BD09" && target === "GCJ02": result = CoordinateConverter.bd09ToGcj02(lng, lat); break; case source === "WGS84" && target === "BD09": const gcj = CoordinateConverter.wgs84ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToBd09(gcj[0], gcj[1]); break; case source === "BD09" && target === "WGS84": const gcj2 = CoordinateConverter.bd09ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToWgs84(gcj2[0], gcj2[1]); break; default: ElMessage.error("不支持的转换类型"); return; } coordForm.value.result = `经度: ${result[0].toFixed(6)}, 纬度: ${result[1].toFixed(6)}`; } // 重置转换表单 function resetCoordinateForm() { coordForm.value = { source: "", target: "", lng: 0, lat: 0, result: "" }; } // 基础地图切换处理 function handleBaseMapChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const mvtsToRemove = Object.keys(addedMvtLayers.value).filter( (mvtId) => !currentSelectedIds.includes(mvtId) ); mvtsToRemove.forEach((mvtId) => { const layersToRemove = addedMvtLayers.value[mvtId]; if (layersToRemove && layersToRemove.length > 0) { layersToRemove.forEach((layer) => { try { const layers = viewer.imageryLayers._layers; for (let i = layers.length - 1; i >= 0; i--) { if (layers[i]._imageryProvider?.id === mvtId) { viewer.imageryLayers.remove(layers[i]); } } } catch (e) { console.error("Error removing MVT layer:", e); } }); delete addedMvtLayers.value[mvtId]; } }); items.forEach((item: any) => { if (!addedMvtLayers.value[item.id] || addedMvtLayers.value[item.id].length === 0) { addedMvtLayers.value[item.id] = []; loadVectorMvt(item.url, item.id, item.type); } }); } // 视频关闭事件监听 $prototype.emitter.on("video-list-play-close", (_id) => { videoPlayList.value = videoPlayList.value.filter((v) => v.id != _id); }); // 加载矢量地图 async function loadVectorMvt(data, layerName, type) { var tt = { name: "maplibres_yw", type: "vector", tiles: [data], bounds: [-180, -85.051129, 180, 85.051129], scheme: "xyz", }; var layersMapbox = []; const sourcesMapbox: any = {}; if (layerName == "geomeg") { await fetch(baseMapUrl) .then((response) => response.json()) .then((data) => { layersMapbox = JSON.parse(JSON.stringify(data.layers)); }); } else if (vectorLayes[layerName] == undefined) { const currentLayers = JSON.parse(JSON.stringify(vectorLayes[layerName])); currentLayers["id"] = currentLayers["id"] + layerName; currentLayers["source-layer"] = layerName; currentLayers["source"] = layerName; layersMapbox.push(currentLayers); } else { layersMapbox = JSON.parse(JSON.stringify(vectorLayes[layerName])); } sourcesMapbox[layerName] = tt; var exampleStyle = { id: data.id, name: "MapLibre", zoom: 10, layers: layersMapbox, bearing: 0, sources: sourcesMapbox, version: 8, metadata: { "maptiler:copyright": "cxwl" }, }; exampleStyle.glyphs = glyphs; exampleStyle.sprite = sprite; let provider = new MVTImageryProvider({ style: exampleStyle }); provider.id = layerName; viewer.imageryLayers.addImageryProvider(provider); addedMvtLayers.value[layerName].push(provider); if (layerName === "lukou_farmland" || layerName === "lukou_ecology") { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.159047, 27.721148, 3270), duration: 3, }); } else { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.490927, 27.048641, 406000), duration: 3, }); } } // 动态监测处理 var videoData = [113.182301, 27.971201]; async function handleCommunityChange(item: any) { if (item == "铁塔视频") { var data = await getVeidoDetail(); if (data.data != null) { addRandomGraphicByCount(videoData, data.data); } else { ElMessage.error(data.message); } } } // 添加铁塔标记 function addRandomGraphicByCount(position, url) { viewer.entities.add({ id: "tietaId", beof: "铁塔视频", name: "铁塔视频001", position: Cesium.Cartesian3.fromDegrees(position[0], position[1]), billboard: { image: "img/marker/mark-spjk.png", width: 30, height: 115, scale: 1.0, color: Cesium.Color.WHITE, eyeOffset: new Cesium.Cartesian3(0, 0, -10), }, label: { text: "铁塔视频", font: "14px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -30), }, properties: { capacityResourceName: "铁塔视频", url: url, name: "铁塔视频", id: "tieta_001", }, }); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(position[0], position[1], 10000), duration: 3, }); } // 3D模型切换处理 function handle3dSwitchChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const tilesToRemove = Object.keys(addedTilesets.value).filter( (tileId) => !currentSelectedIds.includes(tileId) ); tilesToRemove.forEach((tileId) => { addedTilesets.value[tileId].forEach((tileset) => { try { if (tileset && !tileset.isDestroyed()) { tileset.destroy(); } viewer.scene.primitives.remove(tileset); } catch (e) { console.error("Error removing tileset:", e); } }); delete addedTilesets.value[tileId]; }); items.forEach((item: any) => { if (!addedTilesets.value[item.id]) { addedTilesets.value[item.id] = []; item.url.forEach((url: string) => { const tileset = new Cesium.Cesium3DTileset({ url: url, skipLevelOfDetail: true, skipScreenSpaceErrorFactor: 16, baseScreenSpaceError: 1024, maximumScreenSpaceError: 10, immediatelyLoadDesiredLevelOfDetail: false, loadSiblings: false, cullWithChildrenBounds: true, cullRequestsWhileMoving: true, cullRequestsWhileMovingMultiplier: 10, preloadWhenHidden: true, preferLeaves: true, maximumMemoryUsage: 2048, progressiveResolutionHeightFraction: 0.5, dynamicScreenSpaceErrorDensity: 0.5, dynamicScreenSpaceErrorFactor: 1, dynamicScreenSpaceError: false, }); var heightOffset = 0; if (url.indexOf("20220220") >= 0) heightOffset = -32; else if (url.indexOf("2022022101") >= 0) heightOffset = -50.4; tileset.readyPromise .then((palaceTileset) => { viewer.scene.primitives.add(palaceTileset); addedTilesets.value[item.id].push(palaceTileset); const boundingSphere = palaceTileset.boundingSphere; const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0); const offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset); const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3()); palaceTileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, heightOffset + 10000 ), duration: 3, }); }) .catch((error) => { console.error("Error loading tileset:", error); }); }); } }); } // 影像图层切换处理 var currentImageryLayer: Cesium.ImageryLayer | null = null; var src; function handleLayerChange(val: any) { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } if (!val) return; if (val === "baseImagery") { addImage(val); } if (val === "zhuzhou_beidou:GF07" || val === "zhuzhou_beidou:lkyx") { src = "EPSG:4326"; } else if (val !== "baseImagery") { src = "EPSG:4326x2"; } var imageryProvider = new Cesium.WebMapTileServiceImageryProvider({ url: "http://124.232.190.14:3013/geoserver/gwc/service/wmts", layer: val, format: "image/png", style: "", tileMatrixSetID: src, maximumLevel: 18, tilingScheme: new Cesium.GeographicTilingScheme({ numberOfLevelZeroTilesX: 2, numberOfLevelZeroTilesY: 1, }), tileMatrixLabels: [...Array(18).keys()].map((level) => (src + ":" + level).toString() ), }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider); currentImageryLayer.id = val; } // 添加基础影像 async function addImage(val: any) { var rightImageProvider = new Cesium.UrlTemplateImageryProvider({ name: "影像图", type: "xyz", layer: val, url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(rightImageProvider); currentImageryLayer.id = val; rightImageProvider.splitDirection = Cesium.SplitDirection.right; } // 清除影像图层 function clearLayer() { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } selectedLayer.value = ""; } // 组件挂载 onMounted(async () => { viewer = $prototype.$map; await addImage("baseImagery"); const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); const scene = $prototype.$map.scene; const ellipsoid = scene.globe.ellipsoid; handler.setInputAction(function (click) { const pick = $prototype.$map.scene.pick(click.position); const cartesians = $prototype.$map.camera.pickEllipsoid(click.position, ellipsoid); var data = null; if (cartesians) { const cartographic = ellipsoid.cartesianToCartographic(cartesians); const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6); const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6); data = { longitude: longitude, latitude: latitude }; console.log(longitude + "," + latitude); } if (pick && pick.primitive._imageId != undefined && pick.primitive._imageId.indexOf("mark-spjk") >= 0) { var obj = pick.id._properties; videoPlayList.value.push({ name: obj.name, url: obj.url, id: obj.id }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }); // 组件卸载 onUnmounted(() => { Object.values(addedTilesets.value).forEach((tilesets) => { tilesets.forEach((tileset) => { viewer.scene.primitives.remove(tileset); }); }); addedTilesets.value = {}; }); </script> <style lang="scss" scoped> .box { position: absolute; top: 15%; right: 80px; overflow: hidden; } .top-select { display: flex; align-items: center; justify-content: center; gap: 0px; } .select-1, .select-2, .select-3 { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border-radius: 2px; border: 1px solid #00f0f87f; } .select-1 { width: 110px; border-radius: 5px 0 0 5px; } .select-2 { flex: 1; width: 90px; } .select-3 { flex: 1; width: 180px; } /* 坐标系转换按钮样式 */ .coordinate-btn { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border: 1px solid #00f0f87f; color: #b4fdff; border-radius: 0 5px 5px 0; padding: 0 15px; display: flex; align-items: center; gap: 5px; &:hover { background: linear-gradient(180deg, #00f0f8 10%, #173c6a 100%); color: #fff; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); } } /* 自定义Element组件样式 */ :deep(.el-select__wrapper) { background: transparent !important; box-shadow: none !important; } :deep(.el-select__caret) { color: #3cffff; } :deep(.el-select__placeholder), :deep(.el-select__selected-item), :deep(.el-select-dropdown__item) { color: #b4fdff !important; } :deep(.el-tag.el-tag--info) { --el-tag-bg-color: #3cffff96 !important; } /* 确保下拉菜单正常显示 */ :deep(.el-select-dropdown) { display: block !important; background: rgba(1, 28, 82, 0.8) !important; border: 1px solid #00f0f87f !important; z-index: 9999 !important; } :deep(.el-select-dropdown__item) { color: #b4fdff !important; &:hover { background: rgba(0, 240, 248, 0.2) !important; } &.selected { background: rgba(0, 240, 248, 0.3) !important; } } </style> <style lang="scss"> /* 全局样式保持不变 */ .el-select-dropdown__item { color: #b4fdff !important; } .el-select__popper.el-popper { border: 1px solid #3f3f41 !important; background: rgba(1, 28, 82, 0.8) !important; } .el-select-dropdown { border: none !important; background: rgba(1, 28, 82, 0.8) !important; &::-webkit-scrollbar { width: 6px; height: 6px; } &::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 3px; } &::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.3); border-radius: 3px; &:hover { background: rgba(255, 255, 255, 0.4); } } } .el-select-dropdown__item.is-hovering { border: none !important; background: rgba(1, 28, 82, 0.8) !important; } .is-focus .el-select__wrapper { box-shadow: none !important; } /* ================= 坐标系转换弹窗样式优化 ================= */ .coordinate-dialog { .el-dialog__headerbtn .el-dialog__close { color: #b4fdff !important; &:hover { color: #fff !important; } } /* 内容区域样式 */ .el-dialog__body { padding: 20px; background: transparent; } /* 表单样式 */ .coord-form { .el-form-item { margin-bottom: 20px; } .el-form-item__label { color: #b4fdff; font-weight: bold; } /* 输入框样式 */ .el-input { .el-input__wrapper { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(0, 240, 248, 0.5); box-shadow: 0 0 5px rgba(0, 240, 248, 0.2) inset; color: #b4fdff; border-radius: 4px; transition: all 0.3s; &:hover { border-color: #00f0f8; box-shadow: 0 0 8px rgba(0, 240, 248, 0.4) inset; } &.is-focus { border-color: #00f0f8; box-shadow: 0 0 12px rgba(0, 240, 248, 0.6) inset; } } .el-input__inner { color: #b4fdff; &::placeholder { color: rgba(180, 253, 255, 0.6); } } } /* 结果输入框特殊样式 */ .el-form-item:last-child .el-input__wrapper { background: rgba(0, 240, 248, 0.1) !important; border: 1px solid rgba(0, 240, 248, 0.8) !important; } } /* 底部按钮区域 */ .el-dialog__footer { padding: 15px 20px; background: linear-gradient(90deg, rgba(23, 60, 106, 0.5), rgba(0, 240, 248, 0.2)); border-top: 1px solid rgba(0, 240, 248, 0.3); border-radius: 0 0 8px 8px; } /* 按钮样式 */ .cancel-btn { background: transparent; border: 1px solid rgba(0, 240, 248, 0.5); color: #b4fdff; &:hover { background: rgba(0, 240, 248, 0.2); border-color: #00f0f8; color: #fff; } } .convert-btn { background: linear-gradient(90deg, rgba(0, 240, 248, 0.7), rgba(23, 60, 106, 0.9)); border: none; color: #fff; font-weight: bold; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); &:hover { background: linear-gradient(90deg, rgba(0, 240, 248, 0.9), rgba(23, 60, 106, 1)); box-shadow: 0 0 15px rgba(0, 240, 248, 0.7); transform: translateY(-1px); } &:active { transform: translateY(1px); } } } </style>如上所示代码,其中我想知道卫星,矢量地图这些是使用了element的哪些组件布局,
07-13
<el-dialog :title="detailTitle" v-model="openDetail" style="width: 1400px; height: 800px" append-to-body > <el-form ref="powerRef" :model="main" :rules="rules" label-width="80px"> <el-row> <el-col :span="8"> <el-form-item label="年月" prop="years" label-width="140"> <el-date-picker clearable v-model="main.years" type="month" format="YYYY/MM" value-format="YYYY/MM" placeholder="Please select" :readonly="main.reviewStatus != '4'" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="绿电溢价" prop="premium" label-width="140"> <el-input v-model="main.premium" placeholder="Please input" :readonly="main.reviewStatus != '4'" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="厂别" prop="fact" label-width="140"> <el-input v-model="main.fact" placeholder="Please input" readonly /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="启动人" prop="nickName" label-width="140"> <el-input v-model="main.nickName" placeholder="Please input" readonly /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="审核状态" prop="reviewStatus" label-width="140" > <div> <dict-tag :options="rsc_review_status" :value="main.reviewStatus" /> </div> </el-form-item> </el-col> </el-row> </el-form> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="primary" plain icon="Plus" @click="handleAddDetail" v-hasPermi="['rsc:power:add']" >新增</el-button > </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDeleteDetail" v-hasPermi="['rsc:power:remove']" >删除</el-button > </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="Upload" @click="handleImport" v-hasPermi="['rsc:power:import']" >导入</el-button > </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="Upload" @click="handleImportAnnex" v-hasPermi="['rsc:power:import']" >附件</el-button > </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="View" @click="handleView" v-hasPermi="['rsc:power:import']" >预览附件</el-button > </el-col> <el-col :span="1.5"> <el-button type="warning" plain icon="View" @click="handleDeleteFile" v-hasPermi="['rsc:power:import']" >删除附件</el-button > </el-col> </el-row> <div style="max-height: 530px; overflow-y: auto"> <el-table v-loading="loading" :data="powerDataList" @selection-change="handleDetailSelectionChange" :summary-method="getSummeries" show-summary border > <el-table-column type="selection" width="55" align="center" /> <el-table-column label="區域" align="center" prop="locationName" width="120" > </el-table-column> <el-table-column label="动力用量(度)" align="center" prop="powerUsage" width="120" > </el-table-column> <el-table-column label="照明用量(度)" align="center" prop="lightingUsage" width="120" > </el-table-column> <el-table-column label="线路损耗(度)" align="center" prop="lineLoss" width="120" > </el-table-column> <el-table-column label="市電(度)" align="center" prop="electricity" width="100" > </el-table-column> <el-table-column label="綠電(度)" align="center" prop="greenElectricity" width="100" > </el-table-column> <el-table-column label="電網用电量合計(度)" align="center" prop="powerGridTotal" width="160" > </el-table-column> <el-table-column label="幣別" align="center" prop="currency"> <template #default="scope"> <div> <dict-tag :options="rsc_currency_type" :value="scope.row.currency" /> </div> </template> </el-table-column> <el-table-column label="单价(元/度)" align="center" prop="unitPrice" width="120" > </el-table-column> <el-table-column label="電網用电金額(元)" align="center" prop="electricityBills" width="150" > </el-table-column> <el-table-column label="光伏用電量(度)" align="center" prop="photovoltaicUsage" width="140" > </el-table-column> <el-table-column label="光伏用電單價(元/度)" align="center" prop="photovoltaicUnitPrice" width="160" > </el-table-column> <el-table-column label="光伏用電金額(元)" align="center" prop="photovoltaicBills" width="150" > </el-table-column> <el-table-column label="用電量合計" align="center" prop="electricityTotal" width="100" > </el-table-column> <el-table-column label="用電金額合計" align="center" prop="totalBills" width="120" > </el-table-column> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="140" fixed="left" > <template #default="scope"> <el-tooltip content="修改" placement="top"> <el-button link type="primary" icon="Edit" @click="handleUpdateDetail(scope.row)" v-hasPermi="['rsc:power:edit']" ></el-button> </el-tooltip> <!-- <el-tooltip content="删除" placement="top"> <el-button link type="primary" icon="Delete" @click="handleDeleteDetail(scope.row)" v-hasPermi="['rsc:power:remove']" ></el-button> </el-tooltip> --> </template> </el-table-column> </el-table> </div> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="savePower" v-if="main.reviewStatus != '1'" >保存</el-button > <el-button type="primary" @click="startProcess" v-if="main.reviewStatus == '4'" >提交</el-button > <el-button type="primary" @click="cacelPower" v-if=" main.reviewStatus != 1 && main.reviewStatus != 4 && main.reviewStatus != null " >取消申请</el-button > <el-button @click="cancelDetail">取 消</el-button> </div> </template> </el-dialog> 分析以上代码,帮我实现table表头与合计行的固定,不随表格列滚动
07-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

营赢盈英

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值