index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. <template>
  2. <div class="radarEditor" :class="{ disabled: props.disabled }">
  3. <DetectionAreaView
  4. :coordinates="coordinates"
  5. :direction="angle"
  6. :furniture-items="localFurniture"
  7. :canvas-size="500"
  8. mode="edit"
  9. >
  10. <template #furnitures>
  11. <EditableFurniture
  12. v-for="item in localFurniture"
  13. :key="item.nanoid"
  14. :item="item"
  15. :angle="angle"
  16. :coordinates="coordinates"
  17. :canvas-size="400"
  18. :disabled="disabled"
  19. @update="updateFurniture"
  20. @delete="deleteFurniture"
  21. />
  22. </template>
  23. <template #subregion>
  24. <EditableSubregion
  25. ref="editableSubregionRef"
  26. :ranges="coordinates"
  27. :angle="angle"
  28. :canvas-size="400"
  29. :subRegions="localSubRegions"
  30. :editable="!disabled"
  31. :has-bed="localFurniture.some((item) => item.type === 'bed')"
  32. @create="handleSubregionCreate"
  33. @update="handleSubregionUpdate"
  34. />
  35. </template>
  36. </DetectionAreaView>
  37. <div v-if="!disabled && showPanel" class="options">
  38. <div class="close" @click="showPanel = false">×</div>
  39. <div class="header">
  40. <a-radio-group
  41. v-model:value="modeRadio"
  42. button-style="solid"
  43. size="small"
  44. @change="modeRadioChange"
  45. >
  46. <a-radio-button :value="1">配置面板</a-radio-button>
  47. <a-radio-button :value="2">信息面板</a-radio-button>
  48. </a-radio-group>
  49. <a-button type="link" size="small" @click="syncCoordinates">同步坐标</a-button>
  50. </div>
  51. <div v-if="modeRadio === 1" class="config">
  52. <div class="panel">
  53. <div class="panel-hd">家具操作</div>
  54. <div class="panel-ct">
  55. <div class="furnitureTool">
  56. <a-radio-group v-model:value="sideRadio" size="small">
  57. <a-radio :style="radioStyle" :value="1">客厅</a-radio>
  58. <a-radio :style="radioStyle" :value="2">餐厅</a-radio>
  59. <a-radio :style="radioStyle" :value="3">卧室</a-radio>
  60. <a-radio :style="radioStyle" :value="4">卫生间</a-radio>
  61. </a-radio-group>
  62. <furniture-list
  63. v-if="sideRadio === 1"
  64. :icons="livingroomIcons"
  65. @add="add"
  66. ></furniture-list>
  67. <furniture-list
  68. v-if="sideRadio === 2"
  69. :icons="diningroomIcons"
  70. @add="add"
  71. ></furniture-list>
  72. <furniture-list
  73. v-if="sideRadio === 3"
  74. :icons="bedroomIocns"
  75. @add="add"
  76. ></furniture-list>
  77. <furniture-list
  78. v-if="sideRadio === 4"
  79. :icons="bathroomIocns"
  80. @add="add"
  81. ></furniture-list>
  82. </div>
  83. </div>
  84. <div class="panel-hd">区域操作</div>
  85. <div class="panel-ct">
  86. <div class="subregionTool">
  87. <div v-if="localSubRegions.length === 0">
  88. 暂无区域,<a-button type="link" size="small" @click="createSubregion"
  89. >新建区域</a-button
  90. >
  91. </div>
  92. <div v-else>
  93. <span>已创建 {{ localSubRegions.length }} 个区域</span>
  94. <a-button
  95. v-if="localSubRegions.length < 6"
  96. type="link"
  97. size="small"
  98. @click="createSubregion"
  99. >继续创建</a-button
  100. >
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <div v-if="modeRadio === 2" class="info">
  107. <div class="panel">
  108. <div class="panel-hd">
  109. <div
  110. >家具列表 <span v-if="localFurniture.length">({{ localFurniture.length }})</span></div
  111. >
  112. <a-space>
  113. <a-popconfirm
  114. v-if="localFurniture.length"
  115. title="确定清空家具吗?"
  116. @confirm="clearFurniture"
  117. >
  118. <a-button size="small" type="link">清空</a-button>
  119. </a-popconfirm>
  120. <a-button size="small" type="link" @click="modeRadio = 1">添加</a-button>
  121. </a-space>
  122. </div>
  123. <div class="panel-ct">
  124. <template v-if="localFurniture.length">
  125. <div v-for="(furniture, index) in localFurniture" :key="index" class="list-item">
  126. <a-collapse v-model:activeKey="furnitureActiveKey" ghost>
  127. <a-collapse-panel :key="index + 1" :header="`${furniture.name} 属性`">
  128. <div class="mapConfig">
  129. <div class="mapConfig-item">
  130. <label class="mapConfig-item-label">家具尺寸:</label>
  131. <div class="mapConfig-item-content">
  132. <a-space>
  133. <a-input-number
  134. v-model:value="furniture.width"
  135. :min="10"
  136. size="small"
  137. :style="inputStyle"
  138. />
  139. <a-input-number
  140. v-model:value="furniture.length"
  141. :min="10"
  142. size="small"
  143. :style="inputStyle"
  144. />
  145. </a-space>
  146. </div>
  147. </div>
  148. <div class="mapConfig-item">
  149. <label class="mapConfig-item-label">家具旋转:</label>
  150. <div class="mapConfig-item-content">
  151. <a-select
  152. v-model:value="furniture.rotate"
  153. size="small"
  154. :style="inputStyle"
  155. >
  156. <a-select-option :value="0">0°</a-select-option>
  157. <a-select-option :value="90">90°</a-select-option>
  158. <a-select-option :value="180">180°</a-select-option>
  159. <a-select-option :value="270">270°</a-select-option>
  160. </a-select>
  161. </div>
  162. </div>
  163. <div class="mapConfig-item">
  164. <label class="mapConfig-item-label">位置微调:</label>
  165. <div class="mapConfig-item-content"></div>
  166. <a-space>
  167. <ArrowLeftOutlined @click="nudge('left')" />
  168. <ArrowUpOutlined @click="nudge('up')" />
  169. <ArrowDownOutlined @click="nudge('down')" />
  170. <ArrowRightOutlined @click="nudge('right')" />
  171. <a-input-number
  172. v-model:value="nudgeStep"
  173. :min="1"
  174. size="small"
  175. style="width: 60px"
  176. />
  177. </a-space>
  178. </div>
  179. <div class="mapConfig-item">
  180. <label class="mapConfig-item-label">left/top:</label>
  181. <div class="mapConfig-item-content">
  182. <a-space>
  183. <a-input-number
  184. v-model:value="furniture.left"
  185. disabled
  186. size="small"
  187. :style="inputStyle"
  188. />
  189. <a-input-number
  190. v-model:value="furniture.top"
  191. disabled
  192. size="small"
  193. :style="inputStyle"
  194. />
  195. </a-space>
  196. </div>
  197. </div>
  198. <div class="mapConfig-item">
  199. <label class="mapConfig-item-label">x/y:</label>
  200. <div class="mapConfig-item-content">
  201. <a-space>
  202. <a-input-number
  203. v-model:value="furniture.x"
  204. size="small"
  205. :style="inputStyle"
  206. />
  207. <a-input-number
  208. v-model:value="furniture.y"
  209. size="small"
  210. :style="inputStyle"
  211. />
  212. </a-space>
  213. </div>
  214. </div>
  215. <div class="mapConfig-item">
  216. <label class="mapConfig-item-label">操作:</label>
  217. <div class="mapConfig-item-content">
  218. <a-space>
  219. <a-popconfirm
  220. title="确定删除家具吗?"
  221. @confirm="deleteFurniture(furniture.nanoid!)"
  222. >
  223. <DeleteOutlined />
  224. </a-popconfirm>
  225. </a-space>
  226. </div>
  227. </div>
  228. </div>
  229. </a-collapse-panel>
  230. </a-collapse>
  231. </div>
  232. </template>
  233. <div v-else class="list-empty">暂无家具</div>
  234. </div>
  235. </div>
  236. <div class="panel">
  237. <div class="panel-hd">
  238. <div
  239. >区域列表
  240. <span v-if="localSubRegions.length">({{ localSubRegions.length }})</span></div
  241. >
  242. <a-space>
  243. <a-popconfirm
  244. v-if="localSubRegions.length"
  245. title="确定清空子区域吗?"
  246. @confirm="clearSubregions"
  247. >
  248. <a-button size="small" type="link">清空</a-button>
  249. </a-popconfirm>
  250. <a-button size="small" type="link" @click="createSubregion">新建</a-button>
  251. </a-space>
  252. </div>
  253. <div class="panel-ct">
  254. <template v-if="localSubRegions.length">
  255. <div v-for="(region, index) in localSubRegions" :key="index" class="list-item">
  256. <a-collapse v-model:activeKey="regionActiveKey" ghost>
  257. <a-collapse-panel :key="index + 1" :header="`子区域 ${index + 1} 属性`">
  258. <div class="mapConfig">
  259. <div class="mapConfig-item">
  260. <div class="mapConfig-item-label">X范围:</div>
  261. <div class="mapConfig-item-content">
  262. <a-space>
  263. <a-input
  264. v-model:value.trim="region.startXx"
  265. :style="inputStyle"
  266. size="small"
  267. />
  268. <a-input
  269. v-model:value.trim="region.stopXx"
  270. :style="inputStyle"
  271. size="small"
  272. />
  273. </a-space>
  274. </div>
  275. </div>
  276. <div class="mapConfig-item">
  277. <div class="mapConfig-item-label">Y范围:</div>
  278. <div class="mapConfig-item-content">
  279. <a-space>
  280. <a-input
  281. v-model:value.trim="region.startYy"
  282. :style="inputStyle"
  283. size="small"
  284. />
  285. <a-input
  286. v-model:value.trim="region.stopYy"
  287. :style="inputStyle"
  288. size="small"
  289. />
  290. </a-space>
  291. </div>
  292. </div>
  293. <div class="mapConfig-item">
  294. <div class="mapConfig-item-label">Z范围:</div>
  295. <div class="mapConfig-item-content">
  296. <a-space>
  297. <a-input
  298. v-model:value.trim="region.startZz"
  299. :style="inputStyle"
  300. size="small"
  301. />
  302. <a-input
  303. v-model:value.trim="region.stopZz"
  304. :style="inputStyle"
  305. size="small"
  306. />
  307. </a-space>
  308. </div>
  309. </div>
  310. <div class="mapConfig-item">
  311. <div class="mapConfig-item-label">区域跟踪:</div>
  312. <div class="mapConfig-item-content">
  313. <a-switch v-model:checked="region.isTracking" size="small" />
  314. </div>
  315. </div>
  316. <div class="mapConfig-item">
  317. <div class="mapConfig-item-label">区域跌倒:</div>
  318. <div class="mapConfig-item-content">
  319. <a-switch v-model:checked="region.isFalling" size="small" />
  320. </div>
  321. </div>
  322. <div v-if="region.isBed" class="mapConfig-item">
  323. <div class="mapConfig-item-label">呼吸检测:</div>
  324. <div class="mapConfig-item-content"> 默认开启 </div>
  325. </div>
  326. <div class="mapConfig-item">
  327. <div class="mapConfig-item-label">删除区域:</div>
  328. <div class="mapConfig-item-content">
  329. <a-popconfirm
  330. title="确定删除区域吗?"
  331. @confirm="deleteBlockArea(region.id || '')"
  332. >
  333. <DeleteOutlined />
  334. </a-popconfirm>
  335. </div>
  336. </div>
  337. </div>
  338. </a-collapse-panel>
  339. </a-collapse>
  340. </div>
  341. </template>
  342. <div v-else class="list-empty">暂无子区域</div>
  343. </div>
  344. </div>
  345. </div>
  346. </div>
  347. <a-button v-else type="link" @click="showPanel = true">开始配置</a-button>
  348. </div>
  349. </template>
  350. <script setup lang="ts">
  351. import { ref, watch, computed, onUnmounted, reactive } from 'vue'
  352. // import type { FurnitureItem } from '@/types/radar'
  353. import DetectionAreaView from '../DetectionAreaView/index.vue'
  354. import EditableFurniture from '../EditableFurniture/index.vue'
  355. import EditableSubregion from '../EditableSubregion/index.vue'
  356. import type { FurnitureIconType } from '@/types/furniture'
  357. import { message } from 'ant-design-vue'
  358. import { nanoid } from 'nanoid'
  359. import { furnitureIconNameMap, furnitureIconSizeMap } from '@/const/furniture'
  360. import type {
  361. FurnitureItem,
  362. LocalFurnitureItem,
  363. LocalSubRegionItem,
  364. SubRegions,
  365. } from '@/api/room/types'
  366. import {
  367. DeleteOutlined,
  368. ArrowLeftOutlined,
  369. ArrowUpOutlined,
  370. ArrowDownOutlined,
  371. ArrowRightOutlined,
  372. } from '@ant-design/icons-vue'
  373. defineOptions({ name: 'RadarEditor' })
  374. interface Props {
  375. coordinates: [number, number, number, number]
  376. angle: number
  377. furnitureItems?: LocalFurnitureItem[]
  378. subRegions?: LocalSubRegionItem[]
  379. disabled?: boolean
  380. }
  381. const props = defineProps<Props>()
  382. const emit = defineEmits<{
  383. (e: 'update:furnitureItems', items: FurnitureItem[]): void
  384. (e: 'update:subRegions', regions: SubRegions[]): void
  385. }>()
  386. const localFurniture = ref<FurnitureItem[]>(props.furnitureItems ?? [])
  387. const localSubRegions = ref<SubRegions[]>(props.subRegions ?? [])
  388. console.log('props', props)
  389. const inputStyle = computed(() => ({ width: '70px' }))
  390. const pixelPosition = reactive({ left: 0, top: 0 })
  391. const nudgeStep = ref(5)
  392. // 微调功能
  393. const nudge = (direction: 'left' | 'right' | 'up' | 'down') => {
  394. const step = nudgeStep.value
  395. switch (direction) {
  396. case 'left':
  397. pixelPosition.left -= step
  398. break
  399. case 'right':
  400. pixelPosition.left += step
  401. break
  402. case 'up':
  403. pixelPosition.top -= step
  404. break
  405. case 'down':
  406. pixelPosition.top += step
  407. break
  408. }
  409. // updateGeoPosition()
  410. // emit('update', { ...localItem })
  411. }
  412. watch(
  413. () => props.furnitureItems,
  414. (newVal) => {
  415. if (newVal) localFurniture.value = [...newVal]
  416. },
  417. { deep: true }
  418. )
  419. watch(
  420. () => props.subRegions,
  421. (newVal) => {
  422. if (newVal) localSubRegions.value = [...newVal]
  423. },
  424. { deep: true }
  425. )
  426. // 监听本地子区域变化,通知父组件
  427. watch(
  428. localSubRegions,
  429. (newRegions) => {
  430. // emit('update:subRegions', newRegions)
  431. console.log('子区域变化', newRegions)
  432. // 缓存起来
  433. localStorage.setItem('subRegions', JSON.stringify(newRegions))
  434. },
  435. { deep: true }
  436. )
  437. function updateFurniture(item: FurnitureItem) {
  438. localFurniture.value = localFurniture.value.map((i) => (i.nanoid === item.nanoid ? item : i))
  439. emit('update:furnitureItems', localFurniture.value)
  440. }
  441. function deleteFurniture(nanoid: string) {
  442. localFurniture.value = localFurniture.value.filter((i) => i.nanoid !== nanoid)
  443. emit('update:furnitureItems', localFurniture.value)
  444. }
  445. function addFurniture(item: FurnitureItem) {
  446. localFurniture.value.push(item)
  447. emit('update:furnitureItems', [...localFurniture.value])
  448. }
  449. defineExpose({ addFurniture })
  450. const modeRadio = ref<1 | 2 | 3>(1)
  451. const sideRadio = ref<1 | 2 | 3 | 4>(1)
  452. const editableSubregionRef = ref<InstanceType<typeof EditableSubregion>>()
  453. const radioStyle = reactive({
  454. display: 'flex',
  455. height: '30px',
  456. lineHeight: '30px',
  457. })
  458. // 客厅图标
  459. const livingroomIcons = [
  460. 'living_sofa',
  461. 'living_sofa_single',
  462. 'living_tea_table',
  463. 'living_bookcase',
  464. 'living_tv_stand',
  465. ]
  466. // 餐厅图标
  467. const diningroomIcons = [
  468. 'dining_table',
  469. 'dining_table_rect',
  470. 'dining_fridge',
  471. 'dining_chair',
  472. 'bath_door',
  473. ]
  474. // 卧室图标
  475. const bedroomIocns = [
  476. 'bed',
  477. 'bed_table',
  478. 'bed_dressing_chair',
  479. 'bed_dressing_mirror',
  480. 'bed_cabinet',
  481. ]
  482. // 卫生间图标
  483. const bathroomIocns = ['bath_basin', 'bath_shower', 'bath_toilet', 'bath_floor']
  484. // 添加家具
  485. const add = (icon: FurnitureIconType) => {
  486. const originWidth = furnitureIconSizeMap[icon].width || 30
  487. const originHeight = furnitureIconSizeMap[icon].height || 30
  488. const newItem: FurnitureItem = {
  489. name: furnitureIconNameMap[icon],
  490. type: icon,
  491. width: originWidth,
  492. length: originHeight,
  493. top: 0,
  494. left: 0,
  495. rotate: 0,
  496. x: 0,
  497. y: 0,
  498. nanoid: nanoid(),
  499. }
  500. addFurniture(newItem)
  501. message.success('已添加家具')
  502. }
  503. // 创建子区域
  504. const createSubregion = () => {
  505. // modeRadio.value = 2
  506. // 通过ref调用EditableSubregion组件的createNewBlock方法
  507. if (editableSubregionRef.value) {
  508. editableSubregionRef.value?.createNewBlock()
  509. }
  510. }
  511. // 处理子区域创建事件
  512. const handleSubregionCreate = () => {
  513. // message.success('已创建子区域')
  514. }
  515. // 处理子区域更新事件
  516. const handleSubregionUpdate = (item: SubRegions[]) => {
  517. // 可以在这里添加更新后的逻辑
  518. const hasBed = localFurniture.value.some((furniture) => furniture.type === 'bed')
  519. console.log('子区域更新', item, hasBed)
  520. if (hasBed) {
  521. localSubRegions.value = item.map((region, index) => ({
  522. ...region,
  523. isBed: index === 0,
  524. }))
  525. } else {
  526. localSubRegions.value = item
  527. }
  528. // emit('update:subRegions', item)
  529. }
  530. const showPanel = ref(true)
  531. onUnmounted(() => {
  532. // 组件销毁时清除缓存
  533. localStorage.removeItem('subRegions')
  534. })
  535. const regionActiveKey = ref<number[]>([])
  536. const furnitureActiveKey = ref<number[]>([])
  537. const deleteBlockArea = (id: string) => {
  538. if (id) {
  539. localSubRegions.value = localSubRegions.value.filter((item) => item.id !== id)
  540. }
  541. }
  542. const modeRadioChange = () => {
  543. regionActiveKey.value = []
  544. furnitureActiveKey.value = []
  545. }
  546. const syncCoordinates = () => {
  547. console.log('同步坐标', localFurniture.value, localSubRegions.value)
  548. }
  549. const clearSubregions = () => {
  550. localSubRegions.value = []
  551. }
  552. const clearFurniture = () => {
  553. localFurniture.value = []
  554. }
  555. </script>
  556. <style scoped lang="less">
  557. .radarEditor.disabled {
  558. cursor: no-drop;
  559. :deep(*) {
  560. pointer-events: none;
  561. user-select: none;
  562. opacity: 0.85;
  563. }
  564. }
  565. .radarEditor {
  566. position: relative;
  567. display: flex;
  568. gap: 8px;
  569. .radar-view {
  570. flex-shrink: 0;
  571. }
  572. .options {
  573. width: 280px;
  574. background-color: #fefefe;
  575. border-radius: 10px;
  576. padding: 12px;
  577. position: relative;
  578. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  579. .close {
  580. position: absolute;
  581. top: 8px;
  582. right: 12px;
  583. font-size: 22px;
  584. font-weight: 600;
  585. line-height: 1;
  586. color: #999;
  587. cursor: pointer;
  588. transition: color 0.2s;
  589. }
  590. .header {
  591. display: flex;
  592. align-items: center;
  593. margin-bottom: 12px;
  594. }
  595. }
  596. }
  597. .panel {
  598. margin-bottom: 12px;
  599. &-hd {
  600. font-size: 12px;
  601. font-weight: 600;
  602. color: #666;
  603. line-height: 1.5;
  604. padding: 5px 8px;
  605. display: flex;
  606. align-items: center;
  607. justify-content: space-between;
  608. .ant-btn-link {
  609. font-size: 12px;
  610. line-height: 1.5;
  611. padding: 0;
  612. }
  613. }
  614. &-ct {
  615. display: flex;
  616. flex-direction: column;
  617. gap: 8px;
  618. min-height: 30px;
  619. max-height: 300px;
  620. overflow-y: auto;
  621. // 滚动条不遮挡内容
  622. ::-webkit-scrollbar {
  623. width: 4px;
  624. height: 4px;
  625. }
  626. ::-webkit-scrollbar-track {
  627. background-color: transparent;
  628. }
  629. ::-webkit-scrollbar-thumb {
  630. background-color: rgba(0, 0, 0, 0.2);
  631. border-radius: 2px;
  632. }
  633. .furnitureTool {
  634. display: flex;
  635. justify-content: space-between;
  636. background-color: #f5f5f5;
  637. padding: 8px;
  638. border-radius: 8px;
  639. .furnitureList {
  640. flex-grow: 1;
  641. }
  642. }
  643. .subregionTool {
  644. display: flex;
  645. align-items: center;
  646. background-color: #f5f5f5;
  647. padding: 10px 12px;
  648. border-radius: 8px;
  649. font-size: 14px;
  650. color: #333;
  651. }
  652. }
  653. &:last-child {
  654. margin-bottom: 0;
  655. }
  656. .list-item {
  657. display: flex;
  658. align-items: center;
  659. justify-content: space-between;
  660. border-radius: 8px;
  661. background-color: #f5f5f5;
  662. cursor: pointer;
  663. }
  664. .list-empty {
  665. padding: 8px 12px;
  666. font-size: 14px;
  667. color: #999;
  668. border-radius: 8px;
  669. background-color: #f5f5f5;
  670. }
  671. }
  672. .mapConfig {
  673. background-color: #f5f5f5;
  674. border-radius: 10px;
  675. padding: 0 12px;
  676. &-header {
  677. margin-bottom: 10px;
  678. display: flex;
  679. justify-content: space-between;
  680. align-items: center;
  681. .title {
  682. font-size: 14px;
  683. font-weight: 600;
  684. line-height: 24px;
  685. }
  686. .close {
  687. font-size: 14px;
  688. color: #666;
  689. cursor: pointer;
  690. position: relative;
  691. top: -5px;
  692. }
  693. }
  694. &-item {
  695. display: flex;
  696. line-height: 30px;
  697. &-label {
  698. color: #888;
  699. min-width: 80px;
  700. }
  701. &-content {
  702. color: #555;
  703. }
  704. }
  705. }
  706. :deep(.ant-collapse) {
  707. width: 100%;
  708. }
  709. :deep(.ant-collapse .ant-collapse-content > .ant-collapse-content-box) {
  710. padding: 0;
  711. }
  712. :deep(.ant-collapse > .ant-collapse-item > .ant-collapse-header) {
  713. padding: 5px;
  714. user-select: none;
  715. }
  716. </style>