From b64a0deae5b5d33f9e20671a68936b27f0b9b00b Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 21 七月 2026 18:03:03 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro2.0' into dev_pro2.0

---
 src/views/im/manager/group/components/select-dialog.vue |  271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 271 insertions(+), 0 deletions(-)

diff --git a/src/views/im/manager/group/components/select-dialog.vue b/src/views/im/manager/group/components/select-dialog.vue
new file mode 100644
index 0000000..f1af583
--- /dev/null
+++ b/src/views/im/manager/group/components/select-dialog.vue
@@ -0,0 +1,271 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { ImManagerGroupApi } from '#/api/im/manager/group';
+
+import { nextTick, ref } from 'vue';
+
+import { DICT_TYPE } from '#/packages/constants/src';
+import { getDictOptions } from '#/packages/effects/hooks/src';
+
+import { Button, message, Modal } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import {
+  getManagerGroup,
+  getManagerGroupPage,
+} from '#/api/im/manager/group';
+
+const emit = defineEmits<{
+  selected: [rows: ImManagerGroupApi.Group[]];
+}>();
+
+const open = ref(false); // 寮圭獥鏄惁鎵撳紑
+const multiple = ref(false); // 鏄惁澶氶��
+const selectedRows = ref<ImManagerGroupApi.Group[]>([]); // 宸查�夌兢鍒楄〃
+const preSelectedIds = ref<number[]>([]); // 棰勯�夌兢缂栧彿鍒楄〃
+
+/** 缇ら�夋嫨寮圭獥鐨勬悳绱㈣〃鍗� */
+function useGroupSelectGridFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      fieldName: 'name',
+      label: '缇ゅ悕绉�',
+      component: 'Input',
+      componentProps: {
+        allowClear: true,
+        placeholder: '璇疯緭鍏ョ兢鍚嶇О',
+      },
+    },
+    {
+      fieldName: 'status',
+      label: '缇ょ姸鎬�',
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        options: getDictOptions(DICT_TYPE.IM_GROUP_STATUS, 'number'),
+        placeholder: '璇烽�夋嫨缇ょ姸鎬�',
+      },
+    },
+  ];
+}
+
+/** 缇ら�夋嫨寮圭獥鐨勫瓧娈� */
+function useGroupSelectGridColumns(
+  isMultiple = false,
+): VxeTableGridOptions<ImManagerGroupApi.Group>['columns'] {
+  return [
+    {
+      type: isMultiple ? 'checkbox' : 'radio',
+      width: 50,
+    },
+    {
+      field: 'id',
+      title: '缂栧彿',
+      width: 100,
+    },
+    {
+      field: 'name',
+      title: '缇ゅ悕绉�',
+      minWidth: 160,
+    },
+    {
+      field: 'ownerNickname',
+      title: '缇や富',
+      minWidth: 160,
+    },
+    {
+      field: 'memberCount',
+      title: '鎴愬憳鏁�',
+      width: 90,
+    },
+    {
+      field: 'status',
+      title: '缇ょ姸鎬�',
+      width: 100,
+      cellRender: {
+        name: 'CellDict',
+        props: { type: DICT_TYPE.IM_GROUP_STATUS },
+      },
+    },
+  ];
+}
+
+/** 鑾峰彇澶氶�夎褰曪紝鍖呭惈 VXE reserve 璺ㄩ〉璁板綍 */
+function getMultipleSelectedRows() {
+  const selectedMap = new Map<number, ImManagerGroupApi.Group>();
+  const records = [
+    ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
+    ...(gridApi.grid.getCheckboxRecords?.() ?? []),
+  ] as ImManagerGroupApi.Group[];
+  records.forEach((row) => {
+    selectedMap.set(row.id, row);
+  });
+  return [...selectedMap.values()];
+}
+
+/** 澶勭悊澶氶�夊嬀閫夊彉鍖� */
+function handleCheckboxSelectChange() {
+  selectedRows.value = getMultipleSelectedRows();
+}
+
+/** 澶勭悊鍗曢�夊垏鎹� */
+function handleRadioChange(row: ImManagerGroupApi.Group) {
+  selectedRows.value = [row];
+}
+
+/** 澶氶�夋ā寮忎笅鍒囨崲琛屽嬀閫� */
+async function toggleMultipleRow(row: ImManagerGroupApi.Group) {
+  const selected = gridApi.grid.isCheckedByCheckboxRow(row);
+  await gridApi.grid.setCheckboxRow(row, !selected);
+  selectedRows.value = getMultipleSelectedRows();
+}
+
+/** 澶勭悊琛屽弻鍑伙細鍗曢�夌洿鎺ョ‘璁わ紝澶氶�夊垏鎹㈠嬀閫� */
+async function handleCellDblclick({ row }: { row: ImManagerGroupApi.Group }) {
+  if (multiple.value) {
+    await toggleMultipleRow(row);
+    return;
+  }
+  selectedRows.value = [row];
+  await gridApi.grid.setRadioRow(row);
+  handleConfirm();
+}
+
+/** 鍥炴樉棰勯�夌兢 */
+async function applyPreSelection() {
+  if (preSelectedIds.value.length === 0) {
+    return;
+  }
+  const rows = gridApi.grid.getData() as ImManagerGroupApi.Group[];
+  for (const row of rows) {
+    if (!preSelectedIds.value.includes(row.id)) {
+      continue;
+    }
+    if (multiple.value) {
+      await gridApi.grid.setCheckboxRow(row, true);
+    } else {
+      await gridApi.grid.setRadioRow(row);
+      selectedRows.value = [row];
+      return;
+    }
+  }
+  if (multiple.value) {
+    selectedRows.value = getMultipleSelectedRows();
+    return;
+  }
+  const targetId = preSelectedIds.value[0];
+  if (targetId) {
+    selectedRows.value = [await getManagerGroup(targetId)];
+  }
+}
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  formOptions: {
+    schema: useGroupSelectGridFormSchema(),
+  },
+  gridOptions: {
+    columns: useGroupSelectGridColumns(false),
+    height: 520,
+    keepSource: true,
+    checkboxConfig: {
+      highlight: true,
+      range: true,
+      reserve: true,
+    },
+    radioConfig: {
+      highlight: true,
+      trigger: 'row',
+    },
+    proxyConfig: {
+      ajax: {
+        query: async ({ page }, formValues) => {
+          return await getManagerGroupPage({
+            pageNo: page.currentPage,
+            pageSize: page.pageSize,
+            ...formValues,
+          });
+        },
+      },
+    },
+    rowConfig: {
+      keyField: 'id',
+      isHover: true,
+    },
+    toolbarConfig: {
+      refresh: true,
+      search: true,
+    },
+  } as VxeTableGridOptions<ImManagerGroupApi.Group>,
+  gridEvents: {
+    cellDblclick: handleCellDblclick,
+    checkboxAll: handleCheckboxSelectChange,
+    checkboxChange: handleCheckboxSelectChange,
+    radioChange: ({ row }: { row: ImManagerGroupApi.Group }) => {
+      handleRadioChange(row);
+    },
+  },
+});
+
+/** 閲嶇疆鏌ヨ鍜岄�夋嫨鐘舵�� */
+async function resetQueryState() {
+  selectedRows.value = [];
+  await gridApi.grid.clearCheckboxRow();
+  await gridApi.grid.clearCheckboxReserve();
+  await gridApi.grid.clearRadioRow();
+  await gridApi.formApi.resetForm();
+}
+
+/** 鎵撳紑缇ら�夋嫨寮圭獥 */
+async function openModal(
+  selectedIds?: number[],
+  options?: { multiple?: boolean },
+) {
+  open.value = true;
+  multiple.value = options?.multiple ?? false;
+  preSelectedIds.value = selectedIds || [];
+  await nextTick();
+  gridApi.setGridOptions({
+    columns: useGroupSelectGridColumns(multiple.value),
+  });
+  await resetQueryState();
+  await gridApi.query();
+  await nextTick();
+  await applyPreSelection();
+}
+
+/** 鍏抽棴缇ら�夋嫨寮圭獥 */
+function closeModal() {
+  open.value = false;
+}
+
+/** 纭閫夋嫨缇� */
+function handleConfirm() {
+  const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
+  if (rows.length === 0) {
+    message.warning(multiple.value ? '璇疯嚦灏戦�夋嫨涓�鏉℃暟鎹�' : '璇烽�夋嫨涓�鏉℃暟鎹�');
+    return;
+  }
+  emit('selected', multiple.value ? rows : [rows[0]!]);
+  open.value = false;
+}
+
+defineExpose({ open: openModal });
+</script>
+
+<template>
+  <Modal
+    v-model:open="open"
+    title="缇ら�夋嫨"
+    width="70%"
+    :destroy-on-close="true"
+    @ok="handleConfirm"
+    @cancel="closeModal"
+  >
+    <Grid table-title="缇ゅ垪琛�" />
+    <template #footer>
+      <Button @click="closeModal">鍙栨秷</Button>
+      <Button type="primary" @click="handleConfirm">纭畾</Button>
+    </template>
+  </Modal>
+</template>

--
Gitblit v1.9.3