vite 实现排列编辑分类全选功能

需求背景

需要实现编辑的排列列表,并按单排或全部实现全选功能,并添加位子的悬停弹窗效果

解决效果

vite 实现排列编辑分类全选功能_第1张图片

index.vue

html

<!--/**
 * @author: liuk
 * @date: 2023/3/28
 * @describe: 排管理
 * @mail:[email protected]
*/-->
<template>
  <div class="mangeRow">
    <div class="creatbtn">
      <div class="creatbtn1">
        <el-button class="btn" @click="clickLine">+&nbsp;创建排</el-button>
      </div>
    </div>
    <div class="rowHover">
      <el-checkbox v-model="isCheckAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选
      </el-checkbox>
      <el-checkbox-group v-model="checkedList" @change="handlecheckedListChange">
        <div v-for="item in listData" :key="item.burialId">
          <el-checkbox :label="item" class="children" @change="checkboxChange(item.blessingList,$event)">
            <template #default>
              <b>物理排号 :{{ item.serialNumber }}</b>&nbsp;&nbsp;&nbsp;&nbsp;<b>排名称:{{ item.row }}</b>
            </template>
          </el-checkbox>
          <el-icon class="icon-wrap" size="20" @click="editRow(item)">
            <Edit/>
          </el-icon>
          <el-icon class="icon-wrap" size="20" @click="deleteArea(item)">
            <DeleteFilled/>
          </el-icon>
          <div class="rank_content">
            <div class="rankNo" @click="addBlessingDig(item)" style="color: inherit">
              <el-icon size="30" style="margin-top: 20px">
                <Plus/>
              </el-icon>
            </div>
            <div v-for="(item2,index2) in item.blessingList" :key="index2">
              <el-popover
                  placement="top"
                  :width="400"
                  :height="250"
                  trigger="hover"
              >
                <div class="popver-dialog">
                  <el-row :gutter="24">
                    <el-col :span="16">
                      <div class="statusTit" :style="{background:matchList[item2.blessingStatus - 1].color}">
                        {{ matchList[item2.blessingStatus - 1].label }}
                      </div>
                      <p class="tit" :title="item2.blessingName">
                        {{ item2.blessingName }}
                      </p>
                      <p class="price">{{ item2.price }}
                      </p>
                    </el-col>
                  </el-row>
                  <el-row :gutter="24" style="margin:10px 0;">
                    <el-col :span="12">
                      面积:{{ item2.area }}
                    </el-col>
                    <el-col :span="12">
                      墓穴数:{{ formatArea(item2.tombNumber) }}
                    </el-col>
                  </el-row>
                  <el-row :gutter="24" style="margin:10px 0;">
                    <el-col :span="12">
                      客户:{{ item2.customerName }}
                    </el-col>
                    <el-col :span="12">
                      使用人:{{ item2.deceasedName }}
                    </el-col>
                  </el-row>
                </div>
                <template #reference>
                  <div class="rankNo"
                       :style="{
                            background:item2.isSelect?'#fff':matchList[item2.blessingStatus - 1].color,
                            borderColor:matchList[item2.blessingStatus - 1].color}"
                       @click="doBlessClick(item2)"
                  >
                    <p v-if="item2.isSelect">✔️</p>
                    <div v-else>
                      <div class="rank_title">{{ item2.serialNumber }}</div>
                      <div class="rank_title" v-if="!item2.deceasedName?.split(',').length">
                        {{ item2.deceasedName?.split(",").length || 0 }}/{{ item2.tombNumber }}
                      </div>
                      <div class="rank_title" v-if="item2.deceasedName?.split(',').length">{{
                          item2.deceasedName
                        }}
                      </div>
                    </div>
                  </div>
                </template>
              </el-popover>
            </div>
          </div>
        </div>
      </el-checkbox-group>
    </div>
    <!--添加排弹框-->
    <el-dialog title="添加排" v-model="addRowOpen" width="240px" append-to-body top="40vh">
      <span>创建的排的数量</span>
      <el-input-number v-model="rowData.multiRow" style="width: 100%;margin-top: 25px"/>
      <template #footer>
        <div class="dialog-footer">
          <el-row justify="center">
            <el-button type="primary" @click="submitForm(rowData,'addRow')">创建</el-button>
          </el-row>
        </div>
      </template>
    </el-dialog>
    <!--修改排-->
    <el-dialog title="编辑排" v-model="editrowOpen" width="300px" append-to-body top="40vh">
      <el-form-item label="排位名称" prop="burialName">
        <el-input v-model="rowForm.burialName"/>
      </el-form-item>
      <template #footer>
        <div class="dialog-footer">
          <el-row justify="center">
            <el-button type="primary" @click="submitForm(rowForm,'editRow')">修改</el-button>
          </el-row>
        </div>
      </template>
    </el-dialog>
    <!--新增福位弹框-->
    <el-dialog title="添加福位" v-model="blessingDialogOpen" width="1000px">
      <add-blessing-dialog :data="blessingData" @submit="submitBlessing" @close="blessingDialogOpen=false"/>
    </el-dialog>
  </div>
</template>

js

<script setup>
import {delBurialArea, addBurialArea, updateBurialArea} from "@/api/cemetery/burialArea";
import {getCurrentInstance, reactive, toRefs, watch} from "vue";
import {addBlessing} from "@/api/cemetery/blessing";
// Props
const props = defineProps(['data', 'curNodeId','modelValue'])
// Emit
const emit = defineEmits((['getlist', 'burialId', 'curRowId','update:modelValue']))
// ref
const elFromRef = ref(null)

// components
import AddBlessingDialog from "./addBlessingDialog.vue"

const {proxy} = getCurrentInstance()
const model = reactive({
  listData: [],//福位数据
  checkedList: [],// 选中的list元素
  isIndeterminate: true,// 是否为不确定全选
  isCheckAll: false, // 福位全选
  blessingData: {},//福位表单数据
  blessingDialogOpen: false,//福位编辑弹框
})
const {
  checkedBlessingIds,
  listData,
  isIndeterminate,
  isCheckAll,
  blessingDialogOpen,
  blessingData
} = toRefs(model)
const rowModel = reactive({
  rowForm: {},//排表单数据
  addRowOpen: false,//添加排弹框
  curRowId: 0,//当前排id
  rowData: {//排表单数据
    multiRow: 0,//添加排数量
  },
  editrowOpen: false,//修改排弹框
  curRowNum: 0,//排数量
})
const {rowForm, addRowOpen, curRowId, rowData, editrowOpen} = toRefs(rowModel)

const checkedBlessingIds = computed(({// 选中的list元素
  get() {
    return props.modelValue
  },
  set(val) {
    console.log(val)
    emit('update:modelValue', val)
  }
}))

watch(
    () => props.data,
    (val) => {  model.listData = JSON.parse(JSON.stringify(val))  }
)

/* --------- 选择框 */
// 单选框值变化
const handlecheckedListChange = (checkedList) => {
  model.isCheckAll = checkedList.length === model.listData.length
  model.isIndeterminate = checkedList.length > 0 && checkedList.length < model.listData.length
}
// 多选框变化
const checkboxChange = (data, bool) => {
  data.forEach((item) => item.isSelect = bool)
  let ids = data.map(item => item.id)
  if (bool) {
    model.checkedBlessingIds = [...new Set([...model.checkedBlessingIds, ...ids])]
  } else {
    let temp = model.checkedBlessingIds
    model.checkedBlessingIds = temp.filter((id) => ids.indexOf(id) == -1)
  }
}
// 全选单选框变化
const handleCheckAllChange = (bool) => {
  let ids = []
  model.listData.forEach(arr => {
    arr.blessingList.forEach(item => {
      item.isSelect = bool;
      ids.push(item.id)
    })
  })
  model.checkedBlessingIds = bool ? ids : [];
  model.checkedList = bool ? model.listData : []
  model.isIndeterminate = false
}

/* --------- 福位 */
// 选中福位
const doBlessClick = (data) => {
  data.isSelect = !data.isSelect
  if (data.isSelect) {
    model.checkedBlessingIds.push(data.id)
  } else {
    let index = model.checkedBlessingIds.findIndex((v) => v == data.id)
    model.checkedBlessingIds.splice(index, 1)
  }
}
// 新增福位
const addBlessingDig = (item) => {
  console.log(item, 22222)
  resetBlessing()
  model.blessingDialogOpen = true
  model.isaddBlessingDig = true
  rowModel.curRowId = item.burialId
  rowModel.curRowNum = item.blessingList.length
}
// 重置
const resetBlessing = () => {
  model.blessingData = {}
}
// 提交
const submitBlessing = (data) => {// 是否为更多操作提交
  let params = {
    burials: model.checkedBlessingIds,
    ...data
  }
  delete params.burials;
  params.burialId = rowModel.curRowId
  params.serialNumber = rowModel.curRowNum + 1
  //addBlessing(params).then(() => {
  //  proxy.$modal.msgSuccess("新增成功");
  //  model.blessingDialogOpen = false;
  //  emit('getlist')
  //});

}
/* --------- 排 */
// 创建排
const clickLine = () => {
  rowModel.addRowOpen = true
}
// 编辑排
const editRow = (item) => {
  reset()
  rowModel.rowForm.burialName = item.row
  rowModel.curRowId = item.burialId
  rowModel.editrowOpen = true
}
// 删除排
const deleteArea = (node) => {// 是否删除排
  proxy.$modal.confirm(`是否确认删除排园区名称编号为` + node.burialId + '"的数据项?').then(function () {
    return delBurialArea(node.burialId)
  }).then(() => {
    emit('getlist')
    proxy.$modal.msgSuccess("删除成功");
  })
}
// 提交
const submitForm = (data, RowStr) => {// 排编辑/新增
  if (data.burialId != null || RowStr == 'editRow') {
    RowStr == 'editRow' && (data.burialId = rowModel.curRowId)
    //updateBurialArea(data).then(response => {
    //  proxy.$modal.msgSuccess("修改成功");
    //  open.value = false;
    //  emit('getlist');
    //  if (RowStr == 'editRow') {
    //    model.checkedBlessingIds = []
    //    rowModel.editrowOpen = false
    //  }
    //});
  } else {
    data.parentId = RowStr == 'addRow' ? props.curNodeId : props.curPid
    data.ifRow = RowStr == 'addRow' ? 1 : 0
    data.delFlag = 0;
    //addBurialArea(data).then(response => {
    //  proxy.$modal.msgSuccess("新增成功");
    //  open.value = false;
    //  emit('getlist');
    //  if (RowStr == 'addRow') {
    //    model.checkedBlessingIds = []
    //    rowModel.addRowOpen = false
    //  }
    //});
  }
}

/* --------- 弹框 */
// 重置form数据
const reset = () => {
  rowModel.rowForm = {
    headPortrait: "",
    burialName: "",
    status: "",
    constructionTime: "",
    areaPark: 0
  }
}

/* --------- 格式化字段 */
const formatArea = (val) => {
  ...
}

const matchList = [
  {
    label: "空闲",
    color: "#f59a23"
  },
  {
    label: "意向",
    color: "#05aad0"
  },
  {
    label: "预定",
    color: "#ae4ba7"
  },
  {
    label: "购买",
    color: "#00b050"
  },
  {
    label: "入驻",
    color: "#7c4d28"
  },
  {
    label: "迁出",
    color: "#ff77a0"
  }
]

</script>

addBlessingDialog.vue

<template>
  <div class="mangeRow">
    <div class="creatbtn">
      <div class="creatbtn1">
        <el-button class="btn" @click="clickLine">+&nbsp;创建排</el-button>
      </div>
    </div>
    <div class="rowHover">
      <el-checkbox v-model="isCheckAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选
      </el-checkbox>
      <el-checkbox-group v-model="checkedList" @change="handlecheckedListChange">
        <div v-for="item in listData" :key="item.burialId">
          <el-checkbox :label="item" class="children" @change="checkboxChange(item.blessingList,$event)">
            <template #default>
              <b>物理排号 :{{ item.serialNumber }}</b>&nbsp;&nbsp;&nbsp;&nbsp;<b>排名称:{{ item.row }}</b>
            </template>
          </el-checkbox>
          <el-icon class="icon-wrap" size="20" @click="editRow(item)">
            <Edit/>
          </el-icon>
          <el-icon class="icon-wrap" size="20" @click="deleteArea(item)">
            <DeleteFilled/>
          </el-icon>
          <div class="rank_content">
            <div class="rankNo" @click="addBlessingDig(item)" style="color: inherit">
              <el-icon size="30" style="margin-top: 20px">
                <Plus/>
              </el-icon>
            </div>
            <div v-for="(item2,index2) in item.blessingList" :key="index2">
              <el-popover
                  placement="top"
                  :width="400"
                  :height="250"
                  trigger="hover"
              >
                <div class="popver-dialog">
                  <el-row :gutter="24">
                    <el-col :span="16">
                      <div class="statusTit" :style="{background:matchList[item2.blessingStatus - 1].color}">
                        {{ matchList[item2.blessingStatus - 1].label }}
                      </div>
                      <p class="tit" :title="item2.blessingName">
                        {{ item2.blessingName }}
                      </p>
                      <p class="price">{{ item2.price }}
                      </p>
                    </el-col>
                  </el-row>
                  <el-row :gutter="24" style="margin:10px 0;">
                    <el-col :span="12">
                      面积:{{ item2.area }}
                    </el-col>
                    <el-col :span="12">
                      墓穴数:{{ formatArea(item2.tombNumber) }}
                    </el-col>
                  </el-row>
                  <el-row :gutter="24" style="margin:10px 0;">
                    <el-col :span="12">
                      客户:{{ item2.customerName }}
                    </el-col>
                    <el-col :span="12">
                      使用人:{{ item2.deceasedName }}
                    </el-col>
                  </el-row>
                </div>
                <template #reference>
                  <div class="rankNo"
                       :style="{
                            background:item2.isSelect?'#fff':matchList[item2.blessingStatus - 1].color,
                            borderColor:matchList[item2.blessingStatus - 1].color}"
                       @click="doBlessClick(item2)"
                  >
                    <p v-if="item2.isSelect">✔️</p>
                    <div v-else>
                      <div class="rank_title">{{ item2.serialNumber }}</div>
                      <div class="rank_title" v-if="!item2.deceasedName?.split(',').length">
                        {{ item2.deceasedName?.split(",").length || 0 }}/{{ item2.tombNumber }}
                      </div>
                      <div class="rank_title" v-if="item2.deceasedName?.split(',').length">{{
                          item2.deceasedName
                        }}
                      </div>
                    </div>
                  </div>
                </template>
              </el-popover>
            </div>
          </div>
        </div>
      </el-checkbox-group>
    </div>
    <!--添加排弹框-->
    <el-dialog title="添加排" v-model="addRowOpen" width="240px" append-to-body top="40vh">
      <span>创建的排的数量</span>
      <el-input-number v-model="rowData.multiRow" style="width: 100%;margin-top: 25px"/>
      <template #footer>
        <div class="dialog-footer">
          <el-row justify="center">
            <el-button type="primary" @click="submitForm(rowData,'addRow')">创建</el-button>
          </el-row>
        </div>
      </template>
    </el-dialog>
    <!--修改排-->
    <el-dialog title="编辑排" v-model="editrowOpen" width="300px" append-to-body top="40vh">
      <el-form-item label="排位名称" prop="burialName">
        <el-input v-model="rowForm.burialName"/>
      </el-form-item>
      <template #footer>
        <div class="dialog-footer">
          <el-row justify="center">
            <el-button type="primary" @click="submitForm(rowForm,'editRow')">修改</el-button>
          </el-row>
        </div>
      </template>
    </el-dialog>
    <!--新增福位弹框-->
    <el-dialog title="添加福位" v-model="blessingDialogOpen" width="1000px">
      <add-blessing-dialog :data="blessingData" @submit="submitBlessing" @close="blessingDialogOpen=false"/>
    </el-dialog>
  </div>
</template>

<script setup>
import {delBurialArea, addBurialArea, updateBurialArea} from "@/api/cemetery/burialArea";
import {getCurrentInstance, reactive, toRefs, watch} from "vue";
import {addBlessing} from "@/api/cemetery/blessing";
// Props
const props = defineProps(['data', 'curNodeId'])
// Emit
const emit = defineEmits((['getlist', 'burialId', 'curRowId']))
// ref
const elFromRef = ref(null)

// components
import AddBlessingDialog from "./addBlessingDialog.vue"

const {proxy} = getCurrentInstance()
const model = reactive({
  listData: [],//福位数据
  checkedList: [],// 选中的list元素
  checkedBlessingIds: [],// 选中福位id
  isIndeterminate: true,// 是否为不确定全选
  isCheckAll: false, // 福位全选
  blessingData: {},//福位表单数据
  blessingDialogOpen: false,//福位编辑弹框
})
const {
  checkedList,
  checkedBlessingIds,
  listData,
  isIndeterminate,
  isCheckAll,
  blessingDialogOpen,
  blessingData
} = toRefs(model)
const rowModel = reactive({
  rowForm: {},//排表单数据
  addRowOpen: false,//添加排弹框
  curRowId: 0,//当前排id
  rowData: {//排表单数据
    multiRow: 0,//添加排数量
  },
  editrowOpen: false,//修改排弹框
  curRowNum: 0,//排数量
})
const {rowForm, addRowOpen, curRowId, rowData, editrowOpen} = toRefs(rowModel)


watch(
    () => props.data,
    (val) => {
      console.log(val, 111)
      model.listData = JSON.parse(JSON.stringify(val))
    }
)

/* --------- 选择框 */
// 单选框值变化
const handlecheckedListChange = (checkedList) => {
  model.isCheckAll = checkedList.length === model.listData.length
  model.isIndeterminate = checkedList.length > 0 && checkedList.length < model.listData.length
}
// 多选框变化
const checkboxChange = (data, bool) => {
  console.log(data, 222, bool)
  data.forEach((item) => item.isSelect = bool)
  let ids = data.map(item => item.id)
  if (bool) {
    model.checkedBlessingIds = [...new Set([...model.checkedBlessingIds, ...ids])]
  } else {
    let temp = model.checkedBlessingIds
    model.checkedBlessingIds = temp.filter((id) => ids.indexOf(id) == -1)
  }
}
// 全选单选框变化
const handleCheckAllChange = (bool) => {
  let ids = []
  model.listData.forEach(arr => {
    arr.blessingList.forEach(item => {
      item.isSelect = bool;
      ids.push(item.id)
    })
  })
  model.checkedBlessingIds = bool ? ids : [];
  model.checkedList = bool ? model.listData : []
  model.isIndeterminate = false
}

/* --------- 福位 */
// 选中福位
const doBlessClick = (data) => {
  data.isSelect = !data.isSelect
  if (data.isSelect) {
    model.checkedBlessingIds.push(data.id)
  } else {
    let index = model.checkedBlessingIds.findIndex((v) => v == data.id)
    model.checkedBlessingIds.splice(index, 1)
  }
}
// 新增福位
const addBlessingDig = (item) => {
  console.log(item, 22222)
  resetBlessing()
  model.blessingDialogOpen = true
  model.isaddBlessingDig = true
  rowModel.curRowId = item.burialId
  rowModel.curRowNum = item.blessingList.length
}
// 重置
const resetBlessing = () => {
  model.blessingData = {}
}
// 提交
const submitBlessing = (data) => {// 是否为更多操作提交
  let params = {
    burials: model.checkedBlessingIds,
    ...data
  }
  delete params.burials;
  params.burialId = rowModel.curRowId
  params.serialNumber = rowModel.curRowNum + 1
  addBlessing(params).then(() => {
    proxy.$modal.msgSuccess("新增成功");
    model.blessingDialogOpen = false;
    emit('getlist')
  });

}
/* --------- 排 */
// 创建排
const clickLine = () => {
  rowModel.addRowOpen = true
}
// 编辑排
const editRow = (item) => {
  reset()
  rowModel.rowForm.burialName = item.row
  rowModel.curRowId = item.burialId
  rowModel.editrowOpen = true
}
// 删除排
const deleteArea = (node) => {// 是否删除排
  proxy.$modal.confirm(`是否确认删除排园区名称编号为` + node.burialId + '"的数据项?').then(function () {
    return delBurialArea(node.burialId)
  }).then(() => {
    emit('getlist')
    proxy.$modal.msgSuccess("删除成功");
  })
}
// 提交
const submitForm = (data, RowStr) => {// 排编辑/新增
  if (data.burialId != null || RowStr == 'editRow') {
    RowStr == 'editRow' && (data.burialId = rowModel.curRowId)
    updateBurialArea(data).then(response => {
      proxy.$modal.msgSuccess("修改成功");
      open.value = false;
      emit('getlist');
      if (RowStr == 'editRow') {
        model.checkedBlessingIds = []
        rowModel.editrowOpen = false
      }
    });
  } else {
    data.parentId = RowStr == 'addRow' ? props.curNodeId : props.curPid
    data.ifRow = RowStr == 'addRow' ? 1 : 0
    data.delFlag = 0;
    addBurialArea(data).then(response => {
      proxy.$modal.msgSuccess("新增成功");
      open.value = false;
      emit('getlist');
      if (RowStr == 'addRow') {
        model.checkedBlessingIds = []
        rowModel.addRowOpen = false
      }
    });
  }
}

/* --------- 弹框 */
// 重置form数据
const reset = () => {
  rowModel.rowForm = {
    headPortrait: "",
    burialName: "",
    status: "",
    constructionTime: "",
    areaPark: 0
  }
}

/* --------- 格式化字段 */
const formatArea = (val) => {
  ...
}

const matchList = [
  {
    label: "空闲",
    color: "#f59a23"
  },
  {
    label: "意向",
    color: "#05aad0"
  },
  {
    label: "预定",
    color: "#ae4ba7"
  },
  {
    label: "购买",
    color: "#00b050"
  },
  {
    label: "入驻",
    color: "#7c4d28"
  },
  {
    label: "迁出",
    color: "#ff77a0"
  }
]

</script>

<style lang="scss" scoped>
.mangeRow {
  height: 100%;

  .creatbtn {
    .creatbtn1 {
      height: 100%;
      width: 100%;
      // 边框虚线
      border: 1px dashed #ccc;
      margin: auto;
    }

    width: 100%;
    height: 50px;
    margin: auto;
    background-color: #fff;

    .btn {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 20px;
      font-weight: 500;
      line-height: 20px;
      color: rgb(22, 21, 21);
    }
  }

  .rowHover {
    overflow-y: auto;
    padding: 10px;
    width: 100%;
    box-sizing: border-box;
    background-color: #fff;
    height: calc(100% - 220px);

    .icon-wrap {
      position: relative;
      top: 3px;
      margin-left: 15px;
    }

    :deep(.el-checkbox-group) {
      font-size: inherit;
      line-height: inherit;

      .el-checkbox__input.is-checked + .el-checkbox__label {
        color: inherit;
      }
    }

    .el-checkbox__label {
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}

// 福位列表
.rank_content {
  flex-wrap: wrap;
  display: flex;
  margin: 8px;

  > div {
    margin-bottom: 10px;
  }

  .rankNo {
    width: 120px;
    height: 60px;
    text-align: center;
    line-height: 30px;
    margin: 4px;
    color: #FFF;
    border: 1px solid #fff;
    cursor: default;
    user-select: none;
  }
}

// popver弹窗样式
.popver-dialog {
  .statusTit {
    width: 60px;
    height: 25px;
    margin-bottom: 10px;
    line-height: 26px;
    border-radius: 30px;
    text-align: center;
    font-size: 14px;
    color: #fff;

  }

  .tit {
    font-weight: 700;
    font-size: 16px;
    color: #585858;
    line-height: 20px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .price {
    margin: 10px 0 0 0;
    padding: 0;
    color: #70cb4f;
    font-size: 16px;
    font-weight: 700;
  }

  .colImg {
    width: 100%;
    height: 100%;

    img {
      display: block;
      width: 100%;
      height: 100%;
    }
  }
}
</style>

视频

222222

你可能感兴趣的:(#,vue实践,javascript,前端,vue.js)