123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /**
- * 知识库项目编辑
- */
- import { Text, View } from "@tarojs/components";
- import PageCustom from "@/components/page-custom/index";
- import NavBarNormal from "@/components/NavBarNormal/index";
- import BottomBar from "@/components/BottomBar";
- import IconQ from "@/components/icon/IconQ";
- import IconA from "@/components/icon/IconA";
- import IconPlusColor14 from "@/components/icon/IconPlusColor14";
- import IconALink from "@/components/icon/IconALink";
- import IconDeleteGray16 from "@/components/icon/IconDeleteGray16";
- import { useEffect, useRef, useState } from "react";
- import IconAImage from "@/components/icon/IconAImage";
- import WemetaTextarea from "@/components/wemeta-textarea";
- import WemetaInput from "@/components/wemeta-input";
- import UploaderGrid from '@/components/UploaderGrid'
- import type { TMediaType } from "@/types/index";
- import { uploadFile } from "@/utils/http";
- import { EUploadFileScene } from "@/consts/enum";
- import Taro, { useRouter } from "@tarojs/taro";
- import { isSuccess } from "@/utils";
- import { editVisitorDislikeAnswer, getVisitorMessagesByMsgId } from "@/service/visitor";
- import { TVisitorChat } from "@/types/visitor";
- import { EContentType, TMessageBodyContent } from "@/types/bot";
- type TFormdata = {content:string, correctionAnswer: string, links: string[], mediaList: TMediaType[]}
- export default function Index() {
- const router = useRouter()
- const { msgId, visitorId, agentId } = router.params as {msgId: string, visitorId: string, agentId: string}
-
-
- const [visitorQ, setQVisitor] = useState<TVisitorChat|null>(null)
- const [visitor, setVisitor] = useState<TVisitorChat|null>(null)
- const [isDislike, setIsDislike] = useState(false)
- const [formData, setFormData] = useState<TFormdata>(
- {
- content: '',
- correctionAnswer: '',
- links: [],
- mediaList: [] //{fileType: 'image',url: 'https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png'}
- }
- );
- const handleInput = (value: string) => {
- setFormData({
- ...formData,
- content: value,
- });
- };
- const handleValueAInput = (value: string) => {
- setFormData({
- ...formData,
- correctionAnswer: value,
- });
- };
- // 添加链接
- const addLink = () => {
- setFormData({
- ...formData,
- links: [...formData.links, ""],
- });
- };
- // 删除链接
- const removeLink = (e, index) => {
- e.stopPropagation();
- const newLinks = [...formData.links];
- newLinks.splice(index, 1);
- setFormData({
- ...formData,
- links: newLinks,
- });
- };
- // 更新单个链接
- const handleLinkChange = (index:number, value: string) => {
- const newLinks = [...formData.links];
- newLinks[index] = value;
- setFormData({
- ...formData,
- links: newLinks,
- });
- };
- const handleDeleteMedia = (index:number) => {
- setFormData(prev => ({
- ...prev,
- mediaList: prev.mediaList.filter((_, i) => i !== index)
- }));
- };
- const handleSubmit = async () => {
- if(!msgId || !visitorId || !visitor){
- return
- }
- const dataToSubmit = {
- questions : visitorQ?.content ? [visitorQ?.content] : [],
- visitorId: visitorId,
- answer: formData.correctionAnswer,
- content: formData.content,
- agentId: agentId,
- msgId: msgId,
- correctionId: visitor.correctionId,
- links: formData.links.filter(link => link.trim() !== ''),
- pics: formData.mediaList.map( item => item.url),
- }
- console.log(dataToSubmit)
-
- const {status} = await editVisitorDislikeAnswer(dataToSubmit)
- if(isSuccess(status)){
- Taro.showToast({title: '保存成功', icon: 'success'})
- }
- }
- const getDetail = async () => {
- const {status, data} = await getVisitorMessagesByMsgId({
- msgId,
- visitorId,
- size: 2,
- })
-
- if(isSuccess(status), data[0]){
- const _visitor = data[0]
- setVisitor(_visitor)
- if(data[1]){
- setQVisitor(data[1])
- }
- setIsDislike(_visitor.isDislike)
-
- let content = _visitor.content
- let links = _visitor.correctionLinks ?? []
- let pics = _visitor.correctionPics ?? []
- // 特殊处理消息内容
- if(_visitor.contentType === EContentType.AiseekQA){
- try{
- const json = JSON.parse(_visitor.content) as TMessageBodyContent
- content = json.answer.text
- links = json.answer.payload.links
- pics = json.answer.payload.pics
- }catch(e){}
- }
- setFormData({
- content: content,
- correctionAnswer: _visitor.correctionAnswer,
- links: links,
- mediaList: pics?.map( pic => {
- return {fileType: 'image', url: pic}
- }) ?? [],
- })
- }
- }
- const handleChooseMedia = ()=> {
- Taro.chooseMedia({
- count: 10,
- mediaType: ["image"],
- sourceType: ["album", "camera"],
- async success(r) {
- // const tempFiles = r.tempFiles;
- for (const tempFile of r.tempFiles){
- const result = await uploadFile(tempFile.tempFilePath, EUploadFileScene.OTHER)
- if(result?.publicUrl){
- setFormData(prev => {
- return {...prev, mediaList: [{fileType:'image', url: result.publicUrl}, ...prev.mediaList]}
- })
- }
- }
- }
- })
- }
- useEffect(()=> {
- if(visitorId && msgId){
- getDetail()
- }
-
- }, [visitorId, msgId])
-
- return (
- <PageCustom>
- <NavBarNormal scrollFadeIn>{isDislike ? '纠错' : '编辑'}</NavBarNormal>
- <View className="w-full pb-120">
- <View className="p-16">
- {isDislike && <View className="text-gray-45 text-14 text-center py-8">修改后的问答将存入知识库,持续训练提升您的智能体</View>}
- <View className="flex flex-col gap-16">
- <View className="flex flex-col">
- <View className="flex items-start gap-8 mb-6">
- <View className="flex-center h-28">
- <IconQ />
- </View>
- <View className="flex-1 text-14 leading-28">提问</View>
- </View>
- <View className="p-16 bg-white rounded-12">
- {visitorQ?.content}
- </View>
- </View>
- <View className="flex flex-col">
- <View className="flex items-start gap-8 mb-6">
- <View className="flex-center h-28">
- <IconA />
- </View>
- <View className="flex-1 text-14 leading-28">原回答</View>
- </View>
- <View className="">
- <WemetaTextarea
- value={formData.content}
- disabled
- onInput={handleInput}
- />
- </View>
- </View>
- {/* 回答 */}
- <View className="flex flex-col">
- <View className="flex items-start gap-8 mb-6">
- <View className="flex-center h-28">
- <IconA />
- </View>
- <View className="flex-1 text-14 leading-28">纠错回答</View>
- </View>
- <View>
- <WemetaTextarea
- value={formData.correctionAnswer}
- onInput={handleValueAInput}
- placeholder="描述正确的回答"
- />
- </View>
- </View>
- {/* 链接 */}
- <View className="flex flex-col">
- <View className="flex items-start gap-8 mb-6">
- <View className="flex-center h-28">
- <IconALink />
- </View>
- <View className="flex-1 text-14 leading-28">链接</View>
- <View className="flex-center px-8 gap-4" onClick={addLink}>
- <IconPlusColor14 />
- <View className="text-primary">新增</View>
- </View>
- </View>
- <View className="flex flex-col gap-8">
- {formData.links.map((link, index) => {
- return (
- <WemetaInput
- value={link}
- onInput={(value) => handleLinkChange(index, value)}
- suffix={() => (
- <View onClick={(e) => removeLink(e, index)}>
- <IconDeleteGray16 />
- </View>
- )}
- placeholder="请输入查看链接,支持长按粘贴..."
- />
- );
- })}
- </View>
- </View>
- {/* 图片 */}
- <View className="flex flex-col">
- <View className="flex items-start gap-8 mb-6">
- <View className="flex-center h-28">
- <IconAImage />
- </View>
- <View className="flex-1 text-14 leading-28">图片</View>
- </View>
- <UploaderGrid onNewUpload={handleChooseMedia} list = {formData.mediaList} onChange={()=> {}} onDelete={handleDeleteMedia} />
- </View>
-
- </View>
- </View>
- <BottomBar>
- <View className="button-rounded button-primary flex-1" onClick={handleSubmit}>保存</View>
- </BottomBar>
- </View>
- </PageCustom>
- );
- }
|