feat
This commit is contained in:
26
Cunkebao/dist/.vite/manifest.json
vendored
26
Cunkebao/dist/.vite/manifest.json
vendored
@@ -1,18 +1,14 @@
|
|||||||
{
|
{
|
||||||
"_charts-DKSCc2_C.js": {
|
"_charts-Cbn6yFil.js": {
|
||||||
"file": "assets/charts-DKSCc2_C.js",
|
"file": "assets/charts-Cbn6yFil.js",
|
||||||
"name": "charts",
|
"name": "charts",
|
||||||
"imports": [
|
"imports": [
|
||||||
"_ui-DhAz00L0.js",
|
"_ui-Cytu8vuP.js",
|
||||||
"_vendor-2vc8h_ct.js"
|
"_vendor-2vc8h_ct.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_ui-D0C0OGrH.css": {
|
"_ui-Cytu8vuP.js": {
|
||||||
"file": "assets/ui-D0C0OGrH.css",
|
"file": "assets/ui-Cytu8vuP.js",
|
||||||
"src": "_ui-D0C0OGrH.css"
|
|
||||||
},
|
|
||||||
"_ui-DhAz00L0.js": {
|
|
||||||
"file": "assets/ui-DhAz00L0.js",
|
|
||||||
"name": "ui",
|
"name": "ui",
|
||||||
"imports": [
|
"imports": [
|
||||||
"_vendor-2vc8h_ct.js"
|
"_vendor-2vc8h_ct.js"
|
||||||
@@ -21,6 +17,10 @@
|
|||||||
"assets/ui-D0C0OGrH.css"
|
"assets/ui-D0C0OGrH.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"_ui-D0C0OGrH.css": {
|
||||||
|
"file": "assets/ui-D0C0OGrH.css",
|
||||||
|
"src": "_ui-D0C0OGrH.css"
|
||||||
|
},
|
||||||
"_utils-6WF66_dS.js": {
|
"_utils-6WF66_dS.js": {
|
||||||
"file": "assets/utils-6WF66_dS.js",
|
"file": "assets/utils-6WF66_dS.js",
|
||||||
"name": "utils",
|
"name": "utils",
|
||||||
@@ -33,18 +33,18 @@
|
|||||||
"name": "vendor"
|
"name": "vendor"
|
||||||
},
|
},
|
||||||
"index.html": {
|
"index.html": {
|
||||||
"file": "assets/index-BdCPAYQ7.js",
|
"file": "assets/index-QManA_e5.js",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"src": "index.html",
|
"src": "index.html",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_vendor-2vc8h_ct.js",
|
"_vendor-2vc8h_ct.js",
|
||||||
"_utils-6WF66_dS.js",
|
"_utils-6WF66_dS.js",
|
||||||
"_ui-DhAz00L0.js",
|
"_ui-Cytu8vuP.js",
|
||||||
"_charts-DKSCc2_C.js"
|
"_charts-Cbn6yFil.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"assets/index-ChiFk16x.css"
|
"assets/index-BkBrwKGe.css"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
Cunkebao/dist/index.html
vendored
8
Cunkebao/dist/index.html
vendored
@@ -11,13 +11,13 @@
|
|||||||
</style>
|
</style>
|
||||||
<!-- 引入 uni-app web-view SDK(必须) -->
|
<!-- 引入 uni-app web-view SDK(必须) -->
|
||||||
<script type="text/javascript" src="/websdk.js"></script>
|
<script type="text/javascript" src="/websdk.js"></script>
|
||||||
<script type="module" crossorigin src="/assets/index-BdCPAYQ7.js"></script>
|
<script type="module" crossorigin src="/assets/index-QManA_e5.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-2vc8h_ct.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-2vc8h_ct.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/utils-6WF66_dS.js">
|
<link rel="modulepreload" crossorigin href="/assets/utils-6WF66_dS.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/ui-DhAz00L0.js">
|
<link rel="modulepreload" crossorigin href="/assets/ui-Cytu8vuP.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/charts-DKSCc2_C.js">
|
<link rel="modulepreload" crossorigin href="/assets/charts-Cbn6yFil.js">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/ui-D0C0OGrH.css">
|
<link rel="stylesheet" crossorigin href="/assets/ui-D0C0OGrH.css">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-ChiFk16x.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BkBrwKGe.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noResults {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import React, { useState, useCallback, useEffect } from "react";
|
|||||||
import { List, Avatar, Collapse, Button } from "antd";
|
import { List, Avatar, Collapse, Button } from "antd";
|
||||||
import type { CollapseProps } from "antd";
|
import type { CollapseProps } from "antd";
|
||||||
import styles from "./WechatFriends.module.scss";
|
import styles from "./WechatFriends.module.scss";
|
||||||
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
import {
|
||||||
|
useCkChatStore,
|
||||||
|
searchContactsAndGroups,
|
||||||
|
} from "@/store/module/ckchat/ckchat";
|
||||||
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
||||||
|
|
||||||
interface WechatFriendsProps {
|
interface WechatFriendsProps {
|
||||||
@@ -17,6 +20,9 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
|||||||
selectedContactId,
|
selectedContactId,
|
||||||
}) => {
|
}) => {
|
||||||
const [newContractList, setNewContractList] = useState<any[]>([]);
|
const [newContractList, setNewContractList] = useState<any[]>([]);
|
||||||
|
const [searchResults, setSearchResults] = useState<
|
||||||
|
(ContractData | weChatGroup)[]
|
||||||
|
>([]);
|
||||||
const getNewContractListFn = useCkChatStore(
|
const getNewContractListFn = useCkChatStore(
|
||||||
state => state.getNewContractList,
|
state => state.getNewContractList,
|
||||||
);
|
);
|
||||||
@@ -26,17 +32,27 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
|||||||
|
|
||||||
// 使用useEffect来处理异步的getNewContractList调用
|
// 使用useEffect来处理异步的getNewContractList调用
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchNewContractList = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await getNewContractListFn();
|
if (searchKeyword.trim()) {
|
||||||
setNewContractList(result || []);
|
// 有搜索关键词时,获取搜索结果
|
||||||
|
const searchResult = await searchContactsAndGroups();
|
||||||
|
setSearchResults(searchResult || []);
|
||||||
|
setNewContractList([]);
|
||||||
|
} else {
|
||||||
|
// 无搜索关键词时,获取分组列表
|
||||||
|
const result = await getNewContractListFn();
|
||||||
|
setNewContractList(result || []);
|
||||||
|
setSearchResults([]);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取联系人分组列表失败:", error);
|
console.error("获取联系人数据失败:", error);
|
||||||
setNewContractList([]);
|
setNewContractList([]);
|
||||||
|
setSearchResults([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchNewContractList();
|
fetchData();
|
||||||
}, [getNewContractListFn, kfSelected, countLables, searchKeyword]);
|
}, [getNewContractListFn, kfSelected, countLables, searchKeyword]);
|
||||||
|
|
||||||
const [activeKey, setActiveKey] = useState<string[]>([]); // 默认展开第一个分组
|
const [activeKey, setActiveKey] = useState<string[]>([]); // 默认展开第一个分组
|
||||||
@@ -50,30 +66,32 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
|||||||
const [page, setPage] = useState<{ [key: string]: number }>({});
|
const [page, setPage] = useState<{ [key: string]: number }>({});
|
||||||
|
|
||||||
// 渲染联系人项
|
// 渲染联系人项
|
||||||
const renderContactItem = (contact: ContractData) => (
|
const renderContactItem = (contact: ContractData | weChatGroup) => {
|
||||||
<List.Item
|
// 判断是否为群组
|
||||||
key={contact.id}
|
const isGroup = "chatroomId" in contact;
|
||||||
onClick={() => onContactClick(contact)}
|
const avatar = contact.avatar || contact.chatroomAvatar;
|
||||||
className={`${styles.contractItem} ${contact.id === selectedContactId?.id ? styles.selected : ""}`}
|
const name = contact.conRemark || contact.nickname;
|
||||||
>
|
|
||||||
<div className={styles.avatarContainer}>
|
return (
|
||||||
<Avatar
|
<List.Item
|
||||||
src={contact.avatar || contact.chatroomAvatar}
|
key={contact.id}
|
||||||
icon={
|
onClick={() => onContactClick(contact)}
|
||||||
!(contact.avatar || contact.chatroomAvatar) && (
|
className={`${styles.contractItem} ${contact.id === selectedContactId?.id ? styles.selected : ""}`}
|
||||||
<span>{contact.nickname.charAt(0)}</span>
|
>
|
||||||
)
|
<div className={styles.avatarContainer}>
|
||||||
}
|
<Avatar
|
||||||
className={styles.avatar}
|
src={avatar}
|
||||||
/>
|
icon={!avatar && <span>{contact.nickname.charAt(0)}</span>}
|
||||||
</div>
|
className={styles.avatar}
|
||||||
<div className={styles.contractInfo}>
|
/>
|
||||||
<div className={styles.name}>
|
|
||||||
{contact.conRemark || contact.nickname}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className={styles.contractInfo}>
|
||||||
</List.Item>
|
<div className={styles.name}>{name}</div>
|
||||||
);
|
{isGroup && <div className={styles.groupInfo}>群聊</div>}
|
||||||
|
</div>
|
||||||
|
</List.Item>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// 初始化分页数据
|
// 初始化分页数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -188,7 +206,21 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.contractListSimple}>
|
<div className={styles.contractListSimple}>
|
||||||
{newContractList && newContractList.length > 0 ? (
|
{searchKeyword.trim() ? (
|
||||||
|
// 搜索模式:直接显示搜索结果列表
|
||||||
|
<>
|
||||||
|
<div className={styles.header}>搜索结果</div>
|
||||||
|
<List
|
||||||
|
className={styles.list}
|
||||||
|
dataSource={searchResults}
|
||||||
|
renderItem={renderContactItem}
|
||||||
|
/>
|
||||||
|
{searchResults.length === 0 && (
|
||||||
|
<div className={styles.noResults}>未找到匹配的联系人</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : newContractList && newContractList.length > 0 ? (
|
||||||
|
// 正常模式:显示分组
|
||||||
<Collapse
|
<Collapse
|
||||||
className={styles.groupCollapse}
|
className={styles.groupCollapse}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
@@ -196,11 +228,12 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
|||||||
items={getCollapseItems()}
|
items={getCollapseItems()}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
// 备用模式:显示传入的联系人列表
|
||||||
<>
|
<>
|
||||||
<div className={styles.header}>全部好友</div>
|
<div className={styles.header}>全部联系人</div>
|
||||||
<List
|
<List
|
||||||
className={styles.list}
|
className={styles.list}
|
||||||
dataSource={contracts as ContractData[]}
|
dataSource={contracts}
|
||||||
renderItem={renderContactItem}
|
renderItem={renderContactItem}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -131,6 +131,71 @@ export const useCkChatStore = createPersistStore<CkChatState>(
|
|||||||
return cachedResult;
|
return cachedResult;
|
||||||
};
|
};
|
||||||
})(),
|
})(),
|
||||||
|
// 搜索好友和群组的新方法 - 从本地数据库查询并返回扁平化的搜索结果
|
||||||
|
searchContactsAndGroups: (() => {
|
||||||
|
let cachedResult: (ContractData | weChatGroup)[] = [];
|
||||||
|
let lastKfSelected: number | null = null;
|
||||||
|
let lastSearchKeyword: string = "";
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
const state = useCkChatStore.getState();
|
||||||
|
|
||||||
|
// 检查是否需要重新计算缓存
|
||||||
|
const shouldRecalculate =
|
||||||
|
lastKfSelected !== state.kfSelected ||
|
||||||
|
lastSearchKeyword !== state.searchKeyword;
|
||||||
|
|
||||||
|
if (shouldRecalculate) {
|
||||||
|
if (state.searchKeyword.trim()) {
|
||||||
|
const keyword = state.searchKeyword.toLowerCase();
|
||||||
|
|
||||||
|
// 从本地数据库查询联系人数据
|
||||||
|
let allContacts: ContractData[] = await contractService.findAll();
|
||||||
|
|
||||||
|
// 根据选中的客服筛选联系人
|
||||||
|
if (state.kfSelected !== 0) {
|
||||||
|
allContacts = allContacts.filter(
|
||||||
|
item => item.wechatAccountId === state.kfSelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地数据库查询群组数据
|
||||||
|
let allGroups: weChatGroup[] = await weChatGroupService.findAll();
|
||||||
|
|
||||||
|
// 根据选中的客服筛选群组
|
||||||
|
if (state.kfSelected !== 0) {
|
||||||
|
allGroups = allGroups.filter(
|
||||||
|
item => item.wechatAccountId === state.kfSelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索匹配的联系人
|
||||||
|
const matchedContacts = allContacts.filter(item => {
|
||||||
|
const nickname = (item.nickname || "").toLowerCase();
|
||||||
|
const conRemark = (item.conRemark || "").toLowerCase();
|
||||||
|
return nickname.includes(keyword) || conRemark.includes(keyword);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索匹配的群组
|
||||||
|
const matchedGroups = allGroups.filter(item => {
|
||||||
|
const nickname = (item.nickname || "").toLowerCase();
|
||||||
|
const conRemark = (item.conRemark || "").toLowerCase();
|
||||||
|
return nickname.includes(keyword) || conRemark.includes(keyword);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 合并搜索结果
|
||||||
|
cachedResult = [...matchedContacts, ...matchedGroups];
|
||||||
|
} else {
|
||||||
|
cachedResult = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
lastKfSelected = state.kfSelected;
|
||||||
|
lastSearchKeyword = state.searchKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedResult;
|
||||||
|
};
|
||||||
|
})(),
|
||||||
// 异步设置联系人分组列表
|
// 异步设置联系人分组列表
|
||||||
asyncNewContractList: async (data: any[]) => {
|
asyncNewContractList: async (data: any[]) => {
|
||||||
set({ newContractList: data });
|
set({ newContractList: data });
|
||||||
@@ -472,4 +537,6 @@ export const setSearchKeyword = (keyword: string) =>
|
|||||||
useCkChatStore.getState().setSearchKeyword(keyword);
|
useCkChatStore.getState().setSearchKeyword(keyword);
|
||||||
export const clearSearchKeyword = () =>
|
export const clearSearchKeyword = () =>
|
||||||
useCkChatStore.getState().clearSearchKeyword();
|
useCkChatStore.getState().clearSearchKeyword();
|
||||||
|
export const searchContactsAndGroups = () =>
|
||||||
|
useCkChatStore.getState().searchContactsAndGroups();
|
||||||
useCkChatStore.getState().getKfSelectedUser();
|
useCkChatStore.getState().getKfSelectedUser();
|
||||||
|
|||||||
Reference in New Issue
Block a user