活动介绍
file-type

PostCSS内联Base64插件:将资源URL转base64代码示例

下载需积分: 10 | 278KB | 更新于2025-08-13 | 12 浏览量 | 0 下载量 举报 收藏
download 立即下载
PostCSS是一个非常流行的CSS处理工具,它通过插件系统对CSS进行转换。在Web开发中,PostCSS有着广泛的应用,比如用于添加未来的CSS特性、优化CSS代码、管理CSS的依赖等等。今天我们要讨论的是一个名为"postcss-inline-base64"的PostCSS插件,它的作用是将CSS文件中url()函数里面的资源地址转换为Base64编码,从而可以将外部资源内嵌到CSS文件中。 ### 插件功能详解 **内联Base64**: 通常CSS中会通过url()函数引入外部资源,如图片、字体等。使用"postcss-inline-base64"插件后,你可以选择将这些外部资源转换成Base64编码后直接写入CSS文件。这样做的好处是减少了HTTP请求的数量,对于小型资源来说,可以加快页面加载速度,尤其在HTTP/2普及之前,减少请求显得尤为重要。 **插件用法**: 插件的使用非常简单,通过Node.js的require语法引入,并在PostCSS的处理流程中加入这个插件。你也可以传递一些选项给插件,比如指定baseDir,这是用于加载文件的路径,默认是当前工作目录(process.cwd())。 **使用语法**: 插件提供了不同的语法来触发Base64转换。例如,你可以使用以下格式的语法来标记需要转换的文件:`b64---{file}---`。文件路径可以是相对路径或者绝对路径。 **例子说明**: 如果你有一个CSS文件中这样写: ```css :root { --image: 'b64---./example.gif---'; } @font-face { font-family: 'example'; src: 'b64---./example.woff---'; } ``` 使用"postcss-inline-base64"插件处理后,这个CSS文件就会把`--image`变量和`@font-face`中的src直接替换为对应的Base64编码字符串,原本指向的文件路径则不再需要。 ### 插件选项 **baseDir**: 这是一个选项,用于设定在寻找文件时的根目录。如果设置为绝对路径,那么所有相对路径都会从这个目录开始解析。如果保留默认值`process.cwd()`,则从当前工作目录开始解析。 ### 标签说明 - **plugin**: 表明这是一个PostCSS插件。 - **url**: 插件主要处理的是CSS中url()函数内的资源引用。 - **svg, image**: 插件可以处理图片资源和SVG文件。 - **base64**: 插件的核心功能是将资源转换为Base64编码。 - **postcss**: 插件是专门为了PostCSS开发的。 - **inline**: 插件的工作是将外部资源内嵌到CSS中。 - **src**: 插件处理的是CSS文件中的资源路径部分。 - **font-face**: 插件可以处理CSS中的@font-face规则,用以转换字体文件。 ### 压缩包子文件的文件名称列表 **postcss-inline-base64-master**: 从文件名可以看出,这是"postcss-inline-base64"插件的源代码仓库中的master分支。文件名通常遵循这样的命名方式,"postcss-inline-base64"表示插件名称,"master"表示这是主分支,通常包含插件最稳定、最新的代码。 通过使用"postcss-inline-base64"插件,开发者可以有效地减少Web应用中的资源请求数量,从而优化性能,特别是在资源较小且需要快速加载的场景下非常适合。同时,该插件也能够简化Web应用的部署过程,因为你不再需要考虑资源文件的相对路径或者相对服务器的绝对路径,所有必要的资源都已经内嵌到了CSS文件中。不过,需要注意的是,内联过于大的资源可能会导致CSS文件体积变得庞大,从而抵消了性能优化的初衷。因此,在使用该插件时,开发者应该根据实际情况谨慎选择内联的资源大小。

相关推荐

filetype

{ "code": 1, "msg": "success", "data": { "total": 10, "rows": [ { "id": 13, "name": "江苏花果山", "room": "水帘洞", "beginDate": "2024-08-08", "endDate": "2050-08-08", "masterId": 47, "subject": 1, "createTime": "2024-08-23T09:50:31", "updateTime": "2024-08-25T19:53:34", "masterName": "高圆圆6", "status": "在读中" }, { "id": 12, "name": "JavaEE就业422", "room": "214", "beginDate": "2024-08-21", "endDate": "2025-01-10", "masterId": 47, "subject": 1, "createTime": "2024-08-21T15:07:20", "updateTime": "2024-08-21T15:07:20", "masterName": "高圆圆6", "status": "已结课" }, { "id": 11, "name": "JavaEE就业169期", "room": "213", "beginDate": "2024-08-01", "endDate": "2025-01-10", "masterId": 27, "subject": 1, "createTime": "2024-08-20T09:51:45", "updateTime": "2024-08-20T09:52:23", "masterName": "李俊", "status": "已结课" }, { "id": 9, "name": "JavaEE就业168期", "room": "215", "beginDate": "2024-08-20", "endDate": "2025-01-01", "masterId": 47, "subject": 1, "createTime": "2024-08-17T22:54:09", "updateTime": "2024-08-19T14:36:28", "masterName": "高圆圆6", "status": "已结课" }, { "id": 8, "name": "JavaEE就业167期", "room": "325", "beginDate": "2023-11-20", "endDate": "2024-05-10", "masterId": 36, "subject": 1, "createTime": "2023-11-15T11:35:46", "updateTime": "2023-12-13T14:31:24", "masterName": null, "status": "已结课" }, { "id": 7, "name": "大数据就业58期", "room": "209", "beginDate": "2023-08-01", "endDate": "2024-02-15", "masterId": 7, "subject": 3, "createTime": "2023-06-01T17:51:21", "updateTime": "2023-06-01T17:51:21", "masterName": "柴进", "status": "已结课" }, { "id": 6, "name": "JavaEE就业166期", "room": "105", "beginDate": "2023-07-20", "endDate": "2024-02-20", "masterId": 20, "subject": 1, "createTime": "2023-06-01T17:46:10", "updateTime": "2023-06-01T17:46:10", "masterName": "阮小二", "status": "已结课" }, { "id": 5, "name": "JavaEE就业165期", "room": "108", "beginDate": "2023-06-15", "endDate": "2023-12-25", "masterId": 6, "subject": 1, "createTime": "2023-06-01T17:45:40", "updateTime": "2023-06-01T17:45:40", "masterName": "扈三娘", "status": "已结课" }, { "id": 4, "name": "前端就业90期", "room": "210", "beginDate": "2023-07-10", "endDate": "2024-01-20", "masterId": 3, "subject": 2, "createTime": "2023-06-01T17:45:12", "updateTime": "2023-06-01T17:45:12", "masterName": "卢俊义", "status": "已结课" }, { "id": 1, "name": "JavaEE就业163期", "room": "212", "beginDate": "2023-04-30", "endDate": "2023-06-29", "masterId": 10, "subject": 1, "createTime": "2023-06-01T17:08:23", "updateTime": "2023-06-01T17:39:58", "masterName": "林冲", "status": "已结课" } ] } } // src/types/clazz.ts export interface Clazz { id?: number name: string room: string beginDate: string endDate: string masterId?: number | null masterName?: string subject: number createTime?: string updateTime?: string } export interface PageParams { page: number pageSize: number name?: string begin?: string end?: string status?: string } export interface PageResult<T> { rows: T[] total: number } export interface PageModel { total: number rows: any[] } // 分页结果响应接口 export interface PageResultModel { total: number rows: | Clazz[] | { id?: number | undefined name: string room: string beginDate: string endDate: string masterId?: number | null | undefined masterName?: string | undefined subject: number createTime?: string | undefined updateTime?: string | undefined }[] code: number msg: string data: PageModel } export interface ResultModel { code: number msg: string data: any } 根据我后端返回的数据类型把前端接口修改下

filetype

<template>
<Search @location-selected="handleLocationSelected" /> <LocationBar v-if="loaded" :update-interval="100" :use-dms-format="useDmsFormat" /> </template> <style> /* @import "/temp/css/divGraphic.css"; */ </style> <script setup lang="ts"> import { computed, onUnmounted, onMounted, reactive } from "vue"; import LocationBar from "./location-bar.vue"; import Search from "./search.vue"; import initMap from "./init"; import { ref } from "vue"; import { throttle } from 'lodash'; import { loadRipplePoints, createMultipleRippleCircles } from './circle.js'; import { $prototype } from "../../main.ts"; const miniMapContainer = ref<HTMLElement>(); let viewIndicator: Rectangle; // 视图指示器样式 const currentPosition = reactive({ longitude: 113.361538, latitude: 27.339318, }); // 株洲市范围常量 const ZHUZHOU_EXTENT = { west: 112.5, // 株洲市西边界 east: 114.5, // 株洲市东边界 south: 26.0, // 株洲市南边界 north: 28.0 // 株洲市北边界 }; const rippleEntities = ref<any[]>([]); // 存储波纹圆实体 const heightThreshold = 80000; // 高度阈值(米),高于此值隐藏波纹圆 // 修复1:重新定义 indicatorStyle 为 ref const indicatorStyle = ref({ left: '50%', top: '50%', display: "block" }); const updateRippleVisibility = throttle(() => { if (!$prototype.$map || rippleEntities.value.length === 0) return; // 修复1:将 shouldShow 提取到块级作用域外部 let shouldShow = false; // 获取相机高度 const cartographic = $prototype.$map.camera.positionCartographic; // 修复2:添加空值检查 if (cartographic) { const cameraHeight = cartographic.height; shouldShow = cameraHeight > heightThreshold; } // 修复3:确保 shouldShow 已定义 rippleEntities.value.forEach(entity => { entity.show = shouldShow; }); }, 200); // 更新指示器位置 const updateIndicatorPosition = () => { if (!$prototype.$map) return; const camera = $prototype.$map.camera; const rect = camera.computeViewRectangle(); if (!rect) return; // 计算在株洲市范围内的相对位置 const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); // 确保位置在株洲市范围内 const constrainedLon = Math.max(ZHUZHOU_EXTENT.west, Math.min(ZHUZHOU_EXTENT.east, lon)); const constrainedLat = Math.max(ZHUZHOU_EXTENT.south, Math.min(ZHUZHOU_EXTENT.north, lat)); const lonPercent = ((constrainedLon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((constrainedLat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; // 更新CSS指示器 indicatorStyle.value = { left: `${lonPercent}%`, top: `${latPercent}%`, display: "block" }; }; // 更新鹰眼地图 - 只更新指示器位置 const updateOverview = () => { if (!$prototype.$map || !overviewViewer.value) return; // 获取主地图的当前视图中心 const rectangle = $prototype.$map.camera.computeViewRectangle(); if (!rectangle) return; // 更新指示器位置 updateIndicatorPosition(); }; const overviewViewer = ref(null); // 初始化鹰眼地图 - 使用株洲市影像 const initMiniMap = () => { Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDhlNDdmYy03NzFhLTQ1ZTQtOWQ3NS1lZDAzNDc3YjE4NDYiLCJpZCI6MzAxNzQyLCJpYXQiOjE3NDcwNTMyMDN9.eaez8rQxVbPv2LKEU0sMDclPWyHKhh1tR27Vg-_rQSM"; if (!miniMapContainer.value) return; // 创建株洲市专用影像提供器 const zhuzhouProvider = new Cesium.UrlTemplateImageryProvider({ url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, tilingScheme: new Cesium.WebMercatorTilingScheme(), }); // 鹰眼地图初始化 - 使用株洲市影像 overviewViewer.value = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, imageryProvider: zhuzhouProvider, // 修复2:移除地形服务 terrainProvider: undefined, // 修复3:使用正确的投影 mapProjection: new Cesium.WebMercatorProjection(), // 修复4:禁用天空盒和大气层 skyBox: false, skyAtmosphere: false }); // 设置固定视野为株洲市范围 overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ) }); // 隐藏控件 const toolbar = overviewViewer.value.container.getElementsByClassName("cesium-viewer-toolbar")[0]; if (toolbar) toolbar.style.display = "none"; // 修复5:隐藏版权信息 overviewViewer.value.cesiumWidget.creditContainer.style.display = "none"; // 初始化视图指示器 initRectangle(); }; // 初始化视图指示器 function initRectangle() { // 创建视图指示器(株洲市范围框) viewIndicator = overviewViewer.value.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ), material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED, outlineWidth: 2, }, }); } const loaded = ref(false); const useDmsFormat = ref(false); function addDemoGraphics() { const chinaBoundary = $prototype.$map.dataSources.add( Cesium.GeoJsonDataSource.load("/shp_zz.geojson", { stroke: Cesium.Color.WHITE, fill: false, clampToGround: true, describe: null, }) ); chinaBoundary.then((dataSource) => { const entities = dataSource.entities.values; for (let entity of entities) { if (entity.polyline) { entity.polyline.fill = false; } } }); } function flyToDes() { const center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0); $prototype.$map.camera.flyTo({ destination: new Cesium.Cartesian3( -2432812.6687511606, 5559483.804371395, 2832009.419525571 ), orientation: { heading: 6.283185307179421, pitch: -1.0472145569408116, roll: 6.2831853071795205, }, complete: function () {}, }); } // 监听主地图相机变化 const setupCameraListener = () => { $prototype.$map.camera.changed.addEventListener(updateOverview); }; // 鹰眼地图点击处理 const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer.value) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 计算在固定范围内的相对位置 const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; // 转换为株洲市范围内的经纬度 const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); // 主地图飞向点击位置 $prototype.$map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000000), }); }; function addImage() { var rightImageProvider = new Cesium.UrlTemplateImageryProvider({ name: "影像图", type: "xyz", layer: "vec_d", url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); $prototype.$map.imageryLayers.addImageryProvider(rightImageProvider); rightImageProvider.splitDirection = Cesium.SplitDirection.right; } onMounted(() => { initMap(); addImage(); loaded.value = true; addDemoGraphics(); flyToDes(); // 修复6:确保正确的初始化顺序 setTimeout(() => { initMiniMap(); setupCameraListener(); // 初始更新 updateOverview(); }, 1000); (async () => { try { const ripplePoints = await loadRipplePoints(); rippleEntities.value = createMultipleRippleCircles( $prototype.$map, ripplePoints ); $prototype.$map.camera.changed.addEventListener(updateRippleVisibility); updateRippleVisibility(); } catch (error) { console.error('加载波纹圆失败:', error); } })(); }); let currentMarker: any = null; const createMarker = (location: { lng: number; lat: number; name: string }) => { if (currentMarker) { $prototype.$map.entities.remove(currentMarker); } currentMarker = $prototype.$map.entities.add({ position: Cesium.Cartesian3.fromDegrees( location.lng, location.lat, 50 ), point: { pixelSize: 200, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, }, label: { text: location.name, font: "40px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 1, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -20), heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), }, description: `

${location.name}

经度:${location.lng.toFixed(6)}

纬度:${location.lat.toFixed(6)}

`, }); return currentMarker; }; const handleLocationSelected = (location: { lng: number; lat: number; name: string; }) => { if (!$prototype.$map) return; const destination = Cesium.Cartesian3.fromDegrees( location.lng, location.lat, 200 ); $prototype.$map.camera.flyTo({ destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-45), roll: 0, }, duration: 2, complete: () => { createMarker(location); }, }); }; onUnmounted(() => { if ($prototype.$map) { $prototype.$map.destroy(); $prototype.$map = null; } if ($prototype.$map) { $prototype.$map.camera.changed.removeEventListener(updateRippleVisibility); } console.log("组件销毁"); }); const emit = defineEmits(["onload", "onclick"]); const initMars3d = async (option: any) => { emit("onclick", true); emit("onload", $prototype.$map); }; </script> <style lang="less"> /**cesium 工具按钮栏*/ .cesium-viewer-toolbar { top: auto !important; bottom: 35px !important; left: 12px !important; right: auto !important; } .cesium-toolbar-button img { height: 100%; } .cesium-viewer-toolbar > .cesium-toolbar-button, .cesium-navigationHelpButton-wrapper, .cesium-viewer-geocoderContainer { margin-bottom: 5px; float: left; clear: both; text-align: center; } .cesium-button { background-color: rgba(23, 49, 71, 0.8); color: #e6e6e6; fill: #e6e6e6; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); line-height: 32px; } .cesium-button:hover { background: #3ea6ff; } /**cesium 底图切换面板*/ .cesium-baseLayerPicker-dropDown { bottom: 0; left: 40px; max-height: 700px; margin-bottom: 5px; background-color: rgba(23, 49, 71, 0.8); } /**cesium 帮助面板*/ .cesium-navigation-help { top: auto; bottom: 0; left: 40px; transform-origin: left bottom; background: none; background-color: rgba(23, 49, 71, 0.8); .cesium-navigation-help-instructions { background: none; } .cesium-navigation-button { background: none; } .cesium-navigation-button-selected, .cesium-navigation-button-unselected:hover { background: rgba(0, 138, 255, 0.2); } } /**cesium 二维三维切换*/ .cesium-sceneModePicker-wrapper { width: auto; } .cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon { float: right; margin: 0 3px; } /**cesium POI查询输入框*/ .cesium-viewer-geocoderContainer .search-results { left: 0; right: 40px; width: auto; z-index: 9999; } .cesium-geocoder-searchButton { background-color: rgba(23, 49, 71, 0.8); } .cesium-viewer-geocoderContainer .cesium-geocoder-input { background-color: rgba(63, 72, 84, 0.7); } .cesium-viewer-geocoderContainer .cesium-geocoder-input:focus { background-color: rgba(63, 72, 84, 0.9); } .cesium-viewer-geocoderContainer .search-results { background-color: rgba(23, 49, 71, 0.8); } /**cesium info信息框*/ .cesium-infoBox { top: 50px; background-color: rgba(23, 49, 71, 0.8); } .cesium-infoBox-title { background-color: rgba(23, 49, 71, 0.8); } /**cesium 任务栏的FPS信息*/ .cesium-performanceDisplay-defaultContainer { top: auto; bottom: 35px; right: 50px; } .cesium-performanceDisplay-ms, .cesium-performanceDisplay-fps { color: #fff; } /**cesium tileset调试信息面板*/ .cesium-viewer-cesiumInspectorContainer { top: 10px; left: 10px; right: auto; } .cesium-cesiumInspector { background-color: rgba(23, 49, 71, 0.8); } /**覆盖mars3d内部控件的颜色等样式*/ .mars3d-compass .mars3d-compass-outer { fill: rgba(23, 49, 71, 0.8); } .mars3d-contextmenu-ul, .mars3d-sub-menu { background-color: rgba(23, 49, 71, 0.8); > li > a:hover, > li > a:focus, > li > .active { background-color: #3ea6ff; } > .active > a, > .active > a:hover, > .active > a:focus { background-color: #3ea6ff; } } /* Popup样式*/ .mars3d-popup-color { color: #ffffff; } .mars3d-popup-background { background: rgba(23, 49, 71, 0.8); } .mars3d-popup-content { margin: 15px; } .mars3d-template-content label { padding-right: 6px; } .mars3d-template-titile { border-bottom: 1px solid #3ea6ff; } .mars3d-template-titile a { font-size: 16px; } .mars3d-tooltip { background: rgba(23, 49, 71, 0.8); border: 1px solid rgba(23, 49, 71, 0.8); } .mars3d-popup-btn-custom { padding: 3px 10px; border: 1px solid #209ffd; background: #209ffd1c; } .mars-dialog .mars-dialog__content { height: 100%; width: 100%; overflow: auto; padding: 5px; } .image { border: solid 2px #fff; } .content { height: 90%; padding-top: 10px; overflow-x: auto; overflow-y: auto; } .content-text { padding: 0 10px; text-indent: 30px; font-size: 17px; } .details-video { width: 100%; height: 760px; background-color: #000; } :where(.css-lt97qq9).ant-space { display: inline-flex; } :where(.css-lt97qq9).ant-space-align-center { align-items: center; } :where(.css-lt97qq9).ant-image .ant-image-mask { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(0, 0, 0, 0.5); cursor: pointer; opacity: 0; transition: opacity 0.3s; } :where(.css-lt97qq9).ant-image .ant-image-mask .ant-image-mask-info { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 4px; } :where(.css-1t97qq9)[class^="ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class^="ant-image"] [class*=" ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class*=" ant-image"] { box-sizing: border-box; } :where(.css-lt97qq9).ant-image .ant-image-img { width: 100%; height: auto; vertical-align: middle; } </style> <style scoped> .mini-map-container { position: relative; width: 100%; height: 100%; } .main-viewer { width: 100%; height: 100%; } .mini-map { position: absolute; right: 3vw; bottom: 6vh; width: 12vw; height: 17vh; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } .location-indicator { position: absolute; width: 14px; height: 14px; background: #ff3e3e; border: 2px solid white; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 15px rgba(255, 62, 62, 1); z-index: 100; } .view-rectangle { position: absolute; border: 2px solid #00f2fe; z-index: 99; pointer-events: none; box-shadow: 0 0 20px rgba(0, 242, 254, 0.7); } /* 相机聚焦样式 - 四个角折角 */ .corner { position: absolute; width: 25px; height: 25px; z-index: 100; pointer-events: none; } .corner::before, .corner::after { content: ""; position: absolute; background: #00f2fe; box-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .corner-top-left { top: -2px; left: -2px; } .corner-top-left::before { top: 0; left: 0; width: 15px; height: 3px; } .corner-top-left::after { top: 0; left: 0; width: 3px; height: 15px; } .corner-top-right { top: -2px; right: -2px; } .corner-top-right::before { top: 0; right: 0; width: 15px; height: 3px; } .corner-top-right::after { top: 0; right: 0; width: 3px; height: 15px; } .corner-bottom-left { bottom: -2px; left: -2px; } .corner-bottom-left::before { bottom: 0; left: 0; width: 15px; height: 3px; } .corner-bottom-left::after { bottom: 0; left: 0; width: 3px; height: 15px; } .corner-bottom-right { bottom: -2px; right: -2px; } .corner-bottom-right::before { bottom: 0; right: 0; width: 15px; height: 3px; } .corner-bottom-right::after { bottom: 0; right: 0; width: 3px; height: 15px; } .camera-icon { position: absolute; top: 10px; right: 10px; color: #00f2fe; font-size: 24px; z-index: 100; text-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .focus-effect { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 98; border: 2px solid rgba(0, 242, 254, 0.2); border-radius: 5px; box-shadow: inset 0 0 30px rgba(0, 242, 254, 0.1); } .pulse { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; border-radius: 50%; background: rgba(0, 242, 254, 0.7); box-shadow: 0 0 0 0 rgba(0, 242, 254, 0.7); animation: pulse 2s infinite; } ::v-deep.cesium-viewer-toolbar { display: none; } </style> 如上vue代码,还有个问题,就是鹰眼地图里面除了中间的株洲影像不变以外,其余地方加载的还是原本初始的地球影像即可,现在鹰眼地图里面只有这个株洲影像,你尝试修改一下代码,尽可能减少对vue其他无关代码的更改

filetype

<template>
<el-card class="index-card"> <el-form :model="formData" label-position="top" ref="indexForm" class="mobile-form" > <el-form-item label="问卷标题:" prop="dcWjTitle"> <el-input v-model="formData.dcWjTitle" placeholder="请输入问卷标题" clearable :prefix-icon="Document" /> </el-form-item>
<el-form-item label="被测评人:" prop="dcId" class="inline-form-item"> <el-select v-model="formData.dcId" multiple filterable remote reserve-keyword clearable placeholder="请选择被测评人" :remote-method="searchBdr" :loading="bdrLoading" @focus="handleBdrFocus" > <el-option v-for="item in bdrOptions" :key="item.dcId" :label="item.dcName" :value="item.dcId" /> </el-select> </el-form-item> <el-form-item label="人员部门:" prop="dcDept" class="inline-form-item"> <el-input v-model="formData.dcDept" placeholder="请输入人员部门" clearable :prefix-icon="OfficeBuilding" /> </el-form-item>
<el-form-item label="提交状态:" prop="state"> <el-select v-model="formData.state" placeholder="请选择提交状态" clearable class="mobile-select" > <el-option label="已提交" :value="1" /> <el-option label="未提交" :value="0" /> </el-select> </el-form-item> <el-form-item class="button-group"> <el-button type="primary" @click="handleSearch" class="action-button" :icon="Search" > 搜索 </el-button> <el-button @click="handleReset" class="action-button" :icon="Refresh" > 重置 </el-button> </el-form-item> </el-form> </el-card> <el-card class="data-card"> <template #header>
<el-button type="primary" size="small" :icon="Refresh" @click="fetchData" > 刷新数据 </el-button>
</template>
{{ item.dcWjTitle }}
被测评人: {{ item.dcName }}
部门: {{ item.dcDept }}
创建时间: {{ item.createTime }}
提交时间: {{ item.updateTime || '-' }}
<el-tag :type="item.state === '1' ? 'success' : 'info'"> {{ item.state === '1' ? '已提交' : '未提交' }} </el-tag>
总分: {{ item.score || '0' }}
<el-button size="small" type="primary" @click="handleView(item)" class="action-btn" > 编辑/查看 </el-button>
<el-empty v-if="tableData.length === 0" description="暂无数据" />
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size" :page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" @current-change="handlePageChange" />
</el-card>
</template> <script setup> // 确保正确导入所有 Vue 函数 import { ref, reactive, onMounted, onUnmounted } from 'vue'; import axios from 'axios'; import { Document, User, OfficeBuilding, Search, Refresh } from '@element-plus/icons-vue'; import { ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; const router = useRouter(); // 环境变量管理API地址 const API_BASE = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api'; const API_URL = `${API_BASE}/wjdc/wj/listTx`; const BDR_API_URL = `${API_BASE}/wjdc/wj/getBdrList`; // 被测评人相关数据 const bdrOptions = ref([]); // 被测评人选项列表 const bdrLoading = ref(false); // 加载状态 const bdrCache = ref([]); // 缓存所有被测评人数据 // 表单数据 const formData = reactive({ dcWjTitle: '', dcId: [], dcDept: '', state: null }); // 表格数据 const tableData = ref([]); const loading = ref(false); // 分页配置 const pagination = reactive({ current: 1, size: 10, total: 0 }); // 表单引用 const indexForm = ref(null); // 请求取消令牌 let cancelTokenSource = axios.CancelToken.source(); // 处理被测评人输入框获取焦点 const handleBdrFocus = () => { if (bdrCache.value.length === 0) { fetchBdrList(''); } }; // 获取被测评人列表 const fetchBdrList = async (keyword = '') => { const token = getAuthToken(); if (!token) return; bdrLoading.value = true; try { const response = await axios.get(BDR_API_URL, { headers: { 'Authorization': `Bearer ${token}` } }); // 判断返回的数据是否是数组 if (Array.isArray(response.data)) { // 缓存所有数据 bdrCache.value = response.data; // 根据关键字过滤 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName && item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); // 最多显示10条 } else { // 未输入关键字时显示前10条 bdrOptions.value = bdrCache.value.slice(0, 10); } } else { // 如果不是数组,则按照原有格式处理(假设有code和data) if (response.data && response.data.code === 200) { bdrCache.value = response.data.data || []; // 同样的过滤逻辑 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } else { const msg = response.data?.msg || '返回数据格式不正确'; ElMessage.error('获取被测评人列表失败: ' + msg); } } } catch (error) { console.error('获取被测评人列表失败:', error); ElMessage.error('获取被测评人列表失败'); } finally { bdrLoading.value = false; } }; // 搜索被测评人(防抖) let searchBdrTimer = null; const searchBdr = (query) => { if (searchBdrTimer) clearTimeout(searchBdrTimer); searchBdrTimer = setTimeout(() => { if (bdrCache.value.length === 0) { fetchBdrList(query); } else { // 本地过滤 if (query) { const searchTerm = query.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } }, 300); }; // 获取认证令牌 const getAuthToken = () => { const token = localStorage.getItem('token'); if (!token) { ElMessage.warning('请先登录'); router.push('/login'); return null; } return token; }; // 搜索按钮处理函数 - 防抖 let searchTimer = null; const handleSearch = () => { // 检查被测评人选择数量 if (formData.dcId.length > 1) { ElMessage.warning({ message: '当前只能搜索一个被测人员', duration: 3000 }); return; } if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { pagination.current = 1; fetchData(); }, 300); }; // 重置按钮处理函数 const handleReset = () => { if (indexForm.value) { indexForm.value.resetFields(); // 确保重置后 dcId 是空数组 formData.dcId = []; } handleSearch(); }; // 编辑/查看 const handleView = (row) => { router.push({ name: 'Operation', // 路由名称 params: { id: row.dcWjId // 传递问卷ID作为参数 } }); }; // 分页大小改变 const handleSizeChange = (size) => { pagination.size = size; fetchData(); }; // 页码改变 const handlePageChange = (page) => { pagination.current = page; fetchData(); }; // 获取数据 const fetchData = async () => { // 获取认证令牌 const token = getAuthToken(); if (!token) return; // 取消之前的请求 if (cancelTokenSource) { cancelTokenSource.cancel('请求被取消'); } cancelTokenSource = axios.CancelToken.source(); loading.value = true; try { // 构造请求参数 const params = { pageNum: pagination.current, pageSize: pagination.size, ...formData, // 安全处理:确保 dcId 是数组再 join dcId: Array.isArray(formData.dcId) ? formData.dcId.join(',') : '' // 将数组转换为逗号分隔的字符串 }; // 调用API - 添加认证头 const response = await axios.get(API_URL, { params, cancelToken: cancelTokenSource.token, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); // 处理响应数据 const { data } = response; if (data && data.code === 200) { // 修改点:直接使用 data.rows 和 data.total tableData.value = data.rows || []; pagination.total = data.total || 0; // 空数据提示 if (tableData.value.length === 0) { ElMessage.info('没有找到匹配的数据'); } } else { const errorMsg = data?.msg || '未知错误'; console.error('API返回错误:', errorMsg); ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } catch (error) { // 处理认证失败 if (error.response && error.response.status === 401) { ElMessage.error('认证过期,请重新登录'); localStorage.removeItem('token'); router.push('/login'); return; } // 忽略取消请求的错误 if (!axios.isCancel(error)) { console.error('获取数据失败:', error); const errorMsg = error.response?.data?.message || '网络请求失败'; ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } finally { loading.value = false; } }; // 页面加载时获取初始数据 onMounted(() => { fetchData(); }); // 组件卸载时取消所有请求 onUnmounted(() => { if (cancelTokenSource) { cancelTokenSource.cancel('组件卸载,取消请求'); } }); </script> <style scoped> .form-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; } .inline-form-item { flex: 1; min-width: 250px; } .inline-form-item :deep(.el-form-item__label) { float: left; width: auto; padding-right: 12px; line-height: 32px; } .inline-form-item :deep(.el-form-item__content) { display: flex; flex: 1; } /* 移动端响应式 */ @media (max-width: 768px) { .form-row { flex-direction: column; gap: 16px; } .inline-form-item { min-width: 100%; } .inline-form-item :deep(.el-form-item__label) { float: none; width: 100%; padding-right: 0; padding-bottom: 8px; } } /* 卡片容器样式 */ .card-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); gap: 16px; } /* 单个卡片样式 */ .data-card-item { background: #fff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); padding: 16px; display: flex; flex-direction: column; transition: all 0.3s ease; border: 1px solid #ebeef5; } .data-card-item:hover { transform: translateY(-4px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); } /* 卡片头部(序号+标题) */ .card-header-section { padding-bottom: 12px; border-bottom: 1px solid #f0f2f5; margin-bottom: 12px; } .card-id { font-size: 14px; color: #909399; margin-bottom: 4px; } .card-title { font-size: 16px; font-weight: 600; color: #303133; line-height: 1.4; word-break: break-word; } /* 卡片主体(其他信息) */ .card-body-section { flex: 1; margin-bottom: 12px; } .card-row { display: flex; margin-bottom: 8px; font-size: 14px; } .card-label { color: #606266; min-width: 70px; text-align: right; } .card-value { color: #303133; flex: 1; word-break: break-word; } /* 卡片底部(状态+按钮) */ .card-footer-section { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid #f0f2f5; } .status-container { display: flex; align-items: center; gap: 8px; } .score { font-size: 14px; color: #e6a23c; font-weight: 500; } .action-btn { flex-shrink: 0; } /* 移动端响应式 */ @media (max-width: 768px) { .card-container { grid-template-columns: 1fr; } .card-row { flex-direction: column; margin-bottom: 12px; } .card-label { text-align: left; margin-bottom: 4px; font-weight: 500; } .card-footer-section { flex-direction: column; align-items: stretch; gap: 12px; } .status-container { justify-content: space-between; } } /* 添加选择器样式 */ :deep(.el-select) .el-input__inner { height: auto !important; min-height: 44px; padding: 5px 15px; } /* 标签样式 */ :deep(.el-tag) { margin: 2px 6px 2px 0; } /* 下拉菜单样式 */ :deep(.el-select-dropdown) { max-height: 300px; overflow-y: auto; } .index-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); } .card-header { font-size: 18px; font-weight: 600; color: #1a1a1a; } .mobile-form { :deep(.el-form-item__label) { font-weight: 500; margin-bottom: 6px; } :deep(.el-input__inner) { height: 44px; border-radius: 8px; } } .mobile-select { width: 100%; :deep(.el-input__inner) { height: 44px; } } /* 按钮区域样式 */ .button-group { display: flex; gap: 12px; margin-top: 16px; } .action-button { flex: 1; height: 46px; font-size: 16px; border-radius: 8px; } /* 移动端响应式调整 */ @media (max-width: 480px) { .button-group { flex-direction: column; gap: 10px; } .action-button { width: 100%; } } </style> 我想把这个代码修改用于uniapp的详情页

filetype

<template>
<el-card class="index-card"> <el-form :model="formData" label-position="top" ref="indexForm" class="mobile-form" > <el-form-item label="问卷标题:" prop="dcWjTitle"> <el-input v-model="formData.dcWjTitle" placeholder="请输入问卷标题" clearable :prefix-icon="Document" /> </el-form-item>
<el-form-item label="被测评人:" prop="dcId" class="inline-form-item"> <el-select v-model="formData.dcId" multiple filterable remote reserve-keyword clearable placeholder="请选择被测评人" :remote-method="searchBdr" :loading="bdrLoading" @focus="handleBdrFocus" > <el-option v-for="item in bdrOptions" :key="item.dcId" :label="item.dcName" :value="item.dcId" /> </el-select> </el-form-item> <el-form-item label="人员部门:" prop="dcDept" class="inline-form-item"> <el-input v-model="formData.dcDept" placeholder="请输入人员部门" clearable :prefix-icon="OfficeBuilding" /> </el-form-item>
<el-form-item label="提交状态:" prop="state"> <el-select v-model="formData.state" placeholder="请选择提交状态" clearable class="mobile-select" > <el-option label="已提交" :value="1" /> <el-option label="未提交" :value="0" /> </el-select> </el-form-item> <el-form-item class="button-group"> <el-button type="primary" @click="handleSearch" class="action-button" :icon="Search" > 搜索 </el-button> <el-button @click="handleReset" class="action-button" :icon="Refresh" > 重置 </el-button> </el-form-item> </el-form> </el-card> <el-card class="data-card"> <template #header>
<el-button type="primary" size="small" :icon="Refresh" @click="fetchData" > 刷新数据 </el-button>
</template>
{{ item.dcWjTitle }}
被测评人: {{ item.dcName }}
部门: {{ item.dcDept }}
创建时间: {{ item.createTime }}
提交时间: {{ item.updateTime || '-' }}
<el-tag :type="item.state === '1' ? 'success' : 'info'"> {{ item.state === '1' ? '已提交' : '未提交' }} </el-tag>
总分: {{ item.score || '0' }}
<el-button size="small" type="primary" @click="handleView(item)" class="action-btn" > 编辑/查看 </el-button>
<el-empty v-if="tableData.length === 0" description="暂无数据" />
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size" :page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" @current-change="handlePageChange" />
</el-card>
</template> <script setup> // 确保正确导入所有 Vue 函数 import { ref, reactive, onMounted, onUnmounted } from 'vue'; import axios from 'axios'; import { Document, User, OfficeBuilding, Search, Refresh } from '@element-plus/icons-vue'; import { ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; const router = useRouter(); // 环境变量管理API地址 const API_BASE = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api'; const API_URL = `${API_BASE}/wjdc/wj/listTx`; const BDR_API_URL = `${API_BASE}/wjdc/wj/getBdrList`; // 被测评人相关数据 const bdrOptions = ref([]); // 被测评人选项列表 const bdrLoading = ref(false); // 加载状态 const bdrCache = ref([]); // 缓存所有被测评人数据 // 表单数据 const formData = reactive({ dcWjTitle: '', dcId: [], dcDept: '', state: null }); // 表格数据 const tableData = ref([]); const loading = ref(false); // 分页配置 const pagination = reactive({ current: 1, size: 10, total: 0 }); // 表单引用 const indexForm = ref(null); // 请求取消令牌 let cancelTokenSource = axios.CancelToken.source(); // 处理被测评人输入框获取焦点 const handleBdrFocus = () => { if (bdrCache.value.length === 0) { fetchBdrList(''); } }; // 获取被测评人列表 const fetchBdrList = async (keyword = '') => { const token = getAuthToken(); if (!token) return; bdrLoading.value = true; try { const response = await axios.get(BDR_API_URL, { headers: { 'Authorization': `Bearer ${token}` } }); // 判断返回的数据是否是数组 if (Array.isArray(response.data)) { // 缓存所有数据 bdrCache.value = response.data; // 根据关键字过滤 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName && item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); // 最多显示10条 } else { // 未输入关键字时显示前10条 bdrOptions.value = bdrCache.value.slice(0, 10); } } else { // 如果不是数组,则按照原有格式处理(假设有code和data) if (response.data && response.data.code === 200) { bdrCache.value = response.data.data || []; // 同样的过滤逻辑 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } else { const msg = response.data?.msg || '返回数据格式不正确'; ElMessage.error('获取被测评人列表失败: ' + msg); } } } catch (error) { console.error('获取被测评人列表失败:', error); ElMessage.error('获取被测评人列表失败'); } finally { bdrLoading.value = false; } }; // 搜索被测评人(防抖) let searchBdrTimer = null; const searchBdr = (query) => { if (searchBdrTimer) clearTimeout(searchBdrTimer); searchBdrTimer = setTimeout(() => { if (bdrCache.value.length === 0) { fetchBdrList(query); } else { // 本地过滤 if (query) { const searchTerm = query.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } }, 300); }; // 获取认证令牌 const getAuthToken = () => { const token = localStorage.getItem('token'); if (!token) { ElMessage.warning('请先登录'); router.push('/login'); return null; } return token; }; // 搜索按钮处理函数 - 防抖 let searchTimer = null; const handleSearch = () => { // 检查被测评人选择数量 if (formData.dcId.length > 1) { ElMessage.warning({ message: '当前只能搜索一个被测人员', duration: 3000 }); return; } if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { pagination.current = 1; fetchData(); }, 300); }; // 重置按钮处理函数 const handleReset = () => { if (indexForm.value) { indexForm.value.resetFields(); // 确保重置后 dcId 是空数组 formData.dcId = []; } handleSearch(); }; // 编辑/查看 const handleView = (row) => { router.push({ name: 'Operation', // 路由名称 params: { id: row.dcWjId // 传递问卷ID作为参数 } }); }; // 分页大小改变 const handleSizeChange = (size) => { pagination.size = size; fetchData(); }; // 页码改变 const handlePageChange = (page) => { pagination.current = page; fetchData(); }; // 获取数据 const fetchData = async () => { // 获取认证令牌 const token = getAuthToken(); if (!token) return; // 取消之前的请求 if (cancelTokenSource) { cancelTokenSource.cancel('请求被取消'); } cancelTokenSource = axios.CancelToken.source(); loading.value = true; try { // 构造请求参数 const params = { pageNum: pagination.current, pageSize: pagination.size, ...formData, // 安全处理:确保 dcId 是数组再 join dcId: Array.isArray(formData.dcId) ? formData.dcId.join(',') : '' // 将数组转换为逗号分隔的字符串 }; // 调用API - 添加认证头 const response = await axios.get(API_URL, { params, cancelToken: cancelTokenSource.token, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); // 处理响应数据 const { data } = response; if (data && data.code === 200) { // 修改点:直接使用 data.rows 和 data.total tableData.value = data.rows || []; pagination.total = data.total || 0; // 空数据提示 if (tableData.value.length === 0) { ElMessage.info('没有找到匹配的数据'); } } else { const errorMsg = data?.msg || '未知错误'; console.error('API返回错误:', errorMsg); ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } catch (error) { // 处理认证失败 if (error.response && error.response.status === 401) { ElMessage.error('认证过期,请重新登录'); localStorage.removeItem('token'); router.push('/login'); return; } // 忽略取消请求的错误 if (!axios.isCancel(error)) { console.error('获取数据失败:', error); const errorMsg = error.response?.data?.message || '网络请求失败'; ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } finally { loading.value = false; } }; // 页面加载时获取初始数据 onMounted(() => { fetchData(); }); // 组件卸载时取消所有请求 onUnmounted(() => { if (cancelTokenSource) { cancelTokenSource.cancel('组件卸载,取消请求'); } }); </script> <style scoped> .form-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; } .inline-form-item { flex: 1; min-width: 250px; } .inline-form-item :deep(.el-form-item__label) { float: left; width: auto; padding-right: 12px; line-height: 32px; } .inline-form-item :deep(.el-form-item__content) { display: flex; flex: 1; } /* 移动端响应式 */ @media (max-width: 768px) { .form-row { flex-direction: column; gap: 16px; } .inline-form-item { min-width: 100%; } .inline-form-item :deep(.el-form-item__label) { float: none; width: 100%; padding-right: 0; padding-bottom: 8px; } } /* 卡片容器样式 */ .card-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); gap: 16px; } /* 单个卡片样式 */ .data-card-item { background: #fff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); padding: 16px; display: flex; flex-direction: column; transition: all 0.3s ease; border: 1px solid #ebeef5; } .data-card-item:hover { transform: translateY(-4px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); } /* 卡片头部(序号+标题) */ .card-header-section { padding-bottom: 12px; border-bottom: 1px solid #f0f2f5; margin-bottom: 12px; } .card-id { font-size: 14px; color: #909399; margin-bottom: 4px; } .card-title { font-size: 16px; font-weight: 600; color: #303133; line-height: 1.4; word-break: break-word; } /* 卡片主体(其他信息) */ .card-body-section { flex: 1; margin-bottom: 12px; } .card-row { display: flex; margin-bottom: 8px; font-size: 14px; } .card-label { color: #606266; min-width: 70px; text-align: right; } .card-value { color: #303133; flex: 1; word-break: break-word; } /* 卡片底部(状态+按钮) */ .card-footer-section { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid #f0f2f5; } .status-container { display: flex; align-items: center; gap: 8px; } .score { font-size: 14px; color: #e6a23c; font-weight: 500; } .action-btn { flex-shrink: 0; } /* 移动端响应式 */ @media (max-width: 768px) { .card-container { grid-template-columns: 1fr; } .card-row { flex-direction: column; margin-bottom: 12px; } .card-label { text-align: left; margin-bottom: 4px; font-weight: 500; } .card-footer-section { flex-direction: column; align-items: stretch; gap: 12px; } .status-container { justify-content: space-between; } } /* 添加选择器样式 */ :deep(.el-select) .el-input__inner { height: auto !important; min-height: 44px; padding: 5px 15px; } /* 标签样式 */ :deep(.el-tag) { margin: 2px 6px 2px 0; } /* 下拉菜单样式 */ :deep(.el-select-dropdown) { max-height: 300px; overflow-y: auto; } .index-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); } .card-header { font-size: 18px; font-weight: 600; color: #1a1a1a; } .mobile-form { :deep(.el-form-item__label) { font-weight: 500; margin-bottom: 6px; } :deep(.el-input__inner) { height: 44px; border-radius: 8px; } } .mobile-select { width: 100%; :deep(.el-input__inner) { height: 44px; } } /* 按钮区域样式 */ .button-group { display: flex; gap: 12px; margin-top: 16px; } .action-button { flex: 1; height: 46px; font-size: 16px; border-radius: 8px; } /* 移动端响应式调整 */ @media (max-width: 480px) { .button-group { flex-direction: column; gap: 10px; } .action-button { width: 100%; } } </style> 我想要被测评人和人员部门输入框的宽高一致

filetype

<template> <view class="detail-container"> <text>这是详情页</text> </view> </template> <script> export default { setup() { // 可以在这里添加逻辑 } } </script> <style> .detail-container { display: flex; justify-content: center; align-items: center; height: 100vh; } </style>这个是我的详情页代码,现在我想要顶部有一个索引板块,板块里有输入框问卷标题:(cWjTitle)、输入框被测评人(dcId)、输入框人员部门(dcDept)、下拉选择框人员状态(state),代码逻辑和接口参照以下代码:<template>
<el-card class="index-card"> <el-form :model="formData" label-position="top" ref="indexForm" class="mobile-form" > <el-form-item label="问卷标题:" prop="dcWjTitle"> <el-input v-model="formData.dcWjTitle" placeholder="请输入问卷标题" clearable :prefix-icon="Document" /> </el-form-item>
<el-form-item label="被测评人:" prop="dcId" class="inline-form-item"> <el-select v-model="formData.dcId" multiple filterable remote reserve-keyword clearable placeholder="请选择被测评人" :remote-method="searchBdr" :loading="bdrLoading" @focus="handleBdrFocus" > <el-option v-for="item in bdrOptions" :key="item.dcId" :label="item.dcName" :value="item.dcId" /> </el-select> </el-form-item> <el-form-item label="人员部门:" prop="dcDept" class="inline-form-item"> <el-input v-model="formData.dcDept" placeholder="请输入人员部门" clearable :prefix-icon="OfficeBuilding" /> </el-form-item>
<el-form-item label="提交状态:" prop="state"> <el-select v-model="formData.state" placeholder="请选择提交状态" clearable class="mobile-select" > <el-option label="已提交" :value="1" /> <el-option label="未提交" :value="0" /> </el-select> </el-form-item> <el-form-item class="button-group"> <el-button type="primary" @click="handleSearch" class="action-button" :icon="Search" > 搜索 </el-button> <el-button @click="handleReset" class="action-button" :icon="Refresh" > 重置 </el-button> </el-form-item> </el-form> </el-card> <el-card class="data-card"> <template #header>
<el-button type="primary" size="small" :icon="Refresh" @click="fetchData" > 刷新数据 </el-button>
</template>
{{ item.dcWjTitle }}
被测评人: {{ item.dcName }}
部门: {{ item.dcDept }}
创建时间: {{ item.createTime }}
提交时间: {{ item.updateTime || '-' }}
<el-tag :type="item.state === '1' ? 'success' : 'info'"> {{ item.state === '1' ? '已提交' : '未提交' }} </el-tag>
总分: {{ item.score || '0' }}
<el-button size="small" type="primary" @click="handleView(item)" class="action-btn" > 编辑/查看 </el-button>
<el-empty v-if="tableData.length === 0" description="暂无数据" />
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size" :page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" @current-change="handlePageChange" />
</el-card>
</template> <script setup> // 确保正确导入所有 Vue 函数 import { ref, reactive, onMounted, onUnmounted } from 'vue'; import axios from 'axios'; import { Document, User, OfficeBuilding, Search, Refresh } from '@element-plus/icons-vue'; import { ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; const router = useRouter(); // 环境变量管理API地址 const API_BASE = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api'; const API_URL = `${API_BASE}/wjdc/wj/listTx`; const BDR_API_URL = `${API_BASE}/wjdc/wj/getBdrList`; // 被测评人相关数据 const bdrOptions = ref([]); // 被测评人选项列表 const bdrLoading = ref(false); // 加载状态 const bdrCache = ref([]); // 缓存所有被测评人数据 // 表单数据 const formData = reactive({ dcWjTitle: '', dcId: [], dcDept: '', state: null }); // 表格数据 const tableData = ref([]); const loading = ref(false); // 分页配置 const pagination = reactive({ current: 1, size: 10, total: 0 }); // 表单引用 const indexForm = ref(null); // 请求取消令牌 let cancelTokenSource = axios.CancelToken.source(); // 处理被测评人输入框获取焦点 const handleBdrFocus = () => { if (bdrCache.value.length === 0) { fetchBdrList(''); } }; // 获取被测评人列表 const fetchBdrList = async (keyword = '') => { const token = getAuthToken(); if (!token) return; bdrLoading.value = true; try { const response = await axios.get(BDR_API_URL, { headers: { 'Authorization': `Bearer ${token}` } }); // 判断返回的数据是否是数组 if (Array.isArray(response.data)) { // 缓存所有数据 bdrCache.value = response.data; // 根据关键字过滤 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName && item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); // 最多显示10条 } else { // 未输入关键字时显示前10条 bdrOptions.value = bdrCache.value.slice(0, 10); } } else { // 如果不是数组,则按照原有格式处理(假设有code和data) if (response.data && response.data.code === 200) { bdrCache.value = response.data.data || []; // 同样的过滤逻辑 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } else { const msg = response.data?.msg || '返回数据格式不正确'; ElMessage.error('获取被测评人列表失败: ' + msg); } } } catch (error) { console.error('获取被测评人列表失败:', error); ElMessage.error('获取被测评人列表失败'); } finally { bdrLoading.value = false; } }; // 搜索被测评人(防抖) let searchBdrTimer = null; const searchBdr = (query) => { if (searchBdrTimer) clearTimeout(searchBdrTimer); searchBdrTimer = setTimeout(() => { if (bdrCache.value.length === 0) { fetchBdrList(query); } else { // 本地过滤 if (query) { const searchTerm = query.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } }, 300); }; // 获取认证令牌 const getAuthToken = () => { const token = localStorage.getItem('token'); if (!token) { ElMessage.warning('请先登录'); router.push('/login'); return null; } return token; }; // 搜索按钮处理函数 - 防抖 let searchTimer = null; const handleSearch = () => { // 检查被测评人选择数量 if (formData.dcId.length > 1) { ElMessage.warning({ message: '当前只能搜索一个被测人员', duration: 3000 }); return; } if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { pagination.current = 1; fetchData(); }, 300); }; // 重置按钮处理函数 const handleReset = () => { if (indexForm.value) { indexForm.value.resetFields(); // 确保重置后 dcId 是空数组 formData.dcId = []; } handleSearch(); }; // 编辑/查看 const handleView = (row) => { router.push({ name: 'Operation', // 路由名称 params: { id: row.dcWjId // 传递问卷ID作为参数 } }); }; // 分页大小改变 const handleSizeChange = (size) => { pagination.size = size; fetchData(); }; // 页码改变 const handlePageChange = (page) => { pagination.current = page; fetchData(); }; // 获取数据 const fetchData = async () => { // 获取认证令牌 const token = getAuthToken(); if (!token) return; // 取消之前的请求 if (cancelTokenSource) { cancelTokenSource.cancel('请求被取消'); } cancelTokenSource = axios.CancelToken.source(); loading.value = true; try { // 构造请求参数 const params = { pageNum: pagination.current, pageSize: pagination.size, ...formData, // 安全处理:确保 dcId 是数组再 join dcId: Array.isArray(formData.dcId) ? formData.dcId.join(',') : '' // 将数组转换为逗号分隔的字符串 }; // 调用API - 添加认证头 const response = await axios.get(API_URL, { params, cancelToken: cancelTokenSource.token, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); // 处理响应数据 const { data } = response; if (data && data.code === 200) { // 修改点:直接使用 data.rows 和 data.total tableData.value = data.rows || []; pagination.total = data.total || 0; // 空数据提示 if (tableData.value.length === 0) { ElMessage.info('没有找到匹配的数据'); } } else { const errorMsg = data?.msg || '未知错误'; console.error('API返回错误:', errorMsg); ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } catch (error) { // 处理认证失败 if (error.response && error.response.status === 401) { ElMessage.error('认证过期,请重新登录'); localStorage.removeItem('token'); router.push('/login'); return; } // 忽略取消请求的错误 if (!axios.isCancel(error)) { console.error('获取数据失败:', error); const errorMsg = error.response?.data?.message || '网络请求失败'; ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } finally { loading.value = false; } }; // 页面加载时获取初始数据 onMounted(() => { fetchData(); }); // 组件卸载时取消所有请求 onUnmounted(() => { if (cancelTokenSource) { cancelTokenSource.cancel('组件卸载,取消请求'); } }); </script> <style scoped> .form-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; } .inline-form-item { flex: 1; min-width: 250px; } .inline-form-item :deep(.el-form-item__label) { float: left; width: auto; padding-right: 12px; line-height: 32px; } .inline-form-item :deep(.el-form-item__content) { display: flex; flex: 1; } /* 移动端响应式 */ @media (max-width: 768px) { .form-row { flex-direction: column; gap: 16px; } .inline-form-item { min-width: 100%; } .inline-form-item :deep(.el-form-item__label) { float: none; width: 100%; padding-right: 0; padding-bottom: 8px; } } /* 卡片容器样式 */ .card-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); gap: 16px; } /* 单个卡片样式 */ .data-card-item { background: #fff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); padding: 16px; display: flex; flex-direction: column; transition: all 0.3s ease; border: 1px solid #ebeef5; } .data-card-item:hover { transform: translateY(-4px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); } /* 卡片头部(序号+标题) */ .card-header-section { padding-bottom: 12px; border-bottom: 1px solid #f0f2f5; margin-bottom: 12px; } .card-id { font-size: 14px; color: #909399; margin-bottom: 4px; } .card-title { font-size: 16px; font-weight: 600; color: #303133; line-height: 1.4; word-break: break-word; } /* 卡片主体(其他信息) */ .card-body-section { flex: 1; margin-bottom: 12px; } .card-row { display: flex; margin-bottom: 8px; font-size: 14px; } .card-label { color: #606266; min-width: 70px; text-align: right; } .card-value { color: #303133; flex: 1; word-break: break-word; } /* 卡片底部(状态+按钮) */ .card-footer-section { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid #f0f2f5; } .status-container { display: flex; align-items: center; gap: 8px; } .score { font-size: 14px; color: #e6a23c; font-weight: 500; } .action-btn { flex-shrink: 0; } /* 移动端响应式 */ @media (max-width: 768px) { .card-container { grid-template-columns: 1fr; } .card-row { flex-direction: column; margin-bottom: 12px; } .card-label { text-align: left; margin-bottom: 4px; font-weight: 500; } .card-footer-section { flex-direction: column; align-items: stretch; gap: 12px; } .status-container { justify-content: space-between; } } /* 添加选择器样式 */ :deep(.el-select) .el-input__inner { height: auto !important; min-height: 44px; padding: 5px 15px; } /* 标签样式 */ :deep(.el-tag) { margin: 2px 6px 2px 0; } /* 下拉菜单样式 */ :deep(.el-select-dropdown) { max-height: 300px; overflow-y: auto; } .index-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); } .card-header { font-size: 18px; font-weight: 600; color: #1a1a1a; } .mobile-form { :deep(.el-form-item__label) { font-weight: 500; margin-bottom: 6px; } :deep(.el-input__inner) { height: 44px; border-radius: 8px; } } .mobile-select { width: 100%; :deep(.el-input__inner) { height: 44px; } } /* 按钮区域样式 */ .button-group { display: flex; gap: 12px; margin-top: 16px; } .action-button { flex: 1; height: 46px; font-size: 16px; border-radius: 8px; } /* 移动端响应式调整 */ @media (max-width: 480px) { .button-group { flex-direction: column; gap: 10px; } .action-button { width: 100%; } } </style> 但是样式布局要适用于手机端,注意这个是要写到移动端,uniapp+Vue3的项目里。

filetype

2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Running the test! 2025-07-01 15:20:56,557 INFO o.a.j.s.SampleEvent: List of sample_variables: [] 2025-07-01 15:20:56,557 INFO o.a.j.g.u.JMeterMenuBar: setRunning(true, *local*) 2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Starting setUp thread groups 2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Starting setUp ThreadGroup: 1 : tbd 线程组 2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Starting 1 threads for group tbd 线程组. 2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Thread will continue on error 2025-07-01 15:20:56,557 INFO o.a.j.t.ThreadGroup: Starting thread group... number=1 threads=1 ramp-up=1 delayedStart=false 2025-07-01 15:20:56,557 INFO o.a.j.t.ThreadGroup: Started thread group number 1 2025-07-01 15:20:56,557 INFO o.a.j.e.StandardJMeterEngine: Waiting for all setup thread groups to exit 2025-07-01 15:20:56,557 INFO o.a.j.t.JMeterThread: Thread started: tbd 线程组 1-1 2025-07-01 15:20:56,677 INFO o.a.j.u.BeanShellTestElement: Classpath: /D:/%e6%97%a5%e5%b8%b8%e8%bd%af%e4%bb%b6/H.Jmeter/apache-jmeter-5.6.3/bin/ApacheJMeter.jar 2025-07-01 15:20:56,677 INFO o.a.j.u.BeanShellTestElement: ✅ ITesseract 类加载成功 2025-07-01 15:20:56,783 INFO o.a.j.t.JMeterThread: Thread is done: tbd 线程组 1-1 2025-07-01 15:20:56,783 INFO o.a.j.t.JMeterThread: Thread finished: tbd 线程组 1-1 2025-07-01 15:20:56,783 INFO o.a.j.e.StandardJMeterEngine: All Setup Threads have ended 2025-07-01 15:20:56,924 INFO o.a.j.e.StandardJMeterEngine: No enabled thread groups found 2025-07-01 15:20:56,924 INFO o.a.j.e.StandardJMeterEngine: Notifying test listeners of end of test 2025-07-01 15:20:56,924 INFO o.a.j.g.u.JMeterMenuBar: setRunning(false, *local*)

filetype

<template>
{{ section.name }}
<a-empty />
<a-form ref="searchHeaderRef" :model="searchForm" label-align="left" auto-label-width layout="inline" :size="'large'" class="search-header" > <a-form-item field="base_title" label="能力名称:" size="large" style="width: 420px" > <a-input allow-clear v-model="searchForm.base_title" placeholder="请输入能力名称..." @press-enter="fetchTableData" @clear="resetSearch" /> </a-form-item> <a-form-item field="" label=""> <a-space size="medium"> <a-button type="primary" size="medium" @click="fetchTableData" >查询</a-button > <a-button type="primary" size="medium" @click="resetSearch" >刷新</a-button > </a-space> </a-form-item> </a-form> <a-spin :loading="loading" style="width: 100%">
{{ section.name }}
<template v-for="(subSection, subIndex) in section.children" :key="subIndex" >
{{ subSection.name }}
背景图片
内容图片
<icon-image />
{{ item.title }}
{{ item.description }}
</template>
<a-empty />
</a-spin>
</template> <script setup lang="ts"> import { ref, onMounted, nextTick, reactive, onBeforeUnmount } from 'vue'; import { Message } from '@arco-design/web-vue'; import { IconImage } from '@arco-design/web-vue/es/icon'; import { useAbilityMallStore } from '@/store/modules/ability-mall'; import { storeToRefs } from 'pinia'; import { useRouter } from 'vue-router'; import { getAbilityMallList, getabilityMallDetails, createAbilityMall, } from '@/api/abilityMall'; const abilityMallStore = useAbilityMallStore(); const { abilityMallList, abilityMallDetails } = storeToRefs(abilityMallStore); const { getabilityMallDetailsStore } = abilityMallStore; const router = useRouter(); // 定义三级分类数据结构 interface CategoryItem { id: string; title: string; description: string; image: string; // 添加图片字段 } interface SubCategory { id: string; name: string; children: CategoryItem[]; } interface MainCategory { id: string; name: string; children: SubCategory[]; } // 状态管理 const sections = ref<MainCategory[]>([]); const contentRef = ref<HTMLElement | null>(null); const sectionRefs = ref<HTMLElement[]>([]); const activeIndex = ref(0); const loading = ref(false); const searchForm = reactive({ base_title: '', current: '', pageSize: '', }); // 创建 IntersectionObserver 实例 let observer = ref(null) // 更高效的数据转换函数 - 修复图片字段 const transformData = (apiData: any[]): MainCategory[] => { const categoryMap = new Map<string, MainCategory>(); const subcategoryMap = new Map<string, SubCategory>(); apiData.forEach((item) => { const categoryName = item.base_category; const categoryId = categoryName.replace(/\s+/g, '-').toLowerCase(); // 处理一级分类 if (!categoryMap.has(categoryId)) { categoryMap.set(categoryId, { id: categoryId, name: categoryName, children: [], }); } const category = categoryMap.get(categoryId)!; // 处理二级分类 const subcategoryName = item.base_subcategory; const subcategoryId = `${categoryId}-${subcategoryName .replace(/\s+/g, '-') .toLowerCase()}`; if (!subcategoryMap.has(subcategoryId)) { const subcategory: SubCategory = { id: subcategoryId, name: subcategoryName, children: [], }; subcategoryMap.set(subcategoryId, subcategory); category.children.push(subcategory); } const subcategory = subcategoryMap.get(subcategoryId)!; // 添加三级分类项 - 包含图片字段 subcategory.children.push({ id: item.id, title: item.base_title, description: item.base_content, image: item.base_image, // 添加图片字段 }); }); return Array.from(categoryMap.values()); }; // 设置章节引用 const setSectionRef = (el: any) => { if (el) { sectionRefs.value.push(el); } }; // 左侧 Tab 点击跳转 const scrollToSection = (index) => { activeIndex.value = index; const section = sectionRefs.value[index]; if (section) { section.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; // 初始化观察者 const initObserver = () => { observer.value = new IntersectionObserver( (entries) => { entries.forEach((entry) => { const index = sectionRefs.value.indexOf(entry.target); if (entry.isIntersecting) { activeIndex.value = index; } }); }, { threshold: 0.5, // 当目标元素 50% 可见时触发 rootMargin: "0px 0px -100% 0px", // 提前触发,防止底部卡住 } ); // 开始观察所有章节 sectionRefs.value.forEach((section) => { if (section) observer.observe(section); }); }; // 销毁观察者 const destroyObserver = () => { if (observer) { observer.value.disconnect(); } }; onMounted(() => { fetchTableData(); initObserver(); }); onBeforeUnmount(() => { destroyObserver(); }); // 重置搜索 const resetSearch = () => { searchForm.base_title = ''; fetchTableData(); }; // 获取数据 async function fetchTableData() { loading.value = true; try { const { data } = await getAbilityMallList(searchForm); const filteredData = data.filter((item) => item.deleted === 0); // const fakeData = Array.from({ length: 100 }, (_, index) => ({ // id: `item-${index}`, // base_category: `一级分类 ${Math.floor(Math.random() * 20)}`, // base_subcategory: `二级分类 ${Math.floor(Math.random() * 10)}`, // base_title: `能力名称 ${index + 1}`, // base_content: `描述内容 ${index + 1}`, // base_image: `https://via.placeholder.com/100?text=Image${index + 1}`, // deleted: Math.random() > 0.2 ? 0 : 1, // 80% chance of being valid // })); // 使用模拟数据 sections.value = transformData(filteredData || []); // 重置引用 nextTick(() => { sectionRefs.value = []; // 添加初始滚动位置修正 setTimeout(() => { const hash = window.location.hash.substring(1); if (hash) { const index = sections.value.findIndex((s) => s.id === hash); if (index !== -1) { scrollToSection(index); } } else if (sections.value.length > 0) { scrollToSection(0); } }, 100); }); } catch (error) { console.error('获取能力模型失败:', error); Message.error('获取能力模型失败'); loading.value = false; } finally { loading.value = false; } } // 跳转详情 const sceneDetail = async (item: CategoryItem) => { await getabilityMallDetailsStore(item.id); router.push({ path: '/ability/details', query: { id: item.id }, }); }; </script> <style scoped lang="less"> /* 父容器 */ .container { display: flex; height: 100vh; /* 让父容器撑满页面 */ position: relative; padding-left: 40px; background: #fff; font-family: 'DingTalkJinBuTi', serif; } /* 左侧导航栏样式 */ .tabs { width: 180px; padding: 20px 0; flex-shrink: 0; position: sticky; /* 使用粘性定位 */ top: 0; /* 固定在页面顶部 70px 位置 */ max-height: calc(100vh - 70px); /* 最大高度为视口高度,避免溢出 */ overflow-y: auto; /* 允许左侧滚动条 */ z-index: 10; .tab { height: 40px; line-height: 40px; letter-spacing: 1px; text-align: center; margin: 20px; margin-bottom: 12px; font-size: 16px; color: #181818; cursor: pointer; position: relative; transition: all 0.3s ease-in-out; border-radius: 4px; &:hover { background: linear-gradient(90deg, #3261ce 0%, #739ce2 100%); color: #fff; opacity: 0.9; transform: translateX(5px); } } .tab.active { color: #fff; background: linear-gradient(90deg, #3261ce 0%, #739ce2 100%); opacity: 1; box-shadow: 0 2px 8px rgba(50, 97, 206, 0.4); } } .tab-wrapper { overflow: auto; height: 100%; } /* 右侧内容区域 */ .content { flex: 1; height: 100%; overflow-y: auto; /* 允许右侧内容滚动 */ position: relative; scroll-behavior: smooth; margin-left: 20px; /* 右侧内容区域距离左侧导航栏 */ padding-top: 20px; padding-left: 20px; border-left: 1px solid rgba(0, 0, 0, 0.05); } /* 搜索头部样式 */ .content .search-header { width: 100%; display: flex; gap: 16px; padding: 15px 20px; background: #fff; border-bottom: 1px solid rgba(0, 0, 0, 0.05); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); ::v-deep(.arco-form-item) { margin-bottom: 0; } ::v-deep(.arco-form-item-label) { color: #4e5965; } } /* 分类区域样式 */ .section { height: auto; padding: 20px 20px 20px 0; position: relative; border-bottom: 1px solid rgba(0, 0, 0, 0.05); margin-top: 20px; &:first-child { margin-top: 0; } } .section .section-title { border-bottom: 1px solid rgba(0, 0, 0, 0.1); font-size: 22px; color: #181818; height: 50px; display: flex; align-items: center; padding-bottom: 10px; margin-bottom: 20px; } .section .title { font-size: 18px; color: #3261ce; margin: 24px 0 12px; padding-left: 10px; border-left: 4px solid #3261ce; } /* 内容项网格布局 */ .section .sub-content { display: grid; grid-template-columns: repeat(auto-fill, minmax(242px, 1fr)); gap: 20px; margin-top: 20px; position: relative; } /* 内容项样式 */ .section .sub-content .content-item { position: relative; height: 73px; cursor: pointer; // transition: all 0.3s ease; border: 1px solid rgba(0, 0, 0, 0.05); border-radius: 6px; overflow: hidden; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); &:hover { // transform: translateY(-5px); box-shadow: 0 8px 16px rgba(50, 97, 206, 0.2); border-color: rgba(50, 97, 206, 0.3); .position-img { opacity: 1; } .item { backdrop-filter: blur(5px); // background-color: hsla(0, 0%, 100%, 0.85); } .item-desc { opacity: 0.9; } .item-image img { transform: scale(1.35); } } } /* 内容卡片样式 */ .section .sub-content .content-item .item { display: flex; position: relative; overflow: hidden; border-radius: 6px; width: 100%; height: 100%; z-index: 2; // transition: all 0.3s ease; } /* 图片样式 */ .section .sub-content .content-item .item-image { width: 70px; height: 100%; flex-shrink: 0; overflow: hidden; padding: 8px; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; .image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #f5f7fa; color: #c9cdd4; svg { font-size: 24px; } } img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.3s ease; } } /* 文本区域样式 */ .section .sub-content .content-item .item-text { flex: 1; padding: 8px 12px; display: flex; flex-direction: column; justify-content: center; overflow: hidden; .item-title { font-size: 14px; color: #171717cc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .item-desc { font-size: 12px; color: #181818; margin-top: 4px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; line-height: 1.4; // transition: opacity 0.3s ease; } } /* 背景图片 */ .position-img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; overflow: hidden; // transition: opacity 0.3s ease-in-out; z-index: 1; img { width: 100%; height: 100%; object-fit: cover; filter: blur(2px) brightness(0.9); } } /* 占位空间 */ .spacer { height: 100px; } /* 响应式调整 */ @media (max-width: 992px) { .container { flex-direction: column; padding: 0 16px; } .tabs { position: static; width: 100%; margin-right: 0; max-height: none; display: flex; overflow-x: auto; padding: 10px 0; .tab { flex-shrink: 0; margin: 0 10px; } } .content { margin-left: 0; padding-top: 10px; } } </style> 右侧滚动条滚动的时候左侧tab 被选中

filetype

import IconFont from '@components/Iconfont'; import { getToolRecentUseKeys } from '@utils/common.ts'; import { isMobile } from '@wander/base-utils'; import type { MenuProps } from 'antd'; import { Menu } from 'antd'; import classNames from 'classnames/bind'; import { floor } from 'lodash'; import { useEffect, useState } from 'react'; import { NavLink, useLocation, useNavigate } from 'react-router-dom'; import { ADVANCE_DRAW_RECOMMEND_CATEGORY_CONFIG_KEY } from '@/constant.ts'; import { aiMenuList } from '@/pages/ToolList/pc/components/Menu/config.tsx'; import { useStore } from '@/store/createStore'; import styles from './index.module.less'; const cx = classNames.bind(styles); // 每个item高度 48 是item高度 上下还有4px间距 margin 会重叠 只需要加1个4px就够了 const MENU_ITEM_HEIGHT = 52; // 默认菜单高度 48 每个item 10 默认有10个必须显示 const DEFAULT_MENU_HEIGHT = MENU_ITEM_HEIGHT * 5; // header菜单栏高度 const HEADER_LAYOUT_HEIGHT = 80; // 偏差值 避免高度计算不准确 const OVERSCAN_VALUE = 16; const AiPageMenu = () => { const navigate = useNavigate(); const location = useLocation(); const [selectedKeys, setSelectedKeys] = useState(['home']); const toolList = useStore((state) => { return (state.functionSortMap['DRAW_SIDEBAR'] || []).map((value) => { return state.functionList.find((value1) => value1.key === value)!; }); }); // 最近使用工具列表 const { recentlyToolList } = useStore(() => { // 使用次数配置 const recentUseKeys: string[] = getToolRecentUseKeys(); return { recentlyToolList: recentUseKeys .map((value) => { return toolList.filter((value1) => value1.routeKey === value)?.[0]; }) .filter(Boolean) .slice(0, 5), }; }); console.log('toolList', toolList); console.log('recentlyToolList', recentlyToolList); // 推荐一级类目列表 const recommendCategoryList = useStore((state) => { return state.advanceDrawFirstCategoryList.filter((value) => { return (state.initConfigs[ADVANCE_DRAW_RECOMMEND_CATEGORY_CONFIG_KEY] || []).includes( value.mid, ); }); }); // 记录收起菜单位置 的索引 初始值给4 避免闪烁太严重 const [collapseToolIndex, setCollapseToolIndex] = useState(4); // 记录视口高度 const [innerHeight, setInnerHeight] = useState(0); // 工具是否已展开 const [toolCollapsed, setToolCollapsed] = useState(false); useEffect(() => { const handleResize = () => { setInnerHeight(window.innerHeight); }; handleResize(); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); useEffect(() => { // 计算工具显示个数 if (!isMobile() && !toolCollapsed) { // 工具剩余可占位高度 let toolContainerHeight = innerHeight - DEFAULT_MENU_HEIGHT - HEADER_LAYOUT_HEIGHT - OVERSCAN_VALUE; if (recentlyToolList.length) { toolContainerHeight = toolContainerHeight - MENU_ITEM_HEIGHT * (recentlyToolList.length + 1); } // 显示工具个数 const showToolCount = floor(toolContainerHeight / MENU_ITEM_HEIGHT); // 留一个查看更多的位置 setCollapseToolIndex(showToolCount - 1); } }, [recentlyToolList.length, innerHeight, toolCollapsed, toolList]); useEffect(() => { const currentItem = aiMenuList.find((value) => value.route === location.pathname); setSelectedKeys([currentItem?.key || 'home']); }, [location.pathname]); const onSelect: MenuProps['onSelect'] = ({ key, selectedKeys: newSelectedKeys }) => { setSelectedKeys(newSelectedKeys); if (key === 'toolMore') { // 查看更多AI工具 setToolCollapsed(true); return; } if (key === 'collapseToolMenu') { // 收起更多AI工具 setToolCollapsed(false); return; } }; return (
<Menu theme="dark" selectedKeys={selectedKeys} defaultOpenKeys={['commonTool', 'tools']} mode="inline" items={aiMenuList.map((value) => { if (value.key === 'draw') { return { label: value.labelKey, key: value.key, icon: value.icon, children: recommendCategoryList.map((value1) => ({ label: (
{ navigate('/ai/advance_draw/operate', { state: { record: { selectMids: [value1.mid], }, }, }); }} > {value1.name}
), key: value1.parentId, })), }; } if (value.key === 'commonTool') { if (!recentlyToolList.length) { return null; } return { label: value.labelKey, key: value.key, icon: value.icon, children: recentlyToolList.map((value1) => { return { label: <NavLink to={value1.route}>{value1.shortTitle || value1.title}</NavLink>, // key值和AI工具重复了 key: `${value.key}${value1.key}`, }; }), }; } if (value.key === 'tools') { return { label: value.labelKey, key: value.key, icon: value.icon, children: [ ...(toolCollapsed ? toolList : toolList.slice(0, collapseToolIndex)).map( (value) => { return { label: <NavLink to={value.route}>{value.shortTitle || value.title}</NavLink>, key: value.key, }; }, ), toolCollapsed ? { label: ( 收起 <IconFont type="icon-arrow-up" style={{ marginLeft: 4, fontSize: 12 }} /> ), key: 'collapseToolMenu', } : { label: ( 查看更多 <IconFont type="icon-arrow-bottom" style={{ marginLeft: 4, fontSize: 12 }} /> ), key: 'toolMore', }, ], }; } return { label: value.route ? ( <NavLink to={value.route}>{value.labelKey}</NavLink> ) : ( value.labelKey ), key: value.key, icon: value.icon, }; })} onSelect={onSelect} />
); }; export default AiPageMenu; .menu_container { position: fixed; z-index: 99; width: 150px; height: 100vh; overflow-y: scroll; user-select: none; background: #2f3c48; transition: all 0.3s; scrollbar-gutter: stable; &.en { width: 232px; } &::-webkit-scrollbar { z-index: 999; width: 6px; background: transparent; border-radius: 3px; } &::-webkit-scrollbar-track { border-radius: 3px; } &::-webkit-scrollbar-thumb { background-color: rgb(255 255 255 / 30%); border-radius: 3px; transition: all 0.5s; } :global { .ant-menu-dark { background: #2f3c48; } .ant-menu-item, .ant-menu-inline.ant-menu-root .ant-menu-submenu-title { width: 100%; height: 48px; padding-right: 0; padding-left: 12px !important; margin-inline: 0; line-height: 48px; color: #fff; border-radius: 0; .ant-menu-title-content { line-height: 48px; } } .ant-menu-item.ant-menu-item-only-child { padding-left: 36px !important; color: rgb(255 255 255 / 60%); } .ant-menu .ant-menu-submenu-arrow { inset-inline-end: 8px; } .ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected { background: rgb(255 255 255 / 10%); &::after { position: absolute; top: 25%; left: calc(100% - 2px); width: 2px; height: 50%; content: ''; background: #fff; } } .ant-menu-dark.ant-menu-inline .ant-menu-sub.ant-menu-inline { background: transparent; } } } import IconFont from '@components/Iconfont'; export const aiMenuList = [ { labelKey: '首页', route: '/', key: 'home', icon: <IconFont type="icon-home" />, }, { labelKey: '常用工具', key: 'commonTool', icon: <IconFont type="icon-common-tool" />, }, { labelKey: 'AI绘图', key: 'draw', icon: <IconFont type="icon-ai-draw" />, }, { labelKey: 'AI工具', key: 'tools', icon: <IconFont type="icon-ai-tool" />, }, { labelKey: '我的创作', route: '/user/draw/records', key: 'createRecord', icon: <IconFont type="icon-create-record" />, }, ]; 点击查看更多后 我的创作会被隐藏 看不到除非收起AI工具

filetype

<script setup> import { ref, onMounted } from 'vue'; import { onShow } from '@dcloudio/uni-app'; // 响应式数据 const surveyList = ref([]); const total = ref(0); const loading = ref(false); // 获取问卷数据 const fetchSurveyData = async () => { try { loading.value = true; // 使用uni.request发送请求 const [error, res] = await uni.request({ url: 'http://172.26.26.43/dev-api/wjdc/wj/listTx', method: 'GET', data: { pageNum: 1, pageSize: 10, dcWjTitle: '', dcId: '', dcDept: '' } }); if (error) throw error; // 处理响应数据 const response = res.data; if (response.code === 200) { surveyList.value = response.rows; total.value = response.total; } else { throw new Error(response.msg || '请求失败'); } } catch (error) { uni.showToast({ title: error.message || '加载失败', icon: 'none', duration: 2000 }); } finally { loading.value = false; } }; // 使用onShow替代onMounted确保每次进入页面都刷新 onShow(() => { fetchSurveyData(); }); </script> <template> <view class="container"> <view v-if="loading" class="loading-container"> <view class="loading-spinner"></view> <text class="loading-text">加载中...</text> </view> <template v-else> <text class="total">共 {{ total }} 条记录</text> <view v-for="(item, index) in surveyList" :key="index" class="card"> <view class="title">{{ item.dcWjTitle }}</view> <view class="info"> <text>部门: {{ item.dcDept }}</text> <text>创建人: {{ item.createBy }}</text> </view> <view class="meta"> <text>创建时间: {{ item.createTime }}</text> <text class="score">得分: {{ item.score }}</text> </view> </view> <view v-if="surveyList.length === 0" class="empty"> <text>暂无数据</text> </view> </template> </view> </template> <style scoped> .container { padding: 20rpx; background-color: #f5f5f5; min-height: 100vh; } /* 自定义加载状态样式 */ .loading-container { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40rpx 0; } .loading-spinner { width: 60rpx; height: 60rpx; border: 6rpx solid #f3f3f3; border-top: 6rpx solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 20rpx; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .loading-text { color: #666; font-size: 28rpx; } /* 数据样式 */ .total { display: block; margin: 20rpx 0; padding: 0 20rpx; color: #888; font-size: 28rpx; } .card { padding: 30rpx; margin-bottom: 30rpx; border-radius: 16rpx; background-color: #fff; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05); } .title { font-size: 34rpx; font-weight: bold; margin-bottom: 20rpx; color: #333; } .info { display: flex; justify-content: space-between; color: #666; font-size: 28rpx; margin-bottom: 15rpx; } .meta { display: flex; justify-content: space-between; color: #999; font-size: 26rpx; margin-top: 15rpx; } .score { color: #e74c3c; font-weight: bold; } .empty { text-align: center; padding: 100rpx 0; color: #999; font-size: 32rpx; } </style> 我的数据加载板块参照代码:<template>
<el-card class="index-card"> <el-form :model="formData" label-position="top" ref="indexForm" class="mobile-form" > <el-form-item label="问卷标题:" prop="dcWjTitle"> <el-input v-model="formData.dcWjTitle" placeholder="请输入问卷标题" clearable :prefix-icon="Document" /> </el-form-item>
<el-form-item label="被测评人:" prop="dcId" class="inline-form-item"> <el-select v-model="formData.dcId" multiple filterable remote reserve-keyword clearable placeholder="请选择被测评人" :remote-method="searchBdr" :loading="bdrLoading" @focus="handleBdrFocus" > <el-option v-for="item in bdrOptions" :key="item.dcId" :label="item.dcName" :value="item.dcId" /> </el-select> </el-form-item> <el-form-item label="人员部门:" prop="dcDept" class="inline-form-item"> <el-input v-model="formData.dcDept" placeholder="请输入人员部门" clearable :prefix-icon="OfficeBuilding" /> </el-form-item>
<el-form-item label="提交状态:" prop="state"> <el-select v-model="formData.state" placeholder="请选择提交状态" clearable class="mobile-select" > <el-option label="已提交" :value="1" /> <el-option label="未提交" :value="0" /> </el-select> </el-form-item> <el-form-item class="button-group"> <el-button type="primary" @click="handleSearch" class="action-button" :icon="Search" > 搜索 </el-button> <el-button @click="handleReset" class="action-button" :icon="Refresh" > 重置 </el-button> </el-form-item> </el-form> </el-card> <el-card class="data-card"> <template #header>
<el-button type="primary" size="small" :icon="Refresh" @click="fetchData" > 刷新数据 </el-button>
</template>
{{ item.dcWjTitle }}
被测评人: {{ item.dcName }}
部门: {{ item.dcDept }}
创建时间: {{ item.createTime }}
提交时间: {{ item.updateTime || '-' }}
<el-tag :type="item.state === '1' ? 'success' : 'info'"> {{ item.state === '1' ? '已提交' : '未提交' }} </el-tag>
总分: {{ item.score || '0' }}
<el-button size="small" type="primary" @click="handleView(item)" class="action-btn" > 编辑/查看 </el-button>
<el-empty v-if="tableData.length === 0" description="暂无数据" />
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size" :page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" @current-change="handlePageChange" />
</el-card>
</template> <script setup> // 确保正确导入所有 Vue 函数 import { ref, reactive, onMounted, onUnmounted } from 'vue'; import axios from 'axios'; import { Document, User, OfficeBuilding, Search, Refresh } from '@element-plus/icons-vue'; import { ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; const router = useRouter(); // 环境变量管理API地址 const API_BASE = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api'; const API_URL = `${API_BASE}/wjdc/wj/listTx`; const BDR_API_URL = `${API_BASE}/wjdc/wj/getBdrList`; // 被测评人相关数据 const bdrOptions = ref([]); // 被测评人选项列表 const bdrLoading = ref(false); // 加载状态 const bdrCache = ref([]); // 缓存所有被测评人数据 // 表单数据 const formData = reactive({ dcWjTitle: '', dcId: [], dcDept: '', state: null }); // 表格数据 const tableData = ref([]); const loading = ref(false); // 分页配置 const pagination = reactive({ current: 1, size: 10, total: 0 }); // 表单引用 const indexForm = ref(null); // 请求取消令牌 let cancelTokenSource = axios.CancelToken.source(); // 处理被测评人输入框获取焦点 const handleBdrFocus = () => { if (bdrCache.value.length === 0) { fetchBdrList(''); } }; // 获取被测评人列表 const fetchBdrList = async (keyword = '') => { const token = getAuthToken(); if (!token) return; bdrLoading.value = true; try { const response = await axios.get(BDR_API_URL, { headers: { 'Authorization': `Bearer ${token}` } }); // 判断返回的数据是否是数组 if (Array.isArray(response.data)) { // 缓存所有数据 bdrCache.value = response.data; // 根据关键字过滤 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName && item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); // 最多显示10条 } else { // 未输入关键字时显示前10条 bdrOptions.value = bdrCache.value.slice(0, 10); } } else { // 如果不是数组,则按照原有格式处理(假设有code和data) if (response.data && response.data.code === 200) { bdrCache.value = response.data.data || []; // 同样的过滤逻辑 if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } else { const msg = response.data?.msg || '返回数据格式不正确'; ElMessage.error('获取被测评人列表失败: ' + msg); } } } catch (error) { console.error('获取被测评人列表失败:', error); ElMessage.error('获取被测评人列表失败'); } finally { bdrLoading.value = false; } }; // 搜索被测评人(防抖) let searchBdrTimer = null; const searchBdr = (query) => { if (searchBdrTimer) clearTimeout(searchBdrTimer); searchBdrTimer = setTimeout(() => { if (bdrCache.value.length === 0) { fetchBdrList(query); } else { // 本地过滤 if (query) { const searchTerm = query.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } } }, 300); }; // 获取认证令牌 const getAuthToken = () => { const token = localStorage.getItem('token'); if (!token) { ElMessage.warning('请先登录'); router.push('/login'); return null; } return token; }; // 搜索按钮处理函数 - 防抖 let searchTimer = null; const handleSearch = () => { // 检查被测评人选择数量 if (formData.dcId.length > 1) { ElMessage.warning({ message: '当前只能搜索一个被测人员', duration: 3000 }); return; } if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { pagination.current = 1; fetchData(); }, 300); }; // 重置按钮处理函数 const handleReset = () => { if (indexForm.value) { indexForm.value.resetFields(); // 确保重置后 dcId 是空数组 formData.dcId = []; } handleSearch(); }; // 编辑/查看 const handleView = (row) => { router.push({ name: 'Operation', // 路由名称 params: { id: row.dcWjId // 传递问卷ID作为参数 } }); }; // 分页大小改变 const handleSizeChange = (size) => { pagination.size = size; fetchData(); }; // 页码改变 const handlePageChange = (page) => { pagination.current = page; fetchData(); }; // 获取数据 const fetchData = async () => { // 获取认证令牌 const token = getAuthToken(); if (!token) return; // 取消之前的请求 if (cancelTokenSource) { cancelTokenSource.cancel('请求被取消'); } cancelTokenSource = axios.CancelToken.source(); loading.value = true; try { // 构造请求参数 const params = { pageNum: pagination.current, pageSize: pagination.size, ...formData, // 安全处理:确保 dcId 是数组再 join dcId: Array.isArray(formData.dcId) ? formData.dcId.join(',') : '' // 将数组转换为逗号分隔的字符串 }; // 调用API - 添加认证头 const response = await axios.get(API_URL, { params, cancelToken: cancelTokenSource.token, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); // 处理响应数据 const { data } = response; if (data && data.code === 200) { // 修改点:直接使用 data.rows 和 data.total tableData.value = data.rows || []; pagination.total = data.total || 0; // 空数据提示 if (tableData.value.length === 0) { ElMessage.info('没有找到匹配的数据'); } } else { const errorMsg = data?.msg || '未知错误'; console.error('API返回错误:', errorMsg); ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } catch (error) { // 处理认证失败 if (error.response && error.response.status === 401) { ElMessage.error('认证过期,请重新登录'); localStorage.removeItem('token'); router.push('/login'); return; } // 忽略取消请求的错误 if (!axios.isCancel(error)) { console.error('获取数据失败:', error); const errorMsg = error.response?.data?.message || '网络请求失败'; ElMessage.error(`请求失败: ${errorMsg}`); tableData.value = []; pagination.total = 0; } } finally { loading.value = false; } }; // 页面加载时获取初始数据 onMounted(() => { fetchData(); }); // 组件卸载时取消所有请求 onUnmounted(() => { if (cancelTokenSource) { cancelTokenSource.cancel('组件卸载,取消请求'); } }); </script> <style scoped> .form-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; } .inline-form-item { flex: 1; min-width: 250px; } .inline-form-item :deep(.el-form-item__label) { float: left; width: auto; padding-right: 12px; line-height: 32px; } .inline-form-item :deep(.el-form-item__content) { display: flex; flex: 1; } /* 移动端响应式 */ @media (max-width: 768px) { .form-row { flex-direction: column; gap: 16px; } .inline-form-item { min-width: 100%; } .inline-form-item :deep(.el-form-item__label) { float: none; width: 100%; padding-right: 0; padding-bottom: 8px; } } /* 卡片容器样式 */ .card-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); gap: 16px; } /* 单个卡片样式 */ .data-card-item { background: #fff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); padding: 16px; display: flex; flex-direction: column; transition: all 0.3s ease; border: 1px solid #ebeef5; } .data-card-item:hover { transform: translateY(-4px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); } /* 卡片头部(序号+标题) */ .card-header-section { padding-bottom: 12px; border-bottom: 1px solid #f0f2f5; margin-bottom: 12px; } .card-id { font-size: 14px; color: #909399; margin-bottom: 4px; } .card-title { font-size: 16px; font-weight: 600; color: #303133; line-height: 1.4; word-break: break-word; } /* 卡片主体(其他信息) */ .card-body-section { flex: 1; margin-bottom: 12px; } .card-row { display: flex; margin-bottom: 8px; font-size: 14px; } .card-label { color: #606266; min-width: 70px; text-align: right; } .card-value { color: #303133; flex: 1; word-break: break-word; } /* 卡片底部(状态+按钮) */ .card-footer-section { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid #f0f2f5; } .status-container { display: flex; align-items: center; gap: 8px; } .score { font-size: 14px; color: #e6a23c; font-weight: 500; } .action-btn { flex-shrink: 0; } /* 移动端响应式 */ @media (max-width: 768px) { .card-container { grid-template-columns: 1fr; } .card-row { flex-direction: column; margin-bottom: 12px; } .card-label { text-align: left; margin-bottom: 4px; font-weight: 500; } .card-footer-section { flex-direction: column; align-items: stretch; gap: 12px; } .status-container { justify-content: space-between; } } /* 添加选择器样式 */ :deep(.el-select) .el-input__inner { height: auto !important; min-height: 44px; padding: 5px 15px; } /* 标签样式 */ :deep(.el-tag) { margin: 2px 6px 2px 0; } /* 下拉菜单样式 */ :deep(.el-select-dropdown) { max-height: 300px; overflow-y: auto; } .index-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); } .card-header { font-size: 18px; font-weight: 600; color: #1a1a1a; } .mobile-form { :deep(.el-form-item__label) { font-weight: 500; margin-bottom: 6px; } :deep(.el-input__inner) { height: 44px; border-radius: 8px; } } .mobile-select { width: 100%; :deep(.el-input__inner) { height: 44px; } } /* 按钮区域样式 */ .button-group { display: flex; gap: 12px; margin-top: 16px; } .action-button { flex: 1; height: 46px; font-size: 16px; border-radius: 8px; } /* 移动端响应式调整 */ @media (max-width: 480px) { .button-group { flex-direction: column; gap: 10px; } .action-button { width: 100%; } } </style>

filetype

"code": "500", "msg": "\r\n### Error updating database. Cause: org.postgresql.util.PSQLException: ERROR: null value in column \"knowledge_base_name\" violates not-null constraint\n 详细:Failing row contains (181777392296001719, null, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 0, 1).\r\n### The error may exist in com/iflytek/fpva/cdc/mapper/common/TbCdcewKnowledgeBaseMapper.java (best guess)\r\n### The error may involve com.iflytek.fpva.cdc.mapper.common.TbCdcewKnowledgeBaseMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO tb_cdcew_knowledge_base ( id, modify_user, create_user_id, modify_time, deleted, create_time, modify_user_id, create_user, mark ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: org.postgresql.util.PSQLException: ERROR: null value in column \"knowledge_base_name\" violates not-null constraint\n 详细:Failing row contains (181777392296001719, null, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 0, 1).\n; ERROR: null value in column \"knowledge_base_name\" violates not-null constraint\n 详细:Failing row contains (181777392296001719, null, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 0, 1).; nested exception is org.postgresql.util.PSQLException: ERROR: null value in column \"knowledge_base_name\" violates not-null constraint\n 详细:Failing row contains (181777392296001719, null, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 118142606008909930, 能胜, 2025-05-13 09:56:29.004, 0, 1).",

filetype
内容概要:本文介绍了奕斯伟科技集团基于RISC-V架构开发的EAM2011芯片及其应用研究。EAM2011是一款高性能实时控制芯片,支持160MHz主频和AI算法,符合汽车电子AEC-Q100 Grade 2和ASIL-B安全标准。文章详细描述了芯片的关键特性、配套软件开发套件(SDK)和集成开发环境(IDE),以及基于该芯片的ESWINEBP3901开发板的硬件资源和接口配置。文中提供了详细的代码示例,涵盖时钟配置、GPIO控制、ADC采样、CAN通信、PWM输出及RTOS任务创建等功能实现。此外,还介绍了硬件申领流程、技术资料获取渠道及开发建议,帮助开发者高效启动基于EAM2011芯片的开发工作。 适合人群:具备嵌入式系统开发经验的研发人员,特别是对RISC-V架构感兴趣的工程师和技术爱好者。 使用场景及目标:①了解EAM2011芯片的特性和应用场景,如智能汽车、智能家居和工业控制;②掌握基于EAM2011芯片的开发板和芯片的硬件资源和接口配置;③学习如何实现基本的外设驱动,如GPIO、ADC、CAN、PWM等;④通过RTOS任务创建示例,理解多任务处理和实时系统的实现。 其他说明:开发者可以根据实际需求扩展这些基础功能。建议优先掌握《EAM2011参考手册》中的关键外设寄存器配置方法,这对底层驱动开发至关重要。同时,注意硬件申领的时效性和替代方案,确保开发工作的顺利进行。
国服第一奶妈
  • 粉丝: 42
上传资源 快速赚钱