@@ -295,7 +295,7 @@ export default function ChatInput({ clear, form, questions, inputForm, wsUrl, on
{
form &&
(showWhenLocked || !inputLock.locked) && setFormShow(!formShow)}
>
}
@@ -338,7 +338,7 @@ export default function ChatInput({ clear, form, questions, inputForm, wsUrl, on
disabled={inputLock.locked}
onInput={handleTextAreaHeight}
placeholder={inputLock.locked ? inputLock.reason : t('chat.inputPlaceholder')}
- className="questionTextarea w-full resize-none border-none bg-transparent outline-none max-h-[160px]"
+ className="questionTextarea w-full resize-none border-none bg-transparent outline-none max-h-[160px] pr-[68px]"
// className={"resize-none py-4 pr-10 text-md min-h-6 max-h-[200px] scrollbar-hide dark:bg-[#2A2B2E] text-gray-800" + (form && ' pl-10')}
onKeyDown={(event) => {
if (event.key === "Enter" && !event.shiftKey) {
diff --git a/src/components/bs-comp/chatComponent/MessageBs.tsx b/src/components/bs-comp/chatComponent/MessageBs.tsx
index 7555d31..dcea3f8 100644
--- a/src/components/bs-comp/chatComponent/MessageBs.tsx
+++ b/src/components/bs-comp/chatComponent/MessageBs.tsx
@@ -39,6 +39,7 @@ const colorList = [
]
export default function MessageBs({ data, onUnlike = () => { }, flow_type, onSource }: { data: ChatMessageType, flow_type: any, onUnlike?: any, onSource?: any }) {
+// export default function MessageBs({ logo, data, onUnlike = () => { }, flow_type, onSource }: { logo: string, data: ChatMessageType, flow_type: any, onUnlike?: any, onSource?: any }) {
const avatarColor = colorList[
(data.sender?.split('').reduce((num, s) => num + s.charCodeAt(), 0) || 0) % colorList.length
]
diff --git a/src/components/bs-comp/chatComponent/MessageUser.tsx b/src/components/bs-comp/chatComponent/MessageUser.tsx
index 99cb0e8..c718888 100644
--- a/src/components/bs-comp/chatComponent/MessageUser.tsx
+++ b/src/components/bs-comp/chatComponent/MessageUser.tsx
@@ -7,7 +7,8 @@ import robotU from "../../../assets/robotU.png";
import btnEdit from "../../../assets/chat/btn-edit.png";
import btnReSend from "../../../assets/chat/btn-reSend.png";
-export default function MessageUser({ useName, data }: { data: ChatMessageType }) {
+export default function MessageUser({ useName = 'xxx', data }: {useName: string, data: ChatMessageType }) {
+// export default function MessageUser({ useName, data }: { data: ChatMessageType }) {
const msg = data.message[data.chatKey]
const { appConfig } = useContext(locationContext)
diff --git a/src/components/bs-comp/selectComponent/LabelSelect.tsx b/src/components/bs-comp/selectComponent/LabelSelect.tsx
new file mode 100644
index 0000000..460b0e7
--- /dev/null
+++ b/src/components/bs-comp/selectComponent/LabelSelect.tsx
@@ -0,0 +1,200 @@
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/bs-ui/popover";
+import { useEffect, useMemo, useRef, useState } from "react";
+import { SearchInput } from "@/components/bs-ui/input";
+import { Checkbox } from "@/components/bs-ui/checkBox";
+import { Label } from "@/components/bs-ui/label";
+import { Pencil2Icon } from "@radix-ui/react-icons";
+import { Trash2 } from "lucide-react";
+import { Input } from "@/components/bs-ui/input";
+import { useToast } from "@/components/bs-ui/toast/use-toast";
+import { useTranslation } from "react-i18next";
+import { bsConfirm } from "@/components/bs-ui/alertDialog/useConfirm";
+import { PlusIcon } from "@radix-ui/react-icons";
+import { useContext } from "react";
+import { userContext } from "@/contexts/userContext";
+import {
+ createLabelApi, updateLabelApi,
+ createLinkApi, deleteLinkApi,
+ deleteLabelApi
+} from "@/controllers/API/label";
+import { captureAndAlertRequestErrorHoc } from "@/controllers/request";
+import biaoqianBian from "../../../assets/npc/biaoqian-bian.png"
+import biaoqianDel from "../../../assets/npc/biaoqian-del.png"
+
+export enum UPDATETYPE {
+ DELETELINK = 'deleteLink',
+ CREATELINK = 'createLink',
+ UPDATENAME = 'updateName',
+ CREATELABEL = 'createLabel',
+ DELETELABEL = 'deleteLabel'
+}
+
+export default function LabelSelect({ labels, all, children, resource, onUpdate }) {
+ const [open, setOpen] = useState(false)
+ const [data, setData] = useState([])
+ const { user } = useContext(userContext)
+ const dataRef = useRef([])
+ const { message } = useToast()
+ const { t } = useTranslation()
+
+ useEffect(() => {
+ const newData = all.map(d => {
+ const res = labels.find(l => l.value === d.value)
+ return res ? { ...d, selected: true } : d
+ })
+ dataRef.current = newData
+ setData(newData)
+ }, [all])
+
+ const handleEdit = (id) => {
+ setData(pre => pre.map(d => ({ ...d, edit: d.value === id })))
+ }
+
+ const handleChecked = (id) => {
+ const type = resource.type === 'assist' ? 3 : 2
+ setData(pre => {
+ const newData = pre.map(d => d.value === id ? { ...d, selected: !d.selected } : d)
+ const cur = newData.find(d => d.value === id)
+ captureAndAlertRequestErrorHoc(
+ (cur.selected ? createLinkApi(id, resource.id, type) : deleteLinkApi(id, resource.id, type)).then(() => {
+ onUpdate({
+ type: cur.selected ? UPDATETYPE.CREATELINK : UPDATETYPE.DELETELINK,
+ data: cur
+ })
+ })
+ )
+ return newData
+ })
+ }
+
+ const nameRef = useRef('')
+ const handleChange = (e, id) => {
+ nameRef.current = id ? dataRef.current.find(d => d.value === id).label : ''
+ setData(pre => pre.map(d => d.value === id ? { ...d, label: e.target.value } : d))
+ }
+
+ const errorRestName = (preName, id) => { //错误发生回退初值
+ preName
+ ? setData(pre => pre.map(d => d.value === id ? { ...d, label: nameRef.current } : d))
+ : setData(pre => pre.filter(d => d.value))
+ }
+
+ const handleSave = async (e, id) => {
+ if (e.key === 'Enter') {
+ setData(pre => pre.map(d => d.value === id ? { ...d, edit: false } : d))
+ const label = data.find(d => d.value === id)
+ if (label.label.length > 10) {
+ errorRestName(nameRef.current, id)
+ return message({ title: t('prompt'), variant: 'warning', description: t('tag.labelMaxLength') })
+ }
+ const err = await captureAndAlertRequestErrorHoc(updateLabelApi(id, label.label).then((res: any) => {
+ setData(pre => {
+ const newData = pre.map(d => d.value ? d : { ...d, label: res.name, value: res.id })
+ dataRef.current = newData
+ return newData
+ })
+ onUpdate({
+ type: UPDATETYPE.UPDATENAME,
+ data: label
+ })
+ return message({ title: t('prompt'), variant: 'success', description: id ? t('updateSuccess') : t('createSuccess') })
+ }))
+ if (!err) {
+ errorRestName(nameRef.current, id)
+ }
+ }
+ }
+
+ const handleDelete = (label) => {
+ bsConfirm({
+ title: t('prompt'),
+ desc: t('tag.confirmDeleteLabel', { label: label.label }),
+ okTxt: "确认",
+ onOk(next) {
+ captureAndAlertRequestErrorHoc(deleteLabelApi(label.value).then(() => {
+ onUpdate({
+ type: UPDATETYPE.DELETELABEL,
+ data: label
+ })
+ message({ title: t('prompt'), variant: 'success', description: t('deleteSuccess') })
+ }))
+ next()
+ }
+ })
+ }
+
+ const handleOpenChange = (b) => { // 可用于整体保存
+ setOpen(b)
+ setData(pre => pre.map(d => ({ ...d, edit: false })))
+ }
+
+ const [keyword, setKeyword] = useState('')
+ const handleSearch = (e) => {
+ const key = e.target.value
+ setKeyword(key)
+ const newData = dataRef.current.filter(d => d.label.toUpperCase().includes(key.toUpperCase()))
+ setData(newData)
+ }
+
+ const handleAdd = () => {
+ if (keyword.length > 10) {
+ return message({ title: t('prompt'), variant: 'warning', description: t('tag.labelMaxLength') })
+ }
+ createLabelApi(keyword).then((res: any) => {
+ const addItem = { label: res.name, value: res.id, edit: false, selected: false }
+ dataRef.current = [addItem, ...dataRef.current]
+ setData([addItem])
+ onUpdate({
+ type: UPDATETYPE.CREATELABEL,
+ data: res.name
+ })
+ })
+ }
+
+ const showAdd = useMemo(() => {
+ if (data.length === 1 && data[0].label === keyword) {
+ return false
+ }
+ return true
+ }, [data])
+
+ return
+
+ {children}
+
+ e.stopPropagation()}>
+
+ {
+ if (e.key === 'Enter') {
+ (!data.length && user.role === 'admin') ? handleAdd() : null
+ }
+ }} />
+
+
+ {data.map(d =>
+
+ handleChecked(d.value)} />
+ {
+ d.edit
+ ? handleChange(e, d.value)}
+ onKeyDown={(e) => handleSave(e, d.value)} />
+ :
+ }
+
+ {user.role === 'admin' &&
+

handleEdit(d.value)} className="w-[14px] cursor-pointer"/>
+

handleDelete(d)} className="w-[14px] ml-[14px] cursor-pointer"/>
+ {/*
handleEdit(d.value)} /> */}
+ {/* handleDelete(d)} className="text-gray-600 cursor-pointer" /> */}
+ }
+
)}
+ {(showAdd && keyword != '' && user.role === 'admin') &&
+ 创建标签
+
}
+
+
+
+}
diff --git a/src/components/bs-comp/sheets/SkillChatSheet.tsx b/src/components/bs-comp/sheets/SkillChatSheet.tsx
index cf14c32..3477069 100644
--- a/src/components/bs-comp/sheets/SkillChatSheet.tsx
+++ b/src/components/bs-comp/sheets/SkillChatSheet.tsx
@@ -1,7 +1,7 @@
import { Badge } from "@/components/bs-ui/badge";
import { Button } from "@/components/bs-ui/button";
import { getChatOnlineApi } from "@/controllers/API/assistant";
-import { useEffect, useMemo, useRef, useState } from "react";
+import { useContext, useEffect, useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { SearchInput } from "../../bs-ui/input";
import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "../../bs-ui/sheet";
@@ -19,40 +19,57 @@ import zidingyi1 from "../../../assets/npc/zidingyi1.png";
import zidingyi2 from "../../../assets/npc/zidingyi2.png";
import npcIcon from "../../../assets/npc/npcIcon.png";
import nengliIcon from "../../../assets/npc/nengliIcon.png";
+import biaoqianPaixu from "../../../assets/chat/biaoqian-paixu.png";
import { useDebounce } from "@/util/hook";
import LoadMore from "../loadMore";
+import { userContext } from "@/contexts/userContext";
+import { getHomeLabelApi } from "@/controllers/API/label";
+import MarkLabel from "@/pages/ChatAppPage/components/MarkLabel";
export default function SkillChatSheet({ children, onSelect }) {
- const [open, setOpen] = useState(false)
-
const { t } = useTranslation()
-
+ const { user } = useContext(userContext)
+ const chatListRef = useRef([])
const navigate = useNavigate()
+ const [labels, setLabels] = useState([])
+ const [open, setOpen] = useState(false)
+ const pageRef = useRef(1)
+ const [options, setOptions] = useState
([])
+ const searchRef = useRef('')
+ const [flag, setFlag] = useState(null) // 解决筛选之后再次发起请求覆盖筛选数据
+
const [keyword, setKeyword] = useState(' ')
const allDataRef = useRef([])
+ const [markLabelOpen, setMarkLabelOpen] = useState(false)
- const pageRef = useRef(1)
- const searchRef = useRef('')
- const [options, setOptions] = useState([])
const loadData = (more = false) => {
- open && getChatOnlineApi(pageRef.current, searchRef.current).then(res => {
- setOptions(opts => more ? [...opts, ...res] : res)
+ getChatOnlineApi(pageRef.current, searchRef.current, -1).then((res: any) => {
+ setFlag(true)
+ chatListRef.current = res
+ setOptions(more ? [...options, ...res] : res)
})
}
- const debounceLoad = useDebounce(loadData, 600, false)
+ // useEffect(() => {
+ // // open && getChatOnlineApi().then(res => {
+ // // allDataRef.current = res
+ // // setKeyword('')
+ // // })
+ // // setKeyword(' ')
+ // pageRef.current = 1
+ // searchRef.current = ''
+ // loadData()
+ // }, [open])
useEffect(() => {
- // open && getChatOnlineApi().then(res => {
- // allDataRef.current = res
- // setKeyword('')
- // })
- // setKeyword(' ')
- pageRef.current = 1
- searchRef.current = ''
- loadData()
- }, [open])
+ debounceLoad()
+ getHomeLabelApi().then((res: any) => {
+ setLabels(res.map(d => ({ label: d.name, value: d.id, selected: true })))
+ })
+ }, [])
+
+ const debounceLoad = useDebounce(loadData, 600, false)
// const options = useMemo(() => {
// return allDataRef.current.filter(el => el.name.toLowerCase().includes(keyword.toLowerCase()))
@@ -64,9 +81,26 @@ export default function SkillChatSheet({ children, onSelect }) {
debounceLoad()
}
- const handleLoadMore = () => {
+ const handleClose = async (bool) => {
+ const newHome = await getHomeLabelApi()
+ // @ts-ignore
+ setLabels(newHome.map(d => ({ label: d.name, value: d.id, selected: true })))
+ setMarkLabelOpen(bool)
+ }
+
+ const [chooseId, setChooseId] = useState() // 筛选项样式变化
+ const handleTagSearch = (id) => {
+ setChooseId(id)
+ setFlag(false)
+ pageRef.current = 1
+ getChatOnlineApi(pageRef.current, '', id).then((res: any) => {
+ setOptions(res)
+ })
+ }
+
+ const handleLoadMore = async () => {
pageRef.current++
- loadData(true)
+ await debounceLoad(true)
}
const render = (item: any) => (
@@ -109,13 +143,31 @@ export default function SkillChatSheet({ children, onSelect }) {
选择对话
选择一个您想使用的上线NPC或能力
{/* setKeyword(e.target.value)} /> */}
-
+
+
+ {/* @ts-ignore */}
+ {user.role === 'admin' &&

setMarkLabelOpen(true)} />}
+ {/*
*/}
+
{ setChooseId(null); loadData(false) }}>全部
+ {
+ labels.map((l, index) => index <= 11 &&
+ //
+
handleTagSearch(l.value)}>{l.label}
)
+ }
+
+