DeviceLeft.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <template>
  2. <div class="long-list">
  3. <div class="list-title">
  4. <span>设备列表</span>
  5. <span style="margin-left: 5px;">{{ count }}</span>
  6. </div>
  7. <div class="list-content">
  8. <div class="list-search">
  9. <a-input v-model:value="searchData" placeholder="搜索设备编号,名称" size="small" />
  10. </div>
  11. <div class="content-container">
  12. <div class="content-nav">
  13. <div :class="activeIndex == index ? 'nav-item-active' : 'nav-item'" v-for="(item, index) in navList"
  14. :key="index" @click="changeNav(item, index)">
  15. {{ item.label }}
  16. </div>
  17. </div>
  18. <div class="content-box">
  19. <div class="basic-device" v-for="(item, index) in filteredListData" :key="index">
  20. <div class="icon-left">
  21. <!-- 状态指示圆点:根据报警级别显示不同颜色(绿色正常/红色报警) -->
  22. <div :class="item.netStatus ? 'icon-item' : 'icon-item-warn'"></div>
  23. </div>
  24. <!-- 设备标题区域:包含序列号和操作按钮 -->
  25. <div class="basic-title">
  26. <!-- 设备序列号显示 -->
  27. <div class="title-text">{{ item.strserno || '-' }}</div>
  28. <!-- 操作按钮组:详情、配置、重启三种操作 -->
  29. <div class="title-btn">
  30. <div :class="active == index ? 'btn-active' : 'btn'" @click="handlerClick('detail', item, index)">详情
  31. </div>
  32. <div class="btn" @click="handlerClick('config', item, index)">配置</div>
  33. <div class="btn" @click="handlerClick('restart', item, index)">重启</div>
  34. </div>
  35. </div>
  36. <!-- 设备详细信息区域:2x2网格布局展示关键信息 -->
  37. <div class="basic-content">
  38. <div class="content-item">{{ item.strname || '-' }}</div>
  39. <div class="content-item">
  40. <span class="icon-pie">
  41. <span class="pie-item" :class="item.netStatus ? 'pie-item' : 'pie-item-warn'"></span>
  42. </span>
  43. <span>{{ item.netStatus ? '在线' : '离线' }}</span>
  44. </div>
  45. <div class="content-item">{{ item.strinstallpos || '-' }}</div>
  46. <div class="content-item">
  47. <span>{{ item.readData.temperature || '-' }}</span>
  48. <span>℃</span>
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </template>
  57. <script setup lang="ts">
  58. import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
  59. import { managesysList, monitorSystem } from '../hsqHome.api.js'
  60. let active = ref(0)
  61. /** 响应式数据:当前场景/系统的唯一标识ID,用于API请求参数 */
  62. const systemId = ref('')
  63. /** 响应式数据:设备列表总数,显示在标题栏中 */
  64. const count = ref(0)
  65. /** 响应式数据:搜索框的绑定值,用于按设备编号、名称过滤 */
  66. const searchData = ref('')
  67. /** 响应式数据:设备列表原始数据,存储从后端获取的所有设备信息 */
  68. const sourceList = ref<any[]>([])
  69. /** 根据搜索关键字过滤后的设备列表 */
  70. const filteredListData = computed(() => {
  71. const keyword = searchData.value.trim().toLowerCase()
  72. if (!keyword) {
  73. return sourceList.value
  74. }
  75. return sourceList.value.filter((item) => {
  76. const serno = String(item.strserno ?? '').toLowerCase()
  77. const name = String(item.strname ?? '').toLowerCase()
  78. return serno.includes(keyword) || name.includes(keyword)
  79. })
  80. })
  81. /** 响应式数据:当前激活的导航项索引,用于控制导航栏高亮状态 */
  82. const activeIndex = ref(0)
  83. /** 响应式数据:导航栏配置数组,定义可切换的设备类型分类 */
  84. const navList = ref<any[]>([
  85. { label: '光谱摄像机', value: '0' },
  86. ])
  87. /** 定义组件事件:向父组件传递details事件,用于通信选中设备的操作类型和数据 */
  88. const $emit = defineEmits(['details'])
  89. /** 定时器变量:用于存储定时获取数据的定时器ID,便于在组件卸载时清理 */
  90. let timer: null | NodeJS.Timeout = null;
  91. /**
  92. * 定时轮询获取监测数据的核心函数
  93. * 通过递归调用setTimeout实现每30秒自动刷新一次设备数据
  94. * 采用异步方式避免阻塞主线程,确保UI响应流畅
  95. *
  96. * @param flag - 可选参数,控制是否立即执行
  97. * - true(首次调用):立即执行,不等待延时
  98. * - false/undefined(后续调用):等待30秒后执行
  99. */
  100. async function getMonitor(flag?: boolean) {
  101. // 设置定时器:根据flag决定是否立即执行
  102. timer = setTimeout(async () => {
  103. // 调用数据获取接口,await确保数据加载完成后再继续
  104. await getData()
  105. // 清空定时器引用,防止内存泄漏
  106. if (timer) {
  107. timer = null;
  108. }
  109. // 递归调用自身,形成定时轮询机制
  110. getMonitor();
  111. }, flag ? 0 : 10000); // 首次立即执行,之后每隔30秒执行一次
  112. }
  113. /**
  114. * 导航栏切换处理函数
  115. * 当用户点击不同的设备类型标签时触发,更新当前激活的导航索引
  116. * (当前实现仅更新UI状态,未实现实际的数据筛选逻辑)
  117. *
  118. * @param item - 被点击的导航项对象,包含label和value属性
  119. * @param index - 被点击导航项在navList数组中的索引位置
  120. */
  121. function changeNav(item: any, index: number) {
  122. // 更新激活状态索引,触发导航栏样式重新渲染
  123. activeIndex.value = index
  124. }
  125. /**
  126. * 设备操作按钮点击事件处理函数
  127. * 统一处理详情、配置、重启三种操作按钮的点击事件
  128. * 将操作类型和设备数据封装成事件对象传递给父组件
  129. *
  130. * @param type - 操作类型字符串
  131. * - 'detail': 查看设备详细信息
  132. * - 'config': 查看或修改设备配置
  133. * - 'restart': 执行设备重启操作
  134. * @param item - 被操作的目标设备完整数据对象
  135. */
  136. function handlerClick(type: string, item: any, index: number) {
  137. // 触发details事件,将操作类型和设备数据传递给父组件(deviceManger.vue)
  138. $emit('details', { type: type, value: item })
  139. active.value = index
  140. }
  141. /**
  142. * 异步获取设备监控数据的API调用函数
  143. * 向后端请求指定系统的所有光谱摄像机设备信息
  144. * 成功后将设备列表数据和数量分别赋值给对应的响应式变量
  145. */
  146. async function getData() {
  147. // 调用监控系统API,传入查询参数:
  148. // - type: 'all' 表示获取全部设备
  149. // - systemId: 当前系统ID(从getManagesysList获取)
  150. // - devicetype: '' 空字符串表示不限制设备类型
  151. const res = await monitorSystem({ type: 'all', systemID: systemId.value, devicetype: '' });
  152. // 控制台输出调试信息,便于开发阶段排查问题
  153. console.log(res, '设备列表数据')
  154. // 提取光谱摄像机设备列表数据,使用空数组作为默认值防止undefined错误
  155. sourceList.value = res.deviceInfo.duaSpeCamera.datalist || [];
  156. // 统计并记录设备总数量,用于标题栏显示
  157. count.value = sourceList.value.length;
  158. // 初始化时,默认选中第一个设备
  159. if (sourceList.value.length > 0) {
  160. active.value = 0
  161. handlerClick('detail', sourceList.value[0], 0)
  162. }
  163. }
  164. /** 搜索条件变化时重置选中项,避免索引越界 */
  165. watch(searchData, () => {
  166. active.value = 0
  167. })
  168. /**
  169. * 异步获取管理系统列表的初始化函数
  170. * 在组件挂载时首先调用此函数,获取当前用户有权限访问的系统列表
  171. * 从返回结果中提取第一个系统的ID作为后续数据查询的基础参数
  172. *
  173. * API参数说明:
  174. * - strtype: 'sys_openair_fire' 系统类型标识(开放空间火灾监测)
  175. * - pagetype: 'normal' 页面类型(普通页面模式)
  176. */
  177. async function getManagesysList() {
  178. // 调用管理系统列表API,传入系统类型和页面类型参数
  179. const res = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' });
  180. // 安全检查:确保返回数据存在且包含records数组
  181. if (res && res.records) {
  182. // 取第一个系统的ID作为当前工作系统ID(通常用户只关注一个主要系统)
  183. systemId.value = res.records[0].id
  184. }
  185. }
  186. /**
  187. * 组件挂载完成后的生命周期钩子
  188. * 执行组件初始化流程:
  189. * 1. 先获取系统ID(必须先于数据获取,因为systemId是getData的必要参数)
  190. * 2. 然后启动定时数据刷新机制(传true表示首次立即执行)
  191. */
  192. onMounted(async () => {
  193. // 等待系统ID获取完成,确保后续API调用有正确的参数
  194. await getManagesysList()
  195. // 启动定时监控,true表示首次立即执行一次
  196. getMonitor(true)
  197. })
  198. /**
  199. * 组件卸载前的生命周期钩子
  200. * 执行资源清理工作,主要是清除定时器以防止内存泄漏
  201. * 如果不清除,即使组件已销毁,定时器仍会继续运行并尝试更新已不存在的响应式数据
  202. */
  203. onUnmounted(() => {
  204. // 检查定时器是否存在,存在则清除
  205. if (timer) {
  206. clearTimeout(timer)
  207. }
  208. })
  209. </script>
  210. <!-- 样式部分:使用Less预处理器,scoped限制样式作用域仅作用于当前组件 -->
  211. <style lang="less" scoped>
  212. // 导入全局主题配置文件,包含颜色变量、主题切换等样式定义
  213. @import '/@/design/theme.less';
  214. /* 深蓝主题模式下的设备列表样式覆盖(预留扩展) */
  215. @{theme-deepblue} {
  216. .long-list {}
  217. }
  218. /* 设备列表主容器:左侧面板的根元素 */
  219. .long-list {
  220. /* ==================== CSS自定义属性:背景图片资源定义 ==================== */
  221. /* 列表标题栏背景图 */
  222. --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
  223. /* 搜索输入框背景图 */
  224. --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
  225. /* (预留)其他UI元素背景图 */
  226. --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-2.png');
  227. /* 设备卡片背景图 */
  228. --image-box-bg3: url('@/assets/images/home-container/configurable/hsq/2-7.png');
  229. /* 状态指示器外框背景图 */
  230. --image-box-bg4: url('@/assets/images/home-container/configurable/hsq/2-8.png');
  231. /* 设备标题区域背景图 */
  232. --image-box-bg5: url('@/assets/images/home-container/configurable/hsq/2-9.png');
  233. /* 基础布局样式 */
  234. position: relative;
  235. /* 相对定位:作为内部绝对定位元素的参考容器 */
  236. width: 100%;
  237. /* 宽度撑满父容器(由deviceManger.vue的430px宽度约束) */
  238. height: 100%;
  239. /* 高度撑满父容器 */
  240. padding: 15px;
  241. /* 内边距:内容与容器边缘保持15px间距 */
  242. box-sizing: border-box;
  243. /* 盒模型:padding计入总宽高,避免溢出 */
  244. /* ========== 标题栏样式:显示"设备列表"文字和数量 ========== */
  245. .list-title {
  246. width: 177px;
  247. /* 固定宽度:匹配背景图尺寸 */
  248. height: 30px;
  249. /* 固定高度 */
  250. line-height: 22px;
  251. /* 行高:垂直居中文字 */
  252. padding-left: 16px;
  253. /* 左内边距:文字缩进 */
  254. color: #01fefc;
  255. /* 青色字体:科技感配色方案 */
  256. font-weight: bolder;
  257. /* 加粗字体:突出标题重要性 */
  258. background: var(--image-box-bg) no-repeat;
  259. /* 使用标题背景图,不重复平铺 */
  260. background-size: 100% 100%;
  261. /* 背景图完全填充容器 */
  262. margin-bottom: 5px;
  263. /* 底部间距:与下方内容区分离 */
  264. }
  265. /* ========== 内容区主容器:包含搜索框、导航和列表 ========== */
  266. .list-content {
  267. width: 100%;
  268. /* 宽度撑满 */
  269. height: calc(100% - 35px);
  270. /* 高度计算:总高度减去标题栏高度和间距 */
  271. }
  272. /* 搜索框容器 */
  273. .list-search {
  274. margin-bottom: 5px;
  275. /* 底部间距:与导航栏分离 */
  276. }
  277. /* 内容容器:包含导航栏和设备列表 */
  278. .content-container {
  279. width: 100%;
  280. /* 宽度撑满 */
  281. height: calc(100% - 47px);
  282. /* 高度计算:减去搜索框高度和间距 */
  283. }
  284. /* ========== 导航栏样式:设备类型分类标签栏 ========== */
  285. .content-nav {
  286. display: flex;
  287. /* 弹性布局:导航项水平排列 */
  288. align-items: center;
  289. /* 垂直居中对齐 */
  290. height: 32px;
  291. /* 固定高度 */
  292. margin: 0px 5px 10px 5px;
  293. /* 外边距:上下左右各留间距 */
  294. background-color: #15517b;
  295. /* 深蓝色背景:与整体风格统一 */
  296. }
  297. /* 导航项默认状态(未激活) */
  298. .nav-item {
  299. display: flex;
  300. /* 弹性布局 */
  301. justify-content: center;
  302. /* 水平居中 */
  303. align-items: center;
  304. /* 垂直居中 */
  305. width: 120px;
  306. /* 固定宽度:每个标签等宽 */
  307. height: 100%;
  308. /* 高度撑满父容器 */
  309. cursor: pointer;
  310. /* 鼠标指针:提示可点击交互 */
  311. }
  312. /* 导航项激活状态(当前选中) */
  313. .nav-item-active {
  314. display: flex;
  315. justify-content: center;
  316. align-items: center;
  317. width: 120px;
  318. height: 100%;
  319. cursor: pointer;
  320. background-color: #1d73a8;
  321. /* 较亮的蓝色背景:视觉上区分选中状态 */
  322. border-bottom: 2px solid #36c7ff;
  323. /* 底部亮蓝色边框:强化选中指示效果 */
  324. }
  325. /* ========== 设备列表滚动容器 ========== */
  326. .content-box {
  327. height: calc(100% - 42px);
  328. /* 高度计算:减去导航栏高度和间距 */
  329. overflow-y: auto;
  330. /* 垂直方向超出时显示滚动条 */
  331. }
  332. /* ========== 单个设备卡片样式 ========== */
  333. .basic-device {
  334. position: relative;
  335. /* 相对定位:作为内部绝对定位元素的参考 */
  336. height: 106px;
  337. /* 固定高度:每个卡片统一尺寸 */
  338. margin-right: 5px;
  339. /* 右侧间距 */
  340. background: var(--image-box-bg3) no-repeat;
  341. /* 设备卡片背景图 */
  342. background-size: 100% 100%;
  343. margin-bottom: 10px;
  344. /* 卡片之间的垂直间距 */
  345. /* 左上角状态指示器外框容器 */
  346. .icon-left {
  347. position: absolute;
  348. /* 绝对定位:相对于卡片容器 */
  349. left: 0;
  350. /* 紧贴左边缘 */
  351. top: 0;
  352. /* 紧贴顶部边缘 */
  353. width: 29px;
  354. /* 外框尺寸 */
  355. height: 29px;
  356. background: var(--image-box-bg4) no-repeat;
  357. /* 外框装饰背景图 */
  358. background-size: 100% 100%;
  359. }
  360. /* 正常状态圆点(绿色):表示设备运行正常 */
  361. .icon-item {
  362. position: absolute;
  363. /* 绝对定位:相对于.icon-left容器 */
  364. left: 50%;
  365. /* 水平居中 */
  366. top: 50%;
  367. /* 垂直居中 */
  368. transform: translate(-50%, -50%);
  369. /* 偏移自身宽高的50%实现完全居中 */
  370. width: 10px;
  371. /* 圆点直径 */
  372. height: 10px;
  373. border-radius: 50%;
  374. /* 圆形:border-radius设为50%形成正圆 */
  375. background-color: #4fffad;
  376. /* 荧光绿:正常状态的视觉暗示 */
  377. }
  378. /* 报警状态圆点(红色):表示设备存在告警 */
  379. .icon-item-warn {
  380. position: absolute;
  381. left: 50%;
  382. top: 50%;
  383. transform: translate(-50%, -50%);
  384. width: 10px;
  385. height: 10px;
  386. border-radius: 50%;
  387. background-color: #ff4d4f;
  388. /* 警示红:报警状态的强烈视觉提醒 */
  389. }
  390. /* 设备标题行:显示序列号和操作按钮 */
  391. .basic-title {
  392. height: 30px;
  393. /* 固定高度 */
  394. margin: 0px 20px 5px 32px;
  395. /* 外边距:避开左侧图标区域 */
  396. padding-left: 10px;
  397. /* 左内边距:文字缩进 */
  398. display: flex;
  399. /* 弹性布局:序列号和按钮组两端对齐 */
  400. justify-content: space-between;
  401. /* 两端对齐:序列号靠左,按钮靠右 */
  402. align-items: center;
  403. /* 垂直居中 */
  404. background: var(--image-box-bg5) no-repeat bottom;
  405. /* 标题行底部装饰线 */
  406. background-size: 100% auto;
  407. }
  408. /* 操作按钮组容器 */
  409. .title-btn {
  410. height: 100%;
  411. /* 高度撑满父容器 */
  412. display: flex;
  413. /* 弹性布局:按钮水平排列 */
  414. align-items: center;
  415. /* 垂直居中 */
  416. }
  417. /* 单个操作按钮样式(详情/配置/重启共用) */
  418. .btn {
  419. width: 40px;
  420. /* 固定宽度 */
  421. display: flex;
  422. /* 弹性布局 */
  423. justify-content: center;
  424. /* 文字水平居中 */
  425. align-items: center;
  426. /* 文字垂直居中 */
  427. background-color: #1e7db4;
  428. /* 深蓝色按钮背景 */
  429. margin: 0px 2px;
  430. /* 按钮之间的水平间距 */
  431. cursor: pointer;
  432. /* 鼠标指针:提示可点击 */
  433. }
  434. .btn-active {
  435. width: 40px;
  436. /* 固定宽度 */
  437. display: flex;
  438. /* 弹性布局 */
  439. justify-content: center;
  440. /* 文字水平居中 */
  441. align-items: center;
  442. /* 文字垂直居中 */
  443. margin: 0px 2px;
  444. /* 按钮之间的水平间距 */
  445. cursor: pointer;
  446. background-color: #1e7db4;
  447. /* 深蓝色按钮背景 */
  448. border: 1px solid #90cff3;
  449. }
  450. /* 设备详细信息区域:2x2网格布局展示四项关键数据 */
  451. .basic-content {
  452. display: flex;
  453. /* 弹性布局 */
  454. flex-wrap: wrap;
  455. /* 允许换行:实现网格布局 */
  456. height: calc(100% - 30px);
  457. /* 高度计算:卡片总高度减去标题行高度 */
  458. padding-left: 20px;
  459. /* 左内边距:与左侧图标对齐 */
  460. padding-bottom: 10px;
  461. /* 底部内边距:防止内容贴底 */
  462. }
  463. /* 单个信息项:网格中的单元格 */
  464. .content-item {
  465. display: flex;
  466. /* 弹性布局 */
  467. align-items: center;
  468. /* 垂直居中对齐 */
  469. width: 50%;
  470. /* 宽度占一半:每行显示两个项目 */
  471. height: calc(50% - 10px);
  472. /* 高度占一半减去margin:两行布局 */
  473. margin: 5px 0px;
  474. /* 垂直间距:行与行之间分隔 */
  475. padding-left: 15px;
  476. /* 左内边距:文字缩进效果 */
  477. /* 第一个单元格(设备名称):深蓝色渐变背景 */
  478. &:nth-child(1) {
  479. background: linear-gradient(to right, #0e5183, transparent);
  480. /* 从左到右渐变至透明 */
  481. }
  482. /* 第二个单元格(运行状态):稍浅的蓝色渐变 */
  483. &:nth-child(2) {
  484. background: linear-gradient(to right, #104974, transparent);
  485. /* 与第一行形成层次感 */
  486. }
  487. /* 第三个单元格(安装位置):同第一行的深色调 */
  488. &:nth-child(3) {
  489. background: linear-gradient(to right, #0e5183, transparent);
  490. /* 保持奇偶行交替效果 */
  491. }
  492. /* 第四个单元格(温度数据):同第二行的浅色调 */
  493. &:nth-child(4) {
  494. background: linear-gradient(to right, #104974, transparent);
  495. }
  496. }
  497. /* 状态指示图标(正常状态的圆形标记) */
  498. .icon-pie {
  499. display: inline-block;
  500. /* 行内块级元素:与文字同行显示 */
  501. position: relative;
  502. /* 相对定位:作为内部绝对定位元素的参考 */
  503. width: 12px;
  504. /* 外圈直径 */
  505. height: 12px;
  506. border-radius: 50%;
  507. /* 圆形 */
  508. background-color: rgba(79, 255, 173, .3);
  509. /* 半透明绿色:柔和的外圈效果 */
  510. margin-right: 5px;
  511. /* 右侧间距:与文字分离 */
  512. }
  513. /* 状态指示图标的内圈实心点 */
  514. .pie-item {
  515. position: absolute;
  516. /* 绝对定位:相对于.icon-pie容器 */
  517. left: 50%;
  518. /* 水平居中 */
  519. top: 50%;
  520. /* 垂直居中 */
  521. transform: translate(-50%, -50%);
  522. /* 居中偏移 */
  523. width: 6px;
  524. /* 内圈直径:比外圈小,形成环形效果 */
  525. height: 6px;
  526. border-radius: 50%;
  527. /* 圆形 */
  528. background-color: rgba(79, 255, 173);
  529. /* 实心荧光绿:清晰的中心点 */
  530. }
  531. .pie-item-warn {
  532. position: absolute;
  533. /* 绝对定位:相对于.icon-pie容器 */
  534. left: 50%;
  535. /* 水平居中 */
  536. top: 50%;
  537. /* 垂直居中 */
  538. transform: translate(-50%, -50%);
  539. /* 居中偏移 */
  540. width: 6px;
  541. /* 内圈直径:比外圈小,形成环形效果 */
  542. height: 6px;
  543. border-radius: 50%;
  544. /* 圆形 */
  545. background-color: #ff4d4f;
  546. /* 实心荧光绿:清晰的中心点 */
  547. }
  548. }
  549. /* 自定义搜索框样式(覆盖Ant Design默认样式) */
  550. .zxm-input {
  551. height: 42px;
  552. /* 固定高度 */
  553. color: #fff;
  554. /* 白色文字:在深色背景上清晰可见 */
  555. background-color: transparent;
  556. /* 透明背景:使用自定义背景图 */
  557. border: none;
  558. /* 移除默认边框 */
  559. background: var(--image-box-bg1) no-repeat;
  560. /* 搜索框专用背景图 */
  561. background-size: 100% 100%;
  562. }
  563. /* 小号输入框变体 */
  564. .zxm-input-sm {
  565. padding: 0px 20px;
  566. /* 左右内边距:文字不紧贴边缘 */
  567. }
  568. /* 隐藏原生滚动条:使用自定义滚动体验或完全隐藏 */
  569. ::-webkit-scrollbar {
  570. display: none;
  571. /* 隐藏WebKit内核浏览器的滚动条 */
  572. }
  573. }
  574. </style>