wujingjing
2025-03-04 ce5d4a0d224aaab33b4d8ddd7b4af170882d406e
预览业务表格
已修改4个文件
已添加1个文件
262 ■■■■■ 文件已修改
src/components/chat/components/playBar/PlayBar.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/playBar/businessTable/index.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/playBar/businessTablePreview/index.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/user/index.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/table/colFilter/ColFilter.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/playBar/PlayBar.vue
@@ -25,12 +25,14 @@
                </el-button>
            </div>
            <div class="set-input ">
            <div class="set-input">
                <div v-if="attachList?.length > 0" class="flex gap-3.5 w-full overflow-x-auto px-2 pb-2">
                    <div
                        v-for="(item, index) in attachList"
                        :key="index"
                        class="flex items-center gap-2 bg-[#f5f5f5] px-2 py-3 rounded-lg w-[220px] relative group"
                        :class="{ 'cursor-pointer': item.type === 'table' }"
                        @click="openAttachPreview(item)"
                    >
                        <template v-if="item.type === 'file'">
                            <el-image
@@ -56,7 +58,7 @@
                        </template>
                        <div
                            class="group-hover:visible invisible absolute right-0.5 top-0.5 bg-red-500 flex-center rounded-full p-0.5 cursor-pointer"
                            @click="deleteAttachInIndex(index)"
                            @click.stop="deleteAttachInIndex(index)"
                        >
                            <span class="ywifont ywicon-guanbi text-white !text-[10px] font-bold"></span>
                        </div>
@@ -142,6 +144,7 @@
                @updateInput="updateInputValue"
            />
            <BusinessTable v-model="businessTableIsShow" @submit="submitBusinessTable" />
            <BusinessTablePreview :data="attachPreviewData" v-model="attachPreviewIsShow" @submit="submitBusinessTable" />
        </div>
    </div>
</template>
@@ -149,15 +152,18 @@
<script setup lang="ts">
import type { InputInstance } from 'element-plus';
import { nextTick, ref } from 'vue';
import BusinessTable from './businessTable/index.vue';
import BusinessTablePreview from './businessTablePreview/index.vue';
import type { Attach } from './hook/useAttach';
import { useAttach } from './hook/useAttach';
import { useInputEvent } from './hook/useInputEvent';
import { useUploadFile } from './hook/useUploadFile';
import InputTip from './inputTip/index.vue';
import CommonPhrases from './phrase/CommonPhrases.vue';
import SceneSwitch from './SceneSwitch.vue';
import VoicePage from './voicePage/VoicePage.vue';
import { useCompRef } from '/@/utils/types';
import { useUploadFile } from './hook/useUploadFile';
import BusinessTable from './businessTable/index.vue';
import { useAttach } from './hook/useAttach';
const emits = defineEmits(['sendClick', 'stopGenClick']);
const props = defineProps({
    isTalking: Boolean,
@@ -269,6 +275,16 @@
    businessTableIsShow.value = true;
};
//#endregion
//#region ====================== é™„件预览 ======================
const attachPreviewIsShow = ref(false);
const attachPreviewData = ref<Attach>();
const openAttachPreview = (item: Attach) => {
    if (item.type === 'file') return;
    attachPreviewIsShow.value = true;
    attachPreviewData.value = item;
};
//#endregion
defineExpose({
    addPhrase,
    showSyncTip,
src/components/chat/components/playBar/businessTable/index.vue
@@ -46,19 +46,19 @@
            </template>
            <template #main>
                <div class="w100 h100">
                    <div class="h-full">
                    <div class="h-full flex-column">
                        <ColFilter class="flex-0 ml-auto mb-2" :column-list="tableCheckData" />
                        <el-table
                            v-loading="tableLoading"
                            ref="draggableTableRef"
                            class="h100"
                            class="flex-auto"
                            border
                            :row-class-name="isDragStatus ? 'cursor-move' : 'cursor-pointer'"
                            :data="tableData"
                            highlight-current-row
                            @sort-change="handleSortChange"
                        >
                            <el-table-column
                                v-for="item in tableColumns"
                                v-for="item in visibleTableColumns"
                                :prop="item.name"
                                sortable="custom"
                                :key="item.name"
@@ -89,6 +89,7 @@
import { useCompRef } from '/@/utils/types';
import { convertListToTree, debounce, travelTree } from '/@/utils/util';
import { ElMessage } from 'element-plus';
import ColFilter from '/@/components/table/colFilter/ColFilter.vue';
const dialogIsShow = defineModel({
    type: Boolean,
});
@@ -106,13 +107,18 @@
        submitLoading.value = false;
    });
    const tables = checkedList.map((item) => {
        const indexMapItem = getIndexMapItem(item.columns);
        return {
            title: item.title,
            columns: item.columns.map((item) => {
                return item.title;
            }),
            columns: item.columns
                .filter((item) => item.isShow)
                .map((item) => {
                    return item.title;
                }),
            values: item.tableData.map((item) => {
                return Object.values(item);
                return Object.values(item).filter((item, index) => {
                    return indexMapItem.get(index).isShow;
                });
            }),
        };
    });
@@ -121,7 +127,6 @@
};
const submitFormValue = async () => {
    const data = await getSubmitData();
    emit('submit', data);
    dialogIsShow.value = false;
};
@@ -169,6 +174,7 @@
                    ...item,
                    // åˆå§‹æŸ¥è¯¢å€¼
                    values: [''],
                    isShow: true,
                };
            });
        }
@@ -221,10 +227,28 @@
const tableData = computed(() => {
    return currentNode.value?.tableData || [];
});
const isDragStatus = ref(false);
const tableColumns = computed(() => {
    return currentNode.value?.columns || [];
});
const tableCheckData = computed(() => {
    return tableColumns.value.map((item) => {
        return {
            prop: item.name,
            label: item.title,
            get isShow() {
                return item.isShow;
            },
            set isShow(value) {
                item.isShow = value;
            },
        };
    });
});
const visibleTableColumns = computed(() => {
    return tableColumns.value.filter((item) => item.isShow);
});
const getTableData = async () => {
    // allTableData.value = (res.values || []).map((item) => {
@@ -249,16 +273,9 @@
    );
};
const indexMapItem = computed<Map<number, any>>(() => {
    return new Map(
        tableColumns.value.map((item, index) => {
            return [index, item];
        })
    );
});
//#region ====================== æŸ¥è¯¢ ======================
const getFilterColumns = (node) => {
    return node?.columns?.filter((item) => item.filter) as any[];
    return node?.columns?.filter((item) => item.filter && item.isShow) as any[];
};
const filterColumns = computed(() => {
    return getFilterColumns(currentNode.value);
@@ -432,4 +449,10 @@
        height: calc(90vh - 111px) !important;
    }
}
.yw-layout-main {
    .el-card__body {
        padding: 10px;
    }
}
</style>
src/components/chat/components/playBar/businessTablePreview/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@
<template>
    <el-dialog
        class="limit-height"
        :destroy-on-close="true"
        v-model="dialogIsShow"
        width="70%"
        :close-on-click-modal="false"
        @closed="closeDialog"
    >
        <template #header>
            <div style="color: #fff">
                <SvgIcon name="ele-Document" :size="16" style="margin-right: 3px; display: inline; vertical-align: middle" />
                <span>查看业务表</span>
            </div>
        </template>
        <div class="w100 h100">
            <div class="h-full flex-column">
                <ColFilter class="flex-0 ml-auto mb-2" :column-list="tableCheckData" />
                <el-table v-loading="tableLoading" ref="draggableTableRef" class="flex-auto" border :data="tableData" highlight-current-row>
                    <el-table-column
                        v-for="item in visibleTableColumns"
                        :prop="item.name"
                        sortable
                        :key="item.name"
                        :label="item.title"
                        show-overflow-tooltip
                    >
                    </el-table-column>
                </el-table>
            </div>
        </div>
    </el-dialog>
</template>
<script setup lang="ts" name="BusinessTablePreview">
import type { PropType } from 'vue';
import { computed, ref, watch } from 'vue';
// import TableSearch from './search/index.vue';
import type { Attach } from '../hook/useAttach';
import ColFilter from '/@/components/table/colFilter/ColFilter.vue';
const dialogIsShow = defineModel({
    type: Boolean,
});
const props = defineProps({
    data: {
        type: Object as PropType<Attach>,
        default: () => {},
    },
});
const closeDialog = () => {
    dialogIsShow.value = false;
    tableData.value = [];
    tableColumns.value = [];
};
//#region ====================== æŒ‡æ ‡ç®¡ç†è¡¨æ ¼æ•°æ®ï¼Œtable init ======================
const tableLoading = ref(false);
const tableData = ref([]);
const tableColumns = ref([]);
const tableCheckData = computed(() => {
    return tableColumns.value.map((item) => {
        return {
            prop: item.name,
            label: item.title,
            get isShow() {
                return item.isShow;
            },
            set isShow(value) {
                item.isShow = value;
            },
        };
    });
});
const visibleTableColumns = computed(() => {
    return tableColumns.value.filter((item) => item.isShow);
});
//#endregion
const getIndexMapItem = (columns) => {
    return new Map<number, any>(
        columns.map((item, index) => {
            return [index, item];
        })
    );
};
//#region ====================== æŸ¥è¯¢ ======================
const parseRecordData = (values, columns) => {
    const indexMapItem = getIndexMapItem(columns);
    return (values || []).map((item, index) => {
        const row = {} as any;
        item?.forEach((item, index) => {
            row[indexMapItem.get(index).name] = item;
        });
        return row;
    });
};
//#endregion
watch(
    () => dialogIsShow.value,
    (val) => {
        if (!val) return;
        tableColumns.value = (props.data?.model?.columns || []).map((item) => {
            return {
                name: item,
                title: item,
                isShow: true,
            };
        });
        tableData.value = parseRecordData(props.data?.model?.values || [], tableColumns.value);
    }
);
</script>
<style scoped lang="scss">
.set-permission {
    padding-block: 16px;
    padding-block-end: 0;
}
.set-form {
    display: block;
    box-sizing: border-box;
    height: 100%;
    padding-block: 16px;
    .set-form-item {
        font-weight: 500;
        color: #667085;
        font-size: 14px;
    }
}
:deep(.el-dialog__body) {
    height: calc(90vh - 111px) !important;
}
</style>
<style lang="scss">
.limit-height {
    .el-dialog__body {
        height: calc(90vh - 111px) !important;
    }
}
.yw-layout-main {
    .el-card__body {
        padding: 10px;
    }
}
</style>
src/components/chat/user/index.vue
@@ -11,6 +11,8 @@
                                v-for="(item, index) in msg.attachList"
                                :key="index"
                                class="flex items-center gap-2 bg-[#e9e9e9] px-2 py-3 rounded-lg w-[220px] relative group"
                                @click="openAttachPreview(item)"
                                :class="{ 'cursor-pointer': item.type === 'table' }"
                            >
                                <template v-if="item.type === 'file'">
                                    <el-image
@@ -42,6 +44,7 @@
                </div>
            </div>
        </div>
        <BusinessTablePreview :data="attachPreviewData" v-model="attachPreviewIsShow" />
        <!-- #endregion -->
        <div class="flex px-4 rounded-lg relative flex-row-reverse items-center" :key="`${msg.historyId}_${msg.role}`">
@@ -103,10 +106,13 @@
</template>
<script setup lang="ts" name="UserMsg">
import { useClipboard } from '@vueuse/core';
import { ElMessage } from 'element-plus';
import { AnswerState, answerTypeMapCom, roleImageMap, type ChatMessage } from '../model/types';
import { isSharePage } from '/@/stores/chatRoom';
import { onClickOutside, useClipboard } from '@vueuse/core';
import { ref } from 'vue';
import BusinessTablePreview from '../components/playBar/businessTablePreview/index.vue';
import { Attach } from '../components/playBar/hook/useAttach';
const emit = defineEmits<{
    (event: 'copyMsg', msgObj: ChatMessage): void;
@@ -135,5 +141,15 @@
const shareClick = (msg) => {
    emit('shareClick', msg);
};
//#region ====================== é™„件预览 ======================
const attachPreviewIsShow = ref(false);
const attachPreviewData = ref<Attach>();
const openAttachPreview = (item: Attach) => {
    if (item.type === 'file') return;
    attachPreviewIsShow.value = true;
    attachPreviewData.value = item;
};
//#endregion
</script>
<style scoped lang="scss"></style>
src/components/table/colFilter/ColFilter.vue
@@ -1,7 +1,7 @@
<template>
    <el-dropdown trigger="click" placement="bottom-end" :hideOnClick="false">
        <span
            title="点击选择显示列"
            :title="title"
            class="rounded-full p-1.5 border-[1.5px] hover:text-blue-400 border-gray-200 border-solid cursor-pointer ywifont ywicon-grid !text-[13px] h-fit"
        ></span>
@@ -35,6 +35,10 @@
        type: Boolean,
        default: true,
    },
    title: {
        type: String,
        default: '点击选择显示列',
    },
});
const emit = defineEmits<{