123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- <script setup lang="ts">
- import {ref, inject} from 'vue';
- import {Search, Delete} from "@element-plus/icons-vue";
- const drawer = ref(false);
- const count = ref(0);
- const input = ref('');
- const loading = ref(false);
- const dataList = ref<any[]>([]);
- // 获取父组件提供的 Hook 实例
- const {db, useStore, deleteDB} = inject('indexedDBHook') as any;
- const emit = defineEmits(['currentData']);
- const props = defineProps({
- msgUuid: {
- type: String,
- default: ''
- }
- })
- watch(drawer, (newVal) => {
- if (newVal) {
- loading.value = true;
- getFirstTwoRecordsFromEachStore(db.value).then((data: any) => {
- dataList.value = data.filter((item: any) => item !== null);
- count.value = dataList.value.length || 0;
- loading.value = false;
- // console.log('First two records from each store:', data);
- }).catch((error) => {
- console.error('Error:', error);
- });
- }
- })
- function handleDeleteDB() {
- deleteDB().then((res) => {
- console.log('Database deleted successfully.', res);
- // // 重新加载页面
- // window.location.reload();
- }).catch((error: any) => {
- console.error('Error deleting database:', error);
- });
- }
- function getFirstTwoRecordsFromObjectStoreWithCursor(db: any, storeName: any) {
- return new Promise((resolve, reject) => {
- const transaction = db.transaction([storeName], 'readonly');
- const objectStore = transaction.objectStore(storeName);
- const request = objectStore.openCursor();
- const results: any[] = [];
- let count = 0;
- request.onerror = (event: any) => {
- reject(`Failed to get data from object store ${storeName}: ${event.target.error}`);
- };
- request.onsuccess = (event: any) => {
- const cursor = event.target.result;
- if (cursor && count < 2) {
- results.push(cursor.value);
- count++;
- cursor.continue();
- } else {
- if (results.length) {
- resolve({
- storeName: storeName,
- data: results
- });
- } else {
- resolve(null)
- }
- }
- };
- });
- }
- async function getFirstTwoRecordsFromEachStore(db: any) {
- return new Promise((resolve, reject) => {
- // 获取所有对象存储的名称
- const storeNames = Array.from(db.objectStoreNames);
- const result: any[] = [];
- // 遍历每个对象存储并获取前 2 条数据
- const promises = storeNames.map((storeName) => {
- return getFirstTwoRecordsFromObjectStoreWithCursor(db, storeName);
- });
- // 等待所有对象存储的数据读取完成
- Promise.all(promises).then((dataArrays) => {
- // 将每个对象存储的数据合并到结果数组中
- dataArrays.forEach((data: any) => {
- result.push(data);
- });
- resolve(result);
- }).catch((error) => {
- reject(error);
- });
- })
- }
- function handleDeleteStore(e: any, item: any) {
- e.stopPropagation();
- if (item === props.msgUuid) {
- const result = getNextOrPreviousId(dataList.value, item);
- emit('currentData', result)
- }
- useStore(item).clearAll().then((res: any) => {
- loading.value = true;
- getFirstTwoRecordsFromEachStore(db.value).then((data: any) => {
- dataList.value = data.filter((item: any) => item !== null);
- count.value = dataList.value.length || 0;
- console.log(dataList.value)
- loading.value = false;
- // console.log('First two records from each store:', data);
- }).catch((error) => {
- console.error('Error:', error);
- });
- });
- }
- function getNextOrPreviousId(array: any, currentId: any) {
- const currentIndex = array.findIndex((item: any) => item.storeName === currentId);
- if (currentIndex === -1) {
- throw new Error("当前 storeName 不在数组中");
- }
- if (currentIndex < array.length - 1) {
- return array[currentIndex + 1].storeName; // 返回下一个对象的 id
- } else if (currentIndex > 0) {
- return array[currentIndex - 1].storeName; // 返回上一个对象的 id
- }
- return null; // 没有下一个或上一个对象
- }
- defineExpose({
- drawer
- })
- </script>
- <template>
- <el-drawer style="height: 70%" v-model="drawer" direction="btt" :show-close="true"
- :close-on-click-modal="false" :destroy-on-close="true"
- :close-on-press-escape="false" class="custom_drawer">
- <template #header>
- <div class="his_flex"><span class="his_title">历史聊天</span><span class="his_count">({{ count }})</span></div>
- </template>
- <div style="height: 100%;overflow: hidden;" v-loading="loading">
- <div class="his_delete">
- <el-input style="margin-right: 12px" v-model="input" placeholder="搜索" clearable :prefix-icon="Search"/>
- <el-button :icon="Delete" circle @click="handleDeleteDB"/>
- </div>
- <div class="his_content">
- <template v-for="item in dataList" :key="item.storeName">
- <div :class="`his_list ${msgUuid === item.storeName ? 'his_list_change' : '' }`"
- @click="emit('currentData',item.storeName)">
- <p class="ellipsis" style="color:#000000;font-weight: 900;">{{ item.data[0]?.content ?? '--' }}</p>
- <p class="ellipsis" style="color: #888888">{{ item.data[1] ? item.data[1].content : '--' }}</p>
- <p class="his_list_op">
- <span>{{ item.data[0]?.timestamp }}</span>
- <el-button :icon="Delete" link @click="(e:any)=>handleDeleteStore(e,item.storeName)"/>
- </p>
- </div>
- </template>
- </div>
- </div>
- </el-drawer>
- </template>
- <style lang="scss">
- .his_flex {
- display: flex;
- align-items: center;
- }
- .custom_drawer {
- height: 70vh !important;
- border-top-left-radius: 15px;
- border-top-right-radius: 15px;
- .el-drawer__header {
- padding: 16px;
- margin-bottom: 0;
- }
- .el-drawer__close-btn, .el-drawer__body {
- padding: 0;
- }
- .el-drawer__body {
- overflow: hidden;
- height: 100%;
- }
- }
- .his_title {
- display: inline-block;
- color: #000000;
- font-size: 20px;
- font-weight: 900;
- margin-right: 3px;
- height: 24px;
- line-height: 24px;
- }
- .his_count {
- display: inline-block;
- height: 24px;
- line-height: 24px;
- }
- .his_delete {
- padding: 0 12px 10px;
- display: flex;
- position: sticky;
- align-items: center;
- justify-content: space-between;
- .is-circle {
- border-radius: 8px;
- }
- }
- .his_content {
- height: calc(100% - 40px);
- overflow: auto;
- padding: 0 12px;
- .ellipsis {
- white-space: nowrap; /* 强制文本不换行 */
- overflow: hidden; /* 隐藏溢出内容 */
- text-overflow: ellipsis; /* 显示省略号 */
- width: 100%; /* 设置宽度(必须) */
- }
- .his_list {
- font-size: 12px;
- padding: 5px 10px;
- border-radius: 8px;
- margin-bottom: 4px;
- box-shadow: 0 0 6px rgba(122, 89, 255, .16);
- cursor: pointer;
- .his_list_op {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- }
- .his_list:hover {
- background-color: rgba(122, 89, 255, .06);
- }
- .his_list_change {
- background-color: rgba(122, 89, 255, .2) !important;
- }
- }
- </style>
|