| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- <template>
- <div class="fire-safety-panel">
- <!-- 数据列表容器 -->
- <div class="sensor-list">
- <!-- 按钮 -->
- <div class="control-bar">
- <a-button class="control-btn" @click="handleSpary(true)">启动喷淋</a-button>
- <a-button class="control-btn" @click="handleSpary(false)">停止喷淋</a-button>
- <a-button class="control-btn">手动控制</a-button>
- <a-button class="control-btn">自动控制</a-button>
- </div>
- <!-- 循环渲染分组 -->
- <div v-for="(beltData, index) in data.beltData" :key="index" class="block-item">
- <!-- {{ beltData }} -->
- <!-- 这里应该由data渲染,因为data数量是动态不固定的,config.config是静态的 -->
- <div v-for="(group, index) in config.config" :key="index" class="sensor-group">
- <!-- 组标题 -->
- <div class="group-title">
- <a-checkbox
- class="check-btn"
- :checked="selectedSids.includes(beltData.sid)"
- @change="(e) => handleCheckChange(e.target.checked, beltData.sid)"
- >
- 控制勾选
- </a-checkbox>
- </div>
- <!-- 循环渲染组内项 -->
- <div v-for="(item, itemIndex) in group.contentTop" :key="itemIndex" class="sensor-item" :class="getBgClass(itemIndex)">
- <div class="item-icon" :class="getBgClass(itemIndex)"></div>
- <div class="item-status">
- <div class="item-label">{{ item.label }}</div>
- <div class="item-code">{{ getItemText(beltData, item) }}</div>
- </div>
- </div>
- <div class="container">
- <div v-for="(item, itemIndex) in group.contents" :key="itemIndex" class="dataInfo-item" :class="getBgClass(itemIndex)">
- <div class="item-status">
- <div class="item-label">{{ item.label }}</div>
- <div class="item-code">
- <span class="status-dot" v-if="item.trans" :class="getStatusClass(beltData, item)"> </span>
- {{ getItemText(beltData, item) }}
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { computed, onMounted, ref } from 'vue';
- import { getFormattedText } from '../../hooks/helper';
- const props = defineProps<{
- config: Array<{
- readFrom: string;
- contentTop: Array<{
- label: string;
- code: string;
- status?: string;
- info?: string;
- }>;
- contents: Array<{
- label: string;
- code: string;
- trans?: any;
- }>;
- }>;
- data: {
- [key: string]: any;
- };
- }>();
- // --- 存储选中的 sid ---
- const selectedSids = ref<string[]>([]);
- // --- 处理勾选变化 ---
- const handleCheckChange = (checked: boolean, sid: string) => {
- if (checked) {
- // 勾选:如果不存在则加入数组
- if (!selectedSids.value.includes(sid)) {
- selectedSids.value.push(sid);
- }
- } else {
- // 取消勾选:从数组中移除
- const index = selectedSids.value.indexOf(sid);
- if (index > -1) {
- selectedSids.value.splice(index, 1);
- }
- }
- console.log('当前选中的 SID 列表:', selectedSids.value);
- };
- const getBgClass = (index) => {
- return index % 2 === 0 ? 'bg-1' : 'bg-2';
- };
- /**
- * 根据配置项从当前皮带数据中获取对应的值
- * @param currentItem 当前循环到的单条皮带数据 (beltData)
- * @param configItem 配置项 (包含 code 和 trans)
- */
- const getItemText = (currentItem: any, configItem: { code: string; trans?: any }) => {
- // 1. 获取原始值: 通过 code 字段从 currentItem 中取值
- const rawValue = currentItem[configItem.code];
- // 2. 如果有翻译映射 (trans),则进行翻译
- if (configItem.trans && configItem.trans[rawValue] !== undefined) {
- return configItem.trans[rawValue];
- }
- // 3. 没有翻译则直接返回原始值
- return rawValue;
- };
- const handleSpary = (state: boolean) => {
- if (state) {
- console.log('启动喷淋');
- } else {
- console.log('停止喷淋');
- }
- };
- const getStatusClass = (beltData: any, item: any) => {
- const val = getItemText(beltData, item);
- // 根据翻译后的值判断颜色(连接=绿,断开=红)
- if (val === '正常') return 'status-normal';
- if (val === '断开') return 'status-danger';
- return '';
- };
- onMounted(() => {
- console.log(props.config, '123');
- console.log(props.data, 'data');
- });
- </script>
- <style scoped lang="less">
- /* 全局面板样式 */
- .fire-safety-panel {
- border-radius: 8px;
- padding: 3px;
- color: #fff;
- font-family: 'Microsoft YaHei', sans-serif;
- padding-top: 10px;
- }
- /* 列表容器 */
- .sensor-list {
- display: flex;
- flex-direction: column;
- gap: 15px; /* 组间距 */
- }
- /** 按钮 **/
- .control-bar {
- background: url('@/assets/images/beltFire/yjkf/1-2title.png');
- background-size: 100% 100%;
- display: flex;
- justify-content: space-around;
- height: 50px;
- }
- .control-btn {
- background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
- border: 1px solid #40c4ff;
- color: #fff;
- font-size: 12px;
- padding: 2px 8px;
- height: 24px;
- margin: auto;
- box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
- display: inline-flex;
- align-items: center;
- justify-content: center;
- }
- /* 分组卡片 */
- .sensor-group {
- background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
- background-size: 100% 100%;
- padding: 10px;
- }
- /* 组标题 */
- .group-title {
- background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
- background-size: 35% 100%;
- color: #fff;
- font-size: 12px;
- font-weight: bold;
- font-style: italic;
- margin-bottom: 8px;
- padding-bottom: 5px;
- padding-left: 10px;
- .check-btn {
- color: #fff;
- font-size: 12px;
- }
- }
- /* 列表项 */
- .sensor-item {
- height: 30px;
- background-size: 100% 100%;
- display: flex;
- align-items: center;
- margin-bottom: 5px;
- font-size: 13px;
- color: #c0d0e0;
- overflow-y: auto;
- background-repeat: no-repeat;
- }
- .sensor-item.bg-1 {
- background-image: url('@/assets/images/beltFire/yjkf/1-5.png');
- }
- .sensor-item.bg-2 {
- background-image: url('@/assets/images/beltFire/yjkf/1-6.png');
- }
- .item-icon {
- background-size: 100% 100%;
- width: 20px;
- height: 20px;
- margin-left: 10px;
- }
- .item-icon.bg-1 {
- background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
- }
- .item-icon.bg-2 {
- background: url('@/assets/images/beltFire/yjkf/1-4wz.svg') no-repeat;
- }
- .container {
- display: flex;
- flex-wrap: wrap;
- gap: 10px;
- }
- .dataInfo-item {
- display: flex;
- justify-content: space-around;
- margin-bottom: 5px;
- font-size: 13px;
- width: calc(50% - 5px);
- color: #c0d0e0;
- }
- .dataInfo-item:nth-child(1),
- .dataInfo-item:nth-child(4) {
- background: url('@/assets/images/beltFire/yjkf/1-7.png') no-repeat;
- background-size: 100% 100%;
- }
- .dataInfo-item:nth-child(2),
- .dataInfo-item:nth-child(3) {
- background: url('@/assets/images/beltFire/yjkf/1-8.png') no-repeat;
- background-size: 100% 100%;
- }
- .item-status {
- width: 100%;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- margin: 0 15px 0 20px;
- .item-label {
- color: #fff;
- height: 30px;
- line-height: 30px;
- }
- .item-code {
- height: 30px;
- line-height: 30px;
- text-align: right;
- color: #91faff;
- font-size: 12px;
- font-family: 'douyuFont';
- }
- }
- .item-content {
- flex: 1;
- display: flex;
- align-items: center;
- .label {
- color: #fff;
- }
- }
- .item-value {
- margin-right: 10px;
- font-size: 12px;
- color: #36dae7;
- }
- .item-info {
- color: #ffff;
- font-size: 11px;
- }
- /* 状态指示灯 */
- .status-dot {
- display: inline-block;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- margin-left: 5px;
- margin-top: 10px;
- animation: pulse 2s infinite;
- background: #3a3a3a;
- // position: absolute;
- // left: 0;
- // top: 50%;
- transform: translateY(-50%);
- box-shadow: 0 0 6px 2px rgba(90, 90, 90, 0.6);
- &.status-normal {
- background-color: #00ff00;
- box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
- }
- &.status-danger {
- background-color: #ff4d4d;
- box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
- animation: flash 1s infinite;
- }
- }
- /* 动画效果 */
- @keyframes pulse {
- 0% {
- transform: scale(1);
- opacity: 1;
- }
- 50% {
- transform: scale(1.2);
- opacity: 0.8;
- }
- 100% {
- transform: scale(1);
- opacity: 1;
- }
- }
- @keyframes flash {
- 0% {
- opacity: 1;
- }
- 50% {
- opacity: 0.5;
- }
- 100% {
- opacity: 1;
- }
- }
- </style>
|