Merge branch 'main' into dev/2025a

dev/ckeditor
Lei OT 1 month ago
commit 4d3c4979c8

@ -1,7 +1,7 @@
{
"name": "global-sales",
"private": true,
"version": "1.4.9",
"version": "1.4.10",
"type": "module",
"scripts": {
"dev": "vite",

@ -1,6 +1,6 @@
import { create } from 'zustand';
import { RealTimeAPI } from '@/channel/realTimeAPI';
import { olog, isEmpty, groupBy, sortArrayByOrder, logWebsocket, pick, sortKeys, omit, sortObjectsByKeysMap } from '@/utils/commons';
import { olog, isEmpty, groupBy, sortArrayByOrder, logWebsocket, pick, sortKeys, omit, sortObjectsByKeysMap, clean7DaysWebsocketLog } from '@/utils/commons';
import { receivedMsgTypeMapped, handleNotification } from '@/channel/bubbleMsgUtils';
import { fetchConversationsList, fetchTemplates, fetchConversationsSearch, UNREAD_MARK, fetchTags } from '@/actions/ConversationActions';
import { devtools } from 'zustand/middleware';
@ -597,6 +597,8 @@ export const useConversationStore = create(
setTags(myTags);
setInitial(true);
// 登录后, 执行一下清除日志缓存
clean7DaysWebsocketLog();
},
reset: () => set(initialConversationState),

@ -595,28 +595,48 @@ export const TagColorStyle = (tag, outerStyle = false) => {
/**
*
*/
const INDEXED_DB_VERSION = 3;
export const logWebsocket = (message, direction) => {
var open = indexedDB.open('LogWebsocketData', 2)
var open = indexedDB.open('LogWebsocketData', INDEXED_DB_VERSION)
open.onupgradeneeded = function () {
var db = open.result
// 数据库是否存在
if (!db.objectStoreNames.contains('LogStore')) {
var store = db.createObjectStore('LogStore', { keyPath: 'id', autoIncrement: true })
store.createIndex('timestamp', 'timestamp', { unique: false })
} else {
const logStore = open.transaction.objectStore('LogStore')
if (!logStore.indexNames.contains('timestamp')) {
logStore.createIndex('timestamp', 'timestamp', { unique: false })
}
}
}
open.onsuccess = function () {
var db = open.result
var tx = db.transaction('LogStore', 'readwrite')
var store = tx.objectStore('LogStore')
store.put({ direction, message, date: new Date().toLocaleString() })
store.put({ direction, message, date: new Date().toLocaleString(), timestamp: Date.now() })
tx.oncomplete = function () {
db.close()
}
}
};
export const readWebsocketLog = () => {
export const readWebsocketLog = (limit = 20) => {
return new Promise((resolve, reject) => {
let openRequest = indexedDB.open('LogWebsocketData')
openRequest.onupgradeneeded = function () {
var db = openRequest.result
// 数据库是否存在
if (!db.objectStoreNames.contains('LogStore')) {
var store = db.createObjectStore('LogStore', { keyPath: 'id', autoIncrement: true })
store.createIndex('timestamp', 'timestamp', { unique: false })
} else {
const logStore = openRequest.transaction.objectStore('LogStore')
if (!logStore.indexNames.contains('timestamp')) {
logStore.createIndex('timestamp', 'timestamp', { unique: false })
}
}
}
openRequest.onerror = function (e) {
reject('Error opening database.')
}
@ -627,21 +647,36 @@ export const readWebsocketLog = () => {
resolve('Database does not exist.')
return
}
let transaction = db.transaction('LogStore')
let transaction = db.transaction('LogStore', 'readonly')
let store = transaction.objectStore('LogStore')
let request = store.getAll()
const request = store.openCursor(null, 'prev'); // 从后往前
const results = [];
let count = 0;
request.onerror = function (e) {
reject('Error getting all records.')
reject('Error getting records.')
}
request.onsuccess = function (e) {
let data = e.target.result
sessionStorage.setItem('websocketLogData', JSON.stringify(data))
console.log(JSON.stringify(data))
resolve(data)
const cursor = e.target.result
if (cursor) {
if (count < limit) {
results.unshift(cursor.value)
count++
cursor.continue()
} else {
console.log(JSON.stringify(results))
resolve(results)
}
} else {
console.log(JSON.stringify(results))
resolve(results)
}
}
}
})
};
/**
* @deprecated
*/
export const clearWebsocketLog = () => {
let openRequest = indexedDB.open('LogWebsocketData')
openRequest.onerror = function (e) {}
@ -658,3 +693,145 @@ export const clearWebsocketLog = () => {
clearRequest.onsuccess = function (e) {}
}
}
export const writeIndexDB = (row, table, database) => {
var open = indexedDB.open(database, INDEXED_DB_VERSION)
open.onupgradeneeded = function () {
var db = open.result
// 数据库是否存在
if (!db.objectStoreNames.contains(table)) {
var store = db.createObjectStore(table, { keyPath: 'id', autoIncrement: true })
store.createIndex('timestamp', 'timestamp', { unique: false })
} else {
const objectStore = open.transaction.objectStore(table)
if (!objectStore.indexNames.contains('timestamp')) {
objectStore.createIndex('timestamp', 'timestamp', { unique: false })
}
}
}
open.onsuccess = function () {
var db = open.result
var tx = db.transaction(table, 'readwrite')
var store = tx.objectStore(table)
store.put({ ...row, _date: new Date().toLocaleString(), timestamp: Date.now() })
tx.oncomplete = function () {
db.close()
}
}
};
export const deleteIndexDBbyKey = (key, table, database) => {
var open = indexedDB.open(database, INDEXED_DB_VERSION)
open.onupgradeneeded = function () {
var db = open.result
// 数据库是否存在
if (!db.objectStoreNames.contains(table)) {
var store = db.createObjectStore(table, { keyPath: 'id', autoIncrement: true })
}
}
open.onsuccess = function () {
var db = open.result
var tx = db.transaction(table, 'readwrite')
var store = tx.objectStore(table)
store.delete(key)
tx.oncomplete = function () {
db.close()
}
}
};
function cleanOldData(database, storeName, dateKey = 'timestamp') {
return function (daysToKeep = 7) {
return new Promise((resolve, reject) => {
let deletedCount = 0
const recordsToDelete = new Set()
let openRequest = indexedDB.open(database, INDEXED_DB_VERSION)
openRequest.onupgradeneeded = function () {
var db = openRequest.result
// 数据库是否存在
if (!db.objectStoreNames.contains(storeName)) {
var store = db.createObjectStore(storeName, { keyPath: 'id', autoIncrement: true })
store.createIndex('timestamp', 'timestamp', { unique: false })
} else {
const logStore = openRequest.transaction.objectStore(storeName)
if (!logStore.indexNames.contains('timestamp')) {
logStore.createIndex('timestamp', 'timestamp', { unique: false })
}
}
}
openRequest.onsuccess = function (e) {
let db = e.target.result
// 数据库是否存在
if (!db.objectStoreNames.contains(storeName)) {
resolve('Database does not exist.')
return
}
// Calculate the cutoff timestamp for "X days ago"
const cutoffTimestamp = Date.now() - daysToKeep * 24 * 60 * 60 * 1000
// Identify old data using the date index and primary key ID
const readTransaction = db.transaction([storeName], 'readwrite')
const objectStore = readTransaction.objectStore(storeName)
if (!objectStore.indexNames.contains(`${dateKey}`)) {
// Clear the store
let clearRequest = objectStore.clear()
console.log(`Cleanup complete. clear ${storeName} records.`)
resolve();
clearRequest.onerror = function (e) {}
clearRequest.onsuccess = function (e) {}
return
}
// Get records older than 'daysToKeep' using the index
const dateIndex = objectStore.index(`${dateKey}`)
const dateRange = IDBKeyRange.upperBound(cutoffTimestamp, false) // Get keys < cutoffTimestamp (strictly older)
const dateCursorRequest = dateIndex.openCursor(dateRange)
dateCursorRequest.onsuccess = (event) => {
const cursor = event.target.result
if (cursor) {
recordsToDelete.add(cursor.primaryKey) // Add the primary key of the record to the set
cursor.continue()
} else {
// Delete identified data in a new transaction
const deleteTransaction = db.transaction([storeName], 'readwrite')
const deleteObjectStore = deleteTransaction.objectStore(storeName)
deleteTransaction.oncomplete = () => {
console.log(`Cleanup complete. Deleted ${deletedCount} records.`)
resolve(deletedCount)
}
deleteTransaction.onerror = (event) => {
console.error('Deletion transaction error:', event.target.error)
reject(event.target.error)
}
// Convert Set to Array for forEach
Array.from(recordsToDelete).forEach((key) => {
const deleteRequest = deleteObjectStore.delete(key)
deleteRequest.onsuccess = () => {
deletedCount++
}
deleteRequest.onerror = (event) => {
console.warn(`Failed to delete record with key ${key}:`, event.target.error)
}
})
}
}
dateCursorRequest.onerror = (event) => {
console.error('Error opening date cursor for deletion:', event.target.error)
reject(event.target.error)
}
}
openRequest.onerror = function (e) {
reject('Error opening database:'+database, e)
}
})
}
}
export const clean7DaysWebsocketLog = cleanOldData('LogWebsocketData', 'LogStore');

@ -101,7 +101,7 @@ function AuthApp() {
endTime: now,
})
messageApi.info('Success')
clearWebsocketLog()
// clearWebsocketLog()
sendNotify()
} catch (error) {
messageApi.error('Failure')

@ -147,13 +147,11 @@ const EmailDetailInline = ({ mailID, emailMsg = {}, disabled = false, ...props }
return (
<>
<div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'>
<div className=' font-bold'>
<div className='email-container h-full flex flex-col gap-0 divide-y divide-neutral-200 divide-solid *:p-2 *:border-0'>
<div className=''>
{loading ? <LoadingOutlined className='mr-1' /> : null}
{mailData.info?.MAI_Subject || emailMsg?.msgOrigin?.subject}
</div>
<div>
<span className=' font-bold '>{mailData.info?.MAI_Subject || emailMsg?.msgOrigin?.subject}</span>
<Divider className='my-2' />
<div className={['flex flex-wrap justify-end', window.innerWidth < 600 ? 'flex-col' : 'flex-row '].join(' ')}>
<div className=' flex-auto basis-0 flex flex-wrap gap-2 mb-2 items-center'>
<Avatar className='' style={TagColorStyle(mailData.info?.MAI_From, true)}>
@ -191,7 +189,8 @@ const EmailDetailInline = ({ mailID, emailMsg = {}, disabled = false, ...props }
{mailData.info.bcc}
</div>
)}
<Divider className='my-2' />
</div>
<div className='overflow-auto'>
<Flex className=' divide-y-0 divide-x divide-gray-200 divide-solid gap-0'>
{mailData.info?.mailType === 'text/html' ? (
<EmailContent content={mailData.content} id={mailID} key={mailID} />

@ -314,10 +314,10 @@ const CustomerProfile = ({ disabled }) => {
className='hover:bg-stone-50 cursor-pointer [&.ant-list-item]:py-1 [&.ant-list-item]:px-2'
onClick={() => setClicked3rdEmailItem(email) }>
<Flex
vertical className="grow"
vertical className="w-full"
>
<div className="text-stone-600 line-clamp-1">
<Typography.Text ellipsis={{tooltip: email.SenderReceiver}} style={{width: 380}} className="text-stone-600">{email.SenderReceiver}</Typography.Text></div>
<Typography.Text ellipsis={{tooltip: email.SenderReceiver}} className="text-stone-600">{email.SenderReceiver}</Typography.Text></div>
<div className="">{email.MAI_Subject}</div>
</Flex>
</List.Item>

Loading…
Cancel
Save