Parcourir la source

feat:企业监控分组组件

yangfeng il y a 7 mois
Parent
commit
c432f36712

+ 431 - 0
apps/bigmember_pc/src/composables/quick-monitor/component/MonitorGroup.vue

@@ -0,0 +1,431 @@
+<script setup>
+import { ref, onMounted, watch } from 'vue'
+import { showToast } from '@/components/toast'
+
+const props = defineProps({
+  // 要回显的分组id
+  echo: {
+    type: String,
+    default: ''
+  },
+  // 分组列表
+  list: {
+    type: Array,
+    default: () => []
+  }
+})
+
+// 属性
+const groupList = ref([])
+const newGroupName = ref('')
+const showAdd = ref(false)
+const isDisabled = ref(false)
+const currentSelect = ref([])
+
+// 冒泡事件名
+const emits = defineEmits(['emitDisabled', 'onChange', 'onAdd', 'onEdit'])
+
+onMounted(() => {
+  initData()
+})
+
+// 监听isDisabled属性
+watch(
+  () => isDisabled.value,
+  (newVal) => {
+    emits('emitDisabled', newVal)
+  }
+)
+// 监听list属性
+watch(
+  () => props.list,
+  (newVal) => {
+    initData()
+  }
+)
+
+// function inputCountHighLight() {
+//   const countElement = document.querySelector('.el-input__count')
+//   const countHtml = document.querySelector('.el-input__count > .el-input__count-inner')
+//   if(countElement && countHtml) {
+//     const str = countHtml.textContent
+//     const regex = /(\d+)\/(\d+)/
+//     let newStr = str.replace(regex, '<em class="highlight">$1</em>/$2');
+//     countHtml.textContent = newStr
+//     countElement.appendChild(countHtml)
+//   }
+// }
+
+function initData() {
+  if (!props.list || !props.list.length) return
+  const formatList = props.list.map((v) => {
+    return {
+      id: v.id,
+      name: v.s_name || v.name,
+      input: '',
+      showEdit: false,
+      canEdit: v.isPut,
+      checked: currentSelect.value.length
+        ? currentSelect.value.includes(v.id)
+        : v.isSelect
+    }
+  })
+  groupList.value = formatList
+  if (props.echo) {
+    setGroupSelected(props.echo)
+  }
+}
+
+// 新增分组改变交互方法
+function onAddAction() {
+  showAdd.value = true
+  newGroupName.value = ''
+  isDisabled.value = true
+}
+// 新增分组确认方法
+function onAddConfirm() {
+  if (!newGroupName.value) {
+    return showToast('请输入分组名称')
+  }
+  if (groupList.value.some((v) => v.name === newGroupName.value)) {
+    return showToast('分组名称已存在')
+  }
+  const newItem = {
+    // id: Math.random(),
+    name: newGroupName.value,
+    showEdit: false,
+    checked: false,
+    input: ''
+  }
+  groupList.value.splice(1, 0, newItem)
+  showAdd.value = false
+  isDisabled.value = false
+  emits('add', { name: newGroupName.value })
+}
+// 新增分组取消方法
+function onAddCancel() {
+  newGroupName.value = ''
+  showAdd.value = false
+  isDisabled.value = false
+}
+// 单项编辑分组
+function onEditGroup(item) {
+  item.input = item.name
+  item.showEdit = true
+  isDisabled.value = true
+}
+// 单项编辑输入方法
+function onItemInput(event, item) {
+  // item.input = event
+}
+// 单项编辑确认方法
+function onItemConfirm(item) {
+  const list = groupList.value
+  if (!item.input) {
+    return showToast('请输入分组名称')
+  }
+  if (list.some((v) => v.name === item.input)) {
+    return showToast('分组名称已存在')
+  }
+  item.name = item.input
+  item.showEdit = false
+  isDisabled.value = false
+  emits('edit', { groupId: item.id, name: item.name })
+}
+// 单项编辑取消方法
+function onItemCancel(item) {
+  item.showEdit = false
+  isDisabled.value = false
+}
+// 分组名称选中事件
+function changeGroupState(item) {
+  const list = groupList.value
+  if (item.name === '默认分组') {
+    list.forEach((v) => {
+      v.checked = false
+    })
+    item.checked = true
+  } else {
+    item.checked = !item.checked
+    const allChecked = list.some((s) => {
+      return s.checked
+    })
+    if (allChecked) {
+      list[0].checked = false
+    } else {
+      list[0].checked = true
+    }
+  }
+  const selected = getSelected()
+  emits('onChange', selected)
+}
+// 获取选中的分组
+function getSelected() {
+  const data = []
+  const lists = groupList.value
+  lists.forEach((v) => {
+    if (v.checked) {
+      data.push(v.id)
+    }
+  })
+  currentSelect.value = data
+  return data.toString()
+}
+// 设置选中的分组
+function setGroupSelected(data) {
+  if (!data) return
+  const list = groupList.value
+  const newData = data.split(',')
+  list.forEach((v) => {
+    v.checked = false
+    newData.forEach((s) => {
+      if (s === v.id) {
+        v.checked = true
+      }
+    })
+  })
+}
+</script>
+<template>
+  <div class="monitor-group" :class="{ disabled: isDisabled }">
+    <div class="flex flex-(items-center justify-end) group-add-container">
+      <div
+        class="flex flex-(items-center justify-between) add-container"
+        v-if="showAdd"
+      >
+        <el-input
+          v-model="newGroupName"
+          placeholder="请输入分组名称"
+          class="add-input"
+          maxlength="15"
+          show-word-limit
+          @keyup.enter.native="onAddConfirm"
+        />
+        <div class="flex flex-items-center add-action">
+          <span class="add-confirm" @click="onAddConfirm">确定</span>
+          <span class="add-cancel" @click="onAddCancel">取消</span>
+        </div>
+      </div>
+      <el-button
+        v-else
+        type="text"
+        icon="el-icon-plus"
+        @click="onAddAction"
+        class="add-btn"
+      >
+        新增分组
+      </el-button>
+    </div>
+    <div class="group-list-container">
+      <div v-for="(item, key) in groupList" :key="key" class="group-item">
+        <div
+          v-if="!item.showEdit"
+          class="flex flex-(items-center justify-between) item-name-container"
+          :class="{ 'item-name-checked': item.checked }"
+          @click="changeGroupState(item)"
+        >
+          <div class="flex flex-items-center flex-1">
+            <div
+              v-if="item.name === '默认分组'"
+              class="j-radio"
+              :class="item.checked ? 'r-checked' : ''"
+            ></div>
+            <div
+              v-else
+              class="j-checkbox"
+              :class="item.checked ? 'checked' : ''"
+            ></div>
+            <span class="item-name" :data-id="item.id">{{ item.name }}</span>
+          </div>
+          <span
+            class="item-edit"
+            v-if="item.canEdit"
+            @click.stop="onEditGroup(item)"
+            >编辑</span
+          >
+        </div>
+        <div
+          v-else
+          class="flex flex-(item-center space-between) item-edit-container"
+        >
+          <el-input
+            v-model="item.input"
+            placeholder="请输入分组名称"
+            class="add-input input-bg"
+            maxlength="15"
+            show-word-limit
+            @input="onItemInput($event, item)"
+            @keyup.enter.native="onItemConfirm(item)"
+          />
+          <div class="flex items-center add-action">
+            <span class="add-confirm" @click="onItemConfirm(item)">确定</span>
+            <span class="add-cancel" @click="onItemCancel(item)">取消</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<style lang="scss" scoped>
+.monitor-group {
+  .j-radio {
+    width: 20px;
+    height: 20px;
+    margin-right: 4px;
+    background: url('~@/assets/images/icon/radio_default.png') no-repeat center
+      center;
+    cursor: pointer;
+    background-size: 20px;
+    &.r-checked {
+      background: url('~@/assets/images/icon/radio_checked2.png') no-repeat
+        center center;
+      background-size: 20px;
+    }
+  }
+  .j-checkbox {
+    width: 20px;
+    height: 20px;
+    margin-right: 4px;
+    border: 0;
+    background: url('~@/assets/images/icon/checkbox_default.png') no-repeat
+      center center;
+    cursor: pointer;
+    background-size: 20px;
+    &.checked {
+      border: 0;
+      background: url('~@/assets/images/icon/checkbox_checked.png') no-repeat
+        center center;
+      background-size: 20px;
+      &[disabled] {
+        background: url('~@/assets/images/icon/checkbox_checked_disabled.png')
+          no-repeat;
+        background-size: 20px;
+      }
+    }
+  }
+  .group-add-container {
+    .add-container {
+      width: 100%;
+    }
+  }
+  .group-list-container {
+    margin-top: 20px;
+    max-height: 380px;
+    overflow-y: auto;
+    border: 1px solid rgba(236, 236, 236, 1);
+    border-radius: 4px;
+    &::-webkit-scrollbar {
+      width: 3px;
+    }
+    .item-name {
+      margin-left: 4px;
+      line-height: 22px;
+    }
+    .item-edit {
+      display: none;
+      color: $color_main;
+      cursor: pointer;
+      line-height: 22px;
+    }
+    .group-item {
+      cursor: pointer;
+      &:hover {
+        background: #eaf8fa;
+        .item-edit {
+          display: block;
+        }
+      }
+      &:not(:last-child) {
+        border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+      }
+    }
+    .item-name-container {
+      padding: 8px 12px 8px 16px;
+      &.item-name-checked {
+        background: #eaf8fa;
+        color: $color_main;
+      }
+    }
+    .item-edit-container {
+      padding: 4px 12px 4px 16px;
+    }
+  }
+  .add-confirm {
+    margin-left: 12px;
+    color: $color_main;
+    font-size: 14px;
+    line-height: 22px;
+    cursor: pointer;
+  }
+  .add-cancel {
+    margin-left: 12px;
+    color: #1d1d1d;
+    font-size: 14px;
+    line-height: 22px;
+    cursor: pointer;
+  }
+  ::v-deep {
+    .add-input {
+      flex: 1;
+      .el-input__inner {
+        padding: 0 12px;
+        height: 30px;
+        line-height: 30px;
+      }
+      &.input-bg {
+        background: #fff;
+        .el-input__inner {
+          background: #eaf8fa;
+        }
+      }
+    }
+    .add-btn {
+      padding: 2px 0;
+      span {
+        margin-left: 0px;
+      }
+    }
+    .el-input__count-inner {
+      background: transparent;
+    }
+  }
+  &.disabled {
+    .group-list-container {
+      background: #f5f6f7;
+    }
+    .add-btn {
+      color: #999999;
+    }
+    .group-item {
+      &:hover {
+        .item-edit {
+          display: none;
+        }
+      }
+    }
+    .item-edit-container {
+      background: #fff;
+    }
+    .item-name-container,
+    .add-btn {
+      pointer-events: none;
+      cursor: not-allowed;
+    }
+    .item-name {
+      color: #999999;
+    }
+    .j-radio {
+      background-image: url('~@/assets/images/icon/radio_default_disabled.png');
+      &.r-checked {
+        background-image: url('~@/assets/images/icon/radio_checked_disabled2.png');
+      }
+    }
+    .j-checkbox {
+      background-image: url('~@/assets/images/icon/checkbox_default_disabled.png');
+      &.checked {
+        background-image: url('~@/assets/images/icon/checkbox_checked_disabled.png');
+      }
+    }
+  }
+}
+</style>