From 38b161e4d52362081bfe78fb5b51fbf384db7ce2 Mon Sep 17 00:00:00 2001
From: schangxiang@126.com <schangxiang@126.com>
Date: 周二, 06 5月 2025 07:22:21 +0800
Subject: [PATCH] 222

---
 HIAWms/web/src/components/Table/components/custom-vxe-column.vue |  555 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 555 insertions(+), 0 deletions(-)

diff --git a/HIAWms/web/src/components/Table/components/custom-vxe-column.vue b/HIAWms/web/src/components/Table/components/custom-vxe-column.vue
new file mode 100644
index 0000000..1c4db54
--- /dev/null
+++ b/HIAWms/web/src/components/Table/components/custom-vxe-column.vue
@@ -0,0 +1,555 @@
+<template>
+  <vxe-column
+    width="60"
+    v-if="currentSeq.seq || showDarg || isDrag || isChecked"
+    :fixed="currentSeq.column.fixed"
+  >
+    <template #header v-if="!radio">
+      <el-checkbox
+        v-if="isChecked"
+        class="th-td-checkbox"
+        v-model="checkedAll.checked"
+        :indeterminate="checkedAll.isIndeterminate"
+        @change="selectChangeAllEvent"
+      ></el-checkbox>
+      <span v-else-if="currentSeq.seq">{{ _gt(currentSeq.column.title) }}</span>
+    </template>
+    <template #default="{ row, rowIndex }">
+      <div class="custom-td-action">
+        <div
+          v-show="showDarg || isDrag"
+          :class="{
+            'drag-move': true,
+            'information-row-td': true,
+            'td-hover': true,
+            disabled: disabledDrag,
+          }"
+        >
+          <Icon icon="icon_move" class="btn-move"></Icon>
+        </div>
+        <span
+          v-if="currentSeq.seq"
+          :style="currentCheckedStyle(row, true)"
+          class="information-row-sort td-sort-hover"
+          >{{ rowIndex + 1 }}</span
+        >
+        <template v-if="radio">
+          <el-radio
+            style="top: 3px; right: 0px"
+            :value="row[id || 'id']"
+            :modelValue="radioValue"
+            :style="currentCheckedStyle(row)"
+            @change="onRadioChange(row)"
+            class="information-row-td td-hover checkout-style"
+          ></el-radio>
+        </template>
+        <template v-else>
+          <a-checkbox
+            v-if="
+              isFunction(isChecked) ? isChecked({ row, rowIndex }) : isChecked
+            "
+            :key="row[props.id || 'id']"
+            v-model="selectionMap[row[props.id || 'id']]"
+            :style="currentCheckedStyle(row)"
+            class="information-row-td td-hover checkout-style"
+            @change="(checked: boolean) => currentCheckedEvent(checked, row)"
+          ></a-checkbox>
+        </template>
+      </div>
+    </template>
+  </vxe-column>
+
+  <template
+    v-for="(column, index) in columns"
+    :field="column.field"
+    :key="column.field"
+  >
+    <!-- header -->
+    <vxe-column
+      v-bind="column"
+      :sortable="column.sortable"
+      v-if="slots[column?.field] || slots[`${column?.field}.header`]"
+      show-header-overflow="title"
+    >
+      <template #header="{ row }: any" v-if="slots[`${column?.field}.header`]">
+        <slot
+          :name="`${column?.field}.header`"
+          :row="row"
+          :index="index"
+          :column="column"
+        ></slot>
+      </template>
+      <!-- column.required == true -->
+      <template #header v-if="column?.required">
+        <span style="color: #ff2929">*</span>
+        {{ _t(column.title) }}
+      </template>
+      <!-- tipConfig header -->
+      <template #header v-if="column?.tipConfig?.tip">
+        <div class="header-tip-config-row">
+          <span v-if="column?.required" style="color: #ff2929">*</span>
+          <span :style="column?.tipConfig?.style">
+            {{ _t(column.title) }}
+          </span>
+          <el-tooltip
+            effect="dark"
+            :content="column?.tipConfig?.tip + ''"
+            placement="top"
+            :persistent="false"
+          >
+            <Icon
+              v-if="column?.tipConfig?.icon"
+              :width="16"
+              :height="16"
+              :icon="column?.tipConfig?.icon"
+            ></Icon>
+          </el-tooltip>
+        </div>
+      </template>
+      <!-- tip -->
+      <template #default="{ row, rowIndex }">
+        <div
+          class="table-context-menu-content"
+          slot-type="native"
+          @click="(event: Event) => onRowClick(row, event)"
+        >
+          <div
+            @contextmenu="(event) => onClickShowMenu(event, row, rowIndex)"
+            slot-type="native"
+            class="table-context-menu"
+          >
+            <slot
+              :name="column.field"
+              :row="row"
+              :index="rowIndex"
+              :column="column"
+            ></slot>
+          </div>
+        </div>
+      </template>
+    </vxe-column>
+    <vxe-column v-bind="column" :title="_t(column.title)" v-else>
+      <template #default="{ row, rowIndex }">
+        <div
+          class="table-context-menu-content"
+          slot-type="native"
+          @click="(event: Event) => onRowClick(row, event)"
+        >
+          <template v-if="get(row, column.field)">
+            <div
+              @contextmenu="(event) => onClickShowMenu(event, row, rowIndex)"
+              class="table-context-menu"
+              slot-type="native"
+            >
+              <el-tooltip
+                effect="dark"
+                :content="get(row, column.field) + ''"
+                placement="top"
+                :persistent="false"
+              >
+                <span slot-type="native" class="over-ellipsis">{{
+                  get(row, column.field)
+                }}</span>
+              </el-tooltip>
+            </div>
+          </template>
+          <template v-else>
+            <div
+              @contextmenu="(event) => onClickShowMenu(event, row, rowIndex)"
+              slot-type="native"
+              class="table-context-menu"
+            >
+              <span slot-type="native" class="over-ellipsis">{{
+                isNil(get(row, column.field)) ? '-' : get(row, column.field)
+              }}</span>
+            </div>
+          </template>
+        </div>
+      </template>
+    </vxe-column>
+  </template>
+</template>
+<script setup lang="ts">
+// @ts-nocheck
+import { computed, ref, useSlots, useAttrs, Ref, watch, inject } from 'vue'
+import Icon from '../../Icon/Icon'
+import type { TablePropsItemType, contextMenuItemType } from '../index.d'
+import { useVModel } from '@vueuse/core'
+import VxeColumn from 'vxe-table/es/column/index'
+
+import { getScopeT } from '@/libs/Language/Language'
+import { isFunction, get, isNil, cloneDeep } from 'lodash'
+
+interface vxePropsType extends TablePropsItemType {
+  id: string
+  contextMenuConfig: contextMenuItemType
+  headBorder: boolean
+  rowStyle: any
+}
+const props = defineProps<vxePropsType>()
+const emit = defineEmits([
+  'drag',
+  'check',
+  'sort',
+  'page',
+  'rowClick',
+  'update:dataSource',
+  'clickFooter',
+  'update',
+  'load',
+  'beforeLoad',
+  'change',
+])
+const _t = getScopeT(props.LanguageScopeKey)
+const _gt = getScopeT()
+const slots = useSlots()
+const tableRef = inject<any>('tableRef')
+const selectionMap = ref<Record<string, boolean>>({})
+const radioValue = ref('')
+
+/**
+ * 閲嶆柊瀹氫箟鍒�
+ */
+const columns = computed(() => {
+  return props.columns.filter((column) => {
+    return column.type !== 'seq' && !column.hide
+  })
+})
+/**
+ * 鏄惁鍚湁搴忓彿
+ */
+const currentSeq = computed(() => {
+  return {
+    seq: props.columns.some((column) => column.type === 'seq'),
+    column: props.columns.find((column) => column.type === 'seq') || {
+      title: '搴忓彿',
+      field: 'seq',
+      type: 'seq',
+    },
+  }
+})
+
+const contextMenuConfig = useVModel(props, 'contextMenuConfig', emit)
+
+const checkedAll = ref({
+  isIndeterminate: false,
+  checked: false,
+})
+
+const currentCheckedStyle = computed(() => {
+  return (row: Record<string, any>, isSort?: boolean) => {
+    const checkedStyle = {
+      display: 'inline',
+      marginLeft: '14px',
+      marginTop: '-1px',
+    }
+    if (!currentSeq.value.seq) {
+      return checkedStyle
+    }
+    if (
+      selectionMap.value[row[props.id || 'id']] ||
+      radioValue.value === row[props.id || 'id']
+    ) {
+      if (isSort) {
+        if (props.isChecked || props.radio) {
+          return { display: 'none' }
+        }
+        return {
+          display: 'inline',
+        }
+      } else {
+        return checkedStyle
+      }
+    } else {
+      if (isSort && !props.isChecked && !props.radio) {
+        return {
+          display: 'inline',
+          marginLeft: '24px',
+        }
+      }
+      return ''
+    }
+  }
+})
+
+const dataSource = computed({
+  get() {
+    return props.dataSource
+  },
+  set(v) {
+    if (v) {
+      emit('update:dataSource', v)
+    }
+  },
+})
+
+/**
+ * 鍙抽敭鑿滃崟
+ * @param event
+ * @param index
+ */
+const onClickShowMenu = (event: MouseEvent, row: any, index: number) => {
+  if (event) {
+    event?.preventDefault()
+    contextMenuConfig.value.show = true
+    contextMenuConfig.value.options.x = event.x
+    contextMenuConfig.value.options.y = event.y
+    contextMenuConfig.value.current = {
+      row,
+      index,
+    }
+  }
+}
+/**
+ * 娓呴櫎閫変腑鏁堟灉
+ */
+const clearSelection = () => {
+  const $table = tableRef.value
+  $table?.setAllCheckboxRow(false)
+
+  dataSource.value.forEach((row: Record<string, any>) => {
+    delete selectionMap.value[row[props.id || 'id']]
+  })
+  $table?.clearCheckboxRow()
+  checkedAll.value.isIndeterminate = false
+  checkedAll.value.checked = false
+  emitCheckboxChange()
+}
+/**
+ * 鍗曢��
+ */
+const onRadioChange = (row) => {
+  const id = row[props.id || 'id']
+  if (radioValue.value === id) {
+    radioValue.value = ''
+  } else {
+    radioValue.value = id
+  }
+  emit('change', row)
+  emit('check', [row])
+}
+/**
+ * 鍏ㄩ��
+ */
+const selectChangeAllEvent = (checked: boolean) => {
+  const $table = tableRef.value
+  const checkedAllFn = (checked: boolean) => {
+    $table?.setAllCheckboxRow(checked)
+    const records = $table.getCheckboxRecords()
+    records.forEach((row: Record<string, any>) => {
+      selectionMap.value[row[props.id || 'id']] = true
+    })
+  }
+  if (!checked && checkedAll.value.isIndeterminate) {
+    checkedAll.value.checked = true
+    checkedAll.value.isIndeterminate = false
+    checkedAllFn(true)
+  } else if (!checked) {
+    clearSelection()
+
+    $table?.setAllCheckboxRow(false)
+    return (selectionMap.value = {})
+  }
+  if (checked) {
+    checkedAllFn(checked)
+    checkedAll.value.isIndeterminate = false
+    checkedAll.value.checked = true
+  } else {
+    clearSelection()
+  }
+  checkedAll.value.isIndeterminate = false
+
+  selectChangeEvent()
+}
+/**
+ *
+ * @param rows
+ */
+const selectionHandle = (
+  rows: Record<string, any>[],
+  checked: boolean = true
+) => {
+  rows.forEach((row: Record<string, any>) => {
+    selectionMap.value[row[props.id || 'id']] = checked
+  })
+}
+
+/**
+ * 鍗曢��
+ */
+const currentCheckedEvent = (checked: boolean, row: Record<string, any>) => {
+  const $table = tableRef.value
+  $table?.setCheckboxRow([row], checked)
+
+  const records = Object.values(selectionMap.value).filter((v) => v)
+  selectionHandle([row], checked)
+  if (records.length > 0) {
+    checkedAll.value.isIndeterminate = true
+    if (records.length === dataSource.value.length) {
+      checkedAll.value.isIndeterminate = false
+      checkedAll.value.checked = true
+    }
+  } else {
+    checkedAll.value.isIndeterminate = false
+    checkedAll.value.checked = false
+  }
+  selectChangeEvent()
+}
+
+/**
+ * 澶氶��
+ */
+const setCheckboxRow = (rows: Record<string, any>[], checked: boolean) => {
+  const $table = tableRef.value
+  if (props.radio) {
+    radioValue.value = rows[0][props.id || 'id']
+  } else {
+    $table?.setCheckboxRow(rows, checked)
+    const records = $table.getCheckboxRecords()
+    selectionHandle(rows, checked)
+    if (records.length > 0) {
+      checkedAll.value.isIndeterminate = true
+      if (records.length === dataSource.value.length) {
+        checkedAll.value.isIndeterminate = false
+        checkedAll.value.checked = true
+      }
+    } else {
+      checkedAll.value.isIndeterminate = false
+      checkedAll.value.checked = false
+    }
+    selectChangeEvent()
+  }
+}
+/**
+ * 鍗曢�夐�変腑
+ */
+const setRadioRow = (row = {}) => {
+  if (props.radio) {
+    radioValue.value = row[props.id || 'id']
+  }
+}
+/**
+ * 鍗曢�夐�変腑
+ * @param id
+ */
+const setRadioRowKey = (id) => {
+  if (props.radio) {
+    radioValue.value = id
+  }
+}
+/**
+ * 鍏ㄩ�変簨浠�
+ */
+
+const getRecords = () => {
+  const records = []
+  dataSource.value.forEach((item: Record<string, any>) => {
+    if (selectionMap.value[item[props.id || 'id']]) {
+      records.push(item)
+    }
+  })
+  return records
+}
+
+const selectChangeEvent = () => {
+  const $table = tableRef.value
+  if ($table) {
+    const records = getRecords()
+    emit('check', records, cloneDeep(selectionMap.value))
+  }
+}
+
+const onRowClick = (row: Record<string, any>, event: Event) => {
+  if (props.cancelRowCheck) return
+  if (props.isStop) {
+    event?.stopPropagation()
+  }
+  if (props.radio) {
+    return onRadioChange(row)
+  }
+  if (props.isChecked) {
+    const dom = event.target as HTMLInputElement
+    if (dom.getAttribute('slot-type') === 'native') {
+      const $table = tableRef.value
+      const checked = $table.isCheckedByCheckboxRow(row)
+      selectionMap.value[row[props.id || 'id']] = !checked
+      currentCheckedEvent(!checked, row)
+    }
+  }
+}
+
+const selectionLength = computed(() => {
+  let l = 0
+  Object.entries(selectionMap.value).forEach(([key, value]: any[]) => {
+    if (value) {
+      l++
+    }
+  })
+  return l
+})
+/**
+ * 瑙﹀彂澶嶉�夋
+ */
+const emitCheckboxChange = () => {
+  const records = tableRef.value?.getCheckboxRecords()
+  emit('check', records, cloneDeep(selectionMap.value))
+}
+
+const handleDataSelection = () => {
+  if (!dataSource.value.length) {
+    checkedAll.value.isIndeterminate = false
+    checkedAll.value.checked = false
+    selectionMap.value = {}
+  } else {
+    const data: any = {}
+    if (!selectionLength.value) {
+      data.isIndeterminate = false
+      data.checked = false
+    } else {
+      data.isIndeterminate = true
+      data.checked = selectionLength.value === dataSource.value.length
+    }
+    checkedAll.value = data
+  }
+  emitCheckboxChange()
+}
+
+if (!props.cancelEmitCheck) {
+  watch(
+    () => dataSource.value.length,
+    (v: number, oldV: number) => {
+      if (v !== oldV) {
+        const currentSelectedKeys: Record<string, boolean> = {}
+        dataSource.value.forEach((item: Record<string, any>) => {
+          const key = item[props.id || 'id']
+
+          if (selectionMap.value.hasOwnProperty(key)) {
+            currentSelectedKeys[key] = selectionMap.value[key]
+          }
+        })
+        Object.entries(selectionMap.value).forEach(([key, value]: any[]) => {
+          if (!currentSelectedKeys.hasOwnProperty(key)) {
+            currentSelectedKeys[key] = false
+          }
+        })
+        selectionMap.value = currentSelectedKeys
+        handleDataSelection()
+      }
+    }
+  )
+}
+
+defineExpose({
+  clearSelection,
+  setCheckboxRow,
+  selectChangeAllEvent,
+  setRadioRowKey,
+  setRadioRow,
+})
+</script>
+<style lang="scss">
+@import url('../index.scss');
+</style>
+<style lang="scss" scoped>
+@import url('../index.module.scss');
+</style>

--
Gitblit v1.9.3