Browse Source

功能完善

songxy 4 months ago
parent
commit
e001e9c638

+ 1 - 1
ais_search/web/public/config.js

@@ -19,7 +19,7 @@
     server: '/server',
     managerServer: 'https://natureai.zjugis.com/manager/server',
     chatServer: '/chat',
-    knowledgeServer: 'https://natureai.zjugis.com/llm',
+    knowledgeServer: 'https://zdzy.zrzyt.zj.gov.cn/aiServer',
     knowledgeDocUrl: 'http://127.0.0.1:8511/knowledge_base/download_doc?knowledge_base_name=policy&file_name=',
     knowledgeDocUrlProxy: 'https://natureai.zjugis.com/doc/portal/knowledge_base/download_doc/',
     landMarketUrl: 'https://natureai.zjugis.com/subscribe/',

+ 0 - 21
ais_search/web/src/api/ai-search-api.js

@@ -1,21 +0,0 @@
-
-export const queryQuestionType = (question) => {
-
-  const myHeaders = new Headers();
-  myHeaders.append("Content-Type", "application/json");
-
-  const raw = JSON.stringify({
-    "query": question
-  });
-
-  const requestOptions = {
-    method: "POST",
-    headers: myHeaders,
-    body: raw,
-    redirect: "follow"
-  };
-
-  return fetch(window.AppGlobalConfig.knowledgeServer + "/tools/function_check", requestOptions)
-    .then((response) => response.json())
-
-}

+ 3 - 10
ais_search/web/src/views/ai-search/ai-search copy.vue

@@ -511,7 +511,6 @@
   </div>
 </template>
 <script setup>
-import { queryQuestionType } from '@/api/ai-search-api';
 import { fetchEventSource } from '@microsoft/fetch-event-source';
 import PDFViewer from '@/components/pdf/PdfCanvas.vue';
 import WordViewer from '@/components/pdf/WordViewer.vue';
@@ -974,15 +973,9 @@ const ask = async (q, isFllow) => {
   question.value = q;
   open.value = false;
   showDoc.value = false;
-  const result = await queryQuestionType(q);
-  if (result?.data.function_flag === '否') {
-    askType.value = 'zcfg';
-    // activeTab.value = 'knowledge';
-    quest(isFllow);
-  } else {
-    askType.value = 'tdsc';
-    questLandMark();
-  }
+  askType.value = 'zcfg';
+  // activeTab.value = 'knowledge';
+  quest(isFllow);
 };
 
 const followAsk = () => {

+ 6 - 12
ais_search/web/src/views/ai-search/ai-search.vue

@@ -506,7 +506,6 @@
   </div>
 </template>
 <script setup>
-import { queryQuestionType } from '@/api/ai-search-api';
 import { fetchEventSource } from '@microsoft/fetch-event-source';
 import PDFViewer from '@/components/pdf/PdfCanvas.vue';
 import WordViewer from '@/components/pdf/WordViewer.vue';
@@ -815,6 +814,7 @@ const questLandMark = async () => {
   await fetchEventSource(window.AppGlobalConfig.landMarketUrl, {
     method: 'POST',
     openWhenHidden: true,
+    timeout: 300000,
     // redirect: 'follow',
     headers: {
       'Content-Type': 'application/json'
@@ -966,15 +966,9 @@ const ask = async (q, isFllow) => {
   question.value = q;
   open.value = false;
   showDoc.value = false;
-  const result = await queryQuestionType(q);
-  if (result?.data.function_flag === '否') {
-    askType.value = 'zcfg';
-    // activeTab.value = 'knowledge';
-    quest(isFllow);
-  } else {
-    askType.value = 'tdsc';
-    questLandMark();
-  }
+  askType.value = 'zcfg';
+  // activeTab.value = 'knowledge';
+  quest(isFllow);
 };
 
 const followAsk = () => {
@@ -1121,14 +1115,13 @@ const quest = async (isFllow) => {
     docs: []
   };
   activeIndex.value = 0;
-  await getQuestionKeyWords();
+  // await getQuestionKeyWords();
 
   if (activeTab.value === 'net') {
     questionUrl = '/chat/bing_chat';
   } else {
     questionUrl = '/chat/kb_chat';
   }
-  getRecommendedQuestion();
 
   const topKs = window?.AppGlobalConfig?.topKs || {
     0: 5,
@@ -1172,6 +1165,7 @@ const quest = async (isFllow) => {
   await fetchEventSource(window.AppGlobalConfig.knowledgeServer + questionUrl, {
     method: 'POST',
     openWhenHidden: true,
+    timeout: 300000,
     headers: {
       'Content-Type': 'application/json'
     },

+ 29 - 76
ais_search/web/src/views/document/FileUpload.vue

@@ -13,8 +13,6 @@
       :multiple="true"
       :maxCount="1"
       accept=".pdf"
-      @change="handleChange"
-      @drop="handleDrop"
       :beforeUpload="handleUpload"
     >
       <p class="ant-upload-drag-icon">
@@ -32,95 +30,50 @@
 import { ref, defineExpose } from "vue";
 import { InboxOutlined } from "@ant-design/icons-vue";
 import { message } from "ant-design-vue";
-import type { UploadChangeParam } from "ant-design-vue";
-import { useUserStore } from "@/stores";
-import axios from "axios";
-import { useRouter, useRoute } from "vue-router";
-const router = useRouter();
-const route = useRoute();
+import http from "@/utils/http";
 
+const props = defineProps<{
+  pid?: number
+}>();
+const emits = defineEmits<{
+  (e: 'close'):void
+}>()
 // 弹窗部分
 const open = ref<boolean>(false);
 const showModal = () => {
   open.value = true;
 };
-defineExpose({ showModal });
 
 // 文件上传部分
 const fileList = ref<any[]>([]);
-const handleChange = (info: UploadChangeParam) => {
-  const status = info.file.status;
-  if (status === "done") {
-    message.success(`“${info.file.name}” 文件上传成功.`);
-  } else if (status === "error") {
-    message.error(`“${info.file.name}” 文件上传失败.`);
-  }
-};
-const handleDrop = (e: DragEvent) => {
-  console.log(e);
-};
-
-const store: any = useUserStore();
-const userId = store?.user?.user?.id ?? "";
 const handleUpload = async (file: any) => {
+  if(props.id === null) return;
+  if(!file) return;
+  const sizeNum = parseFloat((file.size / 1024 / 1024).toFixed(2))
+  if(sizeNum > 50){
+    message.error("上传文件不能大于50MB!");
+    return;
+  }
+  const urlStr = '/ai/knowledge/file/create'
   const formData = new FormData();
-  formData.append("userId", userId); // 用户id
+  formData.append("parentId", props.pid)
   formData.append("file", file); // 文件对象
-
-  const cleanAxios = axios.create();
-  // 在线上请求才不会出错
-  const uploadUrl =
-    (window as any).AppGlobalConfig.onlineAddress +
-    "/server/file/library/user/upload/file";
-  try {
-    // 调用接口上传文件
-    message.success("文件上传中,请稍等 ...");
-    const response = await cleanAxios.post(uploadUrl, formData, {
-      headers: {
-        "Content-Type": "multipart/form-data",
-      },
-    });
-
-    console.log("response", response);
-    // 上传成功处理
-    if (response.status === 200 && response.data.success) {
-      fileList.value = [
-        {
-          uid: file.uid, // 保留唯一标识
-          name: file.name, // 文件名
-          status: "done", // 上传状态
-          url: response.data.data, // 服务器返回的文件地址
-        },
-      ];
-      message.success("文件上传成功!即将为您跳转到我的上传页面 ...");
-      const timer = setTimeout(() => {
-        // 清空文件列表
-        fileList.value = [];
+  formData.append("name", file.name); // 用户id
+  formData.append("size", file.size);
+  formData.append("type", file.type);
+  http.post(urlStr, formData).then((result) => {
+    if (result.data) {
+      message.success("文件导入成功!");
+      const timer = setTimeout(()=>{
         open.value = false;
-        if (route.name === "myUploadFiles") {
-          router
-            .replace({ path: "/home", query: { t: Date.now() } })
-            .then(() => {
-              router.replace({ name: "myUploadFiles" });
-            });
-        } else {
-          // 跳转到 "myUploadFiles" 页面
-          router.push({ name: "myUploadFiles" });
-        }
-        clearTimeout(timer);
-      }, 1500);
+        emits('close')
+        clearTimeout(timer)
+      }, 1500)
     } else {
-      message.error("文件上传失败!");
-      fileList.value = [];
+      message.error("文件导入失败,请稍后重试!");
     }
-  } catch (error) {
-    // 错误处理
-    message.error("文件上传失败,请稍后重试!");
-    fileList.value = [];
-    console.error(error);
-  }
-  // 返回 false,阻止默认上传行为
+  });
   return false;
 };
+defineExpose({ showModal });
 </script>
-<style scoped lang="scss"></style>

+ 1 - 3
ais_search/web/src/views/document/MoveFiles.vue

@@ -21,7 +21,7 @@
     >
       <template #icon="{ key, selected }">
         <MyIcon
-          :icon="iconTypeName.dir"
+          icon="icon-wjj"
           size="18"
           style="margin-right: 5px; margin-top: 2px"
         />
@@ -37,7 +37,6 @@ import { ref, onMounted, watch, toRefs, PropType } from "vue";
 import { message } from "ant-design-vue";
 import MyIcon from "@/components/myIcon/index.vue";
 import { getAllFolder } from "./http";
-import { iconTypeName } from "./config";
 import { moveFiles } from "./http";
 const props = defineProps({
   ids: {
@@ -78,7 +77,6 @@ watch(
 const initModel = () => {
   selectedKeys.value = [];
   getAllFolder().then((res) => {
-    console.log(res);
     treeData.value[0].children = res.data.map((item: any) => {
       return {
         title: item.fileName,

+ 0 - 44
ais_search/web/src/views/document/config.ts

@@ -1,44 +0,0 @@
-// 图标对应图标库id
-export const iconTypeName: any = {
-  dir: "icon-wjj",
-  pdf: "icon-wenjianleixing-suolvetu-PDFwendang",
-  word: "icon-word",
-  text: "icon-txt",
-  ppt: "icon-ppt",
-};
-
-// 表格列
-export const columns = [
-  {
-    title: "文档名称",
-    dataIndex: "fileName",
-    key: "fileName",
-    width: 560
-  },
-  {
-    title: "文档类型",
-    dataIndex: "fileBizline",
-    key: "fileBizline",
-  },
-  {
-    title: "文档大小",
-    dataIndex: "fileFormat",
-    key: "fileFormat",
-    sorter: {
-      compare: (a, b) => a.math - b.math,
-      multiple: 2,
-    },
-  },
-  {
-    title: "创建时间",
-    dataIndex: "createTime",
-    key: "createTime",
-    align: "center",
-  },
-  {
-    title: "操作",
-    key: "action",
-    width: 250,
-    align: "center",
-  },
-];

+ 159 - 107
ais_search/web/src/views/document/index.vue

@@ -24,7 +24,6 @@
               :icon="h(FolderAddOutlined)"
               style="margin-left: 15px; height: 36px"
               @click="openNewFolderModel = true"
-              v-if="!clickFileDetail"
               >新建文件夹</a-button
             >
             <a-button
@@ -46,11 +45,11 @@
               v-model:value="searchValue"
               placeholder="搜索文档"
               style="width: 280px; height: 40px"
-              @pressEnter="getDataSource({ searchKey: searchValue })"
+              @pressEnter="searchHandle"
             >
               <template #suffix>
                 <SearchOutlined
-                  @click="getDataSource({ searchKey: searchValue })"
+                  @click="searchHandle"
                   style=""
                   class="search-icon"
                 />
@@ -69,23 +68,23 @@
             :pagination="false"
           >
             <template #bodyCell="{ column, record }">
-              <template v-if="column.dataIndex === 'fileName'">
+              <template v-if="column.dataIndex === 'name'">
                 <div class="editable-cell">
-                  <div v-if="editableData[record.key]">
-                    <a-input v-model:value="editableData[record.key].fileName" @pressEnter="save(record.key)" />
+                  <div v-if="editableData[record.id] && !record.type">
+                    <a-input v-model:value="editableData[record.id].name" @pressEnter="updateHandle(record.id)" />
                   </div>
                   <div v-else class="editable-cell-text-wrapper">
                     <div
-                      v-if="record.sign == 'dir'"
+                      v-if="!record.type"
                       class="name-box"
                       @click="jumpToFile(record)"
                     >
-                      <MyIcon :icon="iconTypeName.dir" size="18" />
-                      <span>{{ record.fileName }}</span>
+                      <MyIcon icon="icon-wjj" size="18" />
+                      <span>{{ record.name }}</span>
                     </div>
                     <div v-else class="name-box" @click="showFileDetail(record)">
-                      <MyIcon :icon="iconTypeName[record.fileType]" size="18" />
-                      <span>{{ record.fileName }}</span>
+                      <MyIcon icon="icon-wenjianleixing-suolvetu-PDFwendang" size="18" />
+                      <span>{{ record.name }}</span>
                     </div>
                   </div>
                 </div>
@@ -101,7 +100,7 @@
                   :icon="h(DownloadOutlined)"
                   style="margin-right: 15px"
                   @click="
-                    record.sign !== 'dir'
+                    record.type
                       ? downloadFile(record)
                       : downloadFiles([record.id])
                   "
@@ -119,7 +118,7 @@
                           type="link"
                           :icon="h(DeleteOutlined)"
                           style="color: #000"
-                          @click="moveFiles([record.id])"
+                          @click="deleteFiles(record.id)"
                           >刪除</a-button
                         >
                       </a-menu-item>
@@ -137,16 +136,17 @@
                           type="link"
                           :icon="h(VerticalAlignTopOutlined)"
                           style="color: #000"
-                          @click="topFile(record.id)"
+                          @click="topFileHandle(record)"
                           >置顶</a-button
                         >
                       </a-menu-item>
                       <a-menu-item>
                         <a-button
                           type="link"
+                          v-if="!record.type"
                           :icon="h(FormOutlined)"
                           style="color: #000"
-                          @click="editFolderName(record.key)"
+                          @click="editFolderName(record.id)"
                           >编辑</a-button
                         >
                       </a-menu-item>
@@ -158,7 +158,7 @@
           </a-table>
         </div>
       </div>
-      <a-modal v-model:open="openNewFolderModel" title="新建分组" @ok="newFolder">
+      <a-modal v-model:open="openNewFolderModel" title="新建分组" @ok="createFolder">
         <a-input
           style="margin-top: 15px; margin-bottom: 10px"
           v-model:value="folderName"
@@ -170,7 +170,7 @@
         :ids="moveFileIds"
         :closeModel="closeMoveFileModel"
       />
-      <FileUpload ref="userUploadFileRef" />
+      <FileUpload ref="userUploadFileRef" :pid="currentTabId" @close="closeHandle"/>
     </div>
   </div>
 </template>
@@ -180,6 +180,7 @@
  */
 import { cloneDeep } from 'lodash-es';
 import { h, ref, reactive, onMounted } from "vue";
+import http from "@/utils/http";
 import {
   FormOutlined,
   DeleteOutlined,
@@ -194,14 +195,8 @@ import HomeHeader from '@/views/home/components/HomeHeader.vue';
 import { message } from "ant-design-vue";
 import MyIcon from "@/components/myIcon/index.vue";
 import {
-  topDocs,
-  getDocList,
-  deleteDocs,
   downloadDocs,
-  madeNewFolder,
-  isRepeatFolder
 } from "./http";
-import { columns, iconTypeName } from "./config";
 import MoveFileModel from "./MoveFiles.vue";
 import FileUpload from "./FileUpload.vue";
 import FileDetail from "./FileDetail.vue";
@@ -211,69 +206,104 @@ import dayjs from "dayjs";
 onMounted(() => {
   getDataSource();
 });
-const menuList = ref<{
-  name: string,
-  id: string,
-  checked: boolean
-}[]>([
+const menuList_old = JSON.parse(localStorage.getItem("_menuList")) || [
   {
     name: "全部",
-    id: '-1',
+    id: 0,
     checked: true
   }
-])
-const currentTabId = ref('-1')
+]
+const menuList = ref<{
+  name: string,
+  id: number,
+  checked: boolean
+}[]>(cloneDeep(menuList_old))
+const currentTabId = ref(parseInt(localStorage.getItem("_currentTabId") as string) || 0)
 const tabClickHandle = (item) => {
   if (currentTabId.value === item['id']) return;
-  if (item['id'] === '-1') {
-    menuList.value = [{
-      name: "全部",
-      id: '-1',
-      checked: true
-    }]
-    getDataSource();
+  currentTabId.value = item['id']
+  item['checked'] = true;
+  if (item['id'] === 0) {
+    menuList.value = [item];
   } else {
-    getDataSource({
-      id: item.id,
-    });
+    let end = 0;
+    for (let i = 0; i < menuList.value.length; i++){
+      if (menuList.value[i].id === item.id) {
+        end = i;
+        break;
+      }
+    }
+    menuList.value = menuList.value.slice(0, end+1)
   }
+  localStorage.setItem("_currentTabId", currentTabId.value.toString())
+  localStorage.setItem("_menuList", JSON.stringify(menuList.value))
+  getDataSource();
 }
 // 切换目录
-const changeMenu = (fileName: any = null) => {
+const changeMenu = (data: any = null) => {
   // 切换目录时重置搜索内容和选中的文件
   searchValue.value = "";
   state.selectedRowKeys = [];
-
-  if (!fileName) {
-    // 清空选择打开的文件夹
-    clickFileDetail.value = null;
-    // 刷新列表
-    getDataSource();
-    return;
-  }
   menuList.value.forEach((item) => {
     item['checked'] = false;
   })
   menuList.value.push({
-    name: fileName,
-    id: '',
+    name: data.name,
+    id: data.id,
     checked: true,
   })
+  localStorage.setItem("_currentTabId", currentTabId.value.toString())
+  localStorage.setItem("_menuList", JSON.stringify(menuList.value))
 };
 
-// 获取数据
+// 表格列
+const columns = [
+  {
+    title: "文档名称",
+    dataIndex: "name",
+    key: "name",
+    width: 560
+  },
+  {
+    title: "文档类型",
+    dataIndex: "type",
+    key: "type",
+  },
+  {
+    title: "文档大小",
+    dataIndex: "size",
+    key: "size",
+    sorter: {
+      compare: (a, b) => a.size - b.size,
+      multiple: 2,
+    },
+  },
+  {
+    title: "创建时间",
+    dataIndex: "createTime",
+    key: "createTime",
+    align: "center",
+  },
+  {
+    title: "操作",
+    key: "action",
+    width: 250,
+    align: "center",
+  },
+];
 const searchValue = ref("");
 const dataSource = ref<any[]>([]);
-const getDataSource = (params = {}) => {
+const getDataSource = () => {
   // 重置选中的文件
   state.selectedRowKeys = [];
+  const urlStr = `/ai/knowledge/file/list`
   // 获取文档列表
-  getDocList(params).then((res) => {
-    if (res.success) {
-      dataSource.value = res.data.map((item: any) => ({
-        key: item.id,
-        ...item,
-      }));
+  http.get(urlStr, {
+    name: searchValue.value,
+    parentId: currentTabId.value
+  }).then((result) => {
+    if (result.data) {
+      dataSource.value = result.data;
     }
   });
 };
@@ -289,38 +319,37 @@ const state = reactive<{
 const onSelectChange = (selectedRowKeys: any[]) => {
   state.selectedRowKeys = selectedRowKeys;
 };
-
+const searchHandle = () => {
+  getDataSource()
+}
 // 点击进入文件夹
 const clickFileDetail = ref<null | any>(null);
 const jumpToFile = (data: any) => {
   clickFileDetail.value = data;
   currentTabId.value = data.id;
   // 触发目录切换的回调
-  changeMenu(data.fileName);
-  getDataSource({
-    id: data.id,
-  });
+  changeMenu(data);
+  getDataSource();
 };
 
 // 新建文件夹
-const openNewFolderModel = ref(false);
 const folderName = ref("");
-const newFolder = async () => {
-  const res = await isRepeatFolder(folderName.value);
-  if (!res.success) {
-    message.info("文件夹名称重复,请重新输入!");
-    return false;
-  }
-  const res2 = await madeNewFolder(folderName.value);
-  if (res2.success) {
-    message.success("文件夹新建成功!");
-    folderName.value = "";
-    // 刷新列表
-    getDataSource();
-    openNewFolderModel.value = false;
-  } else {
-    message.error("新建文件夹失败,请稍后重试!");
-  }
+const openNewFolderModel = ref(false);
+const createFolder = async () => {
+  const urlStr = '/ai/knowledge/file/create'
+  const formData = new FormData();
+  formData.append("name", folderName.value)
+  formData.append("parentId", currentTabId.value.toString());
+  http.post(urlStr, formData).then((result) => {
+    if (result.data) {
+      message.success("文件夹新建成功!");
+      getDataSource(currentTabId.value);
+      folderName.value = "";
+      openNewFolderModel.value = false;
+    } else {
+      message.error("新建文件夹失败,请稍后重试!");
+    }
+  });
 };
 
 // 下载(单文件下载)
@@ -345,6 +374,9 @@ const downloadFile = async (data: any) => {
 // 上传文档
 const userUploadFileRef = ref<any>(null);
 const uploadFiles = () => userUploadFileRef.value.showModal();
+const closeHandle = () => {
+  getDataSource();
+}
 // 多文件打包下载
 const downloadFiles = async (ids: any[] = []) => {
   message.success("正在为你下载文件,请稍等 ...");
@@ -354,19 +386,53 @@ const downloadFiles = async (ids: any[] = []) => {
     message.error("下载失败,请稍后重试!");
   }
 };
+//文件夹编辑
 const editableData = reactive({});
-const save = (key: string) => {
-  const item = dataSource.value.filter(item => key === item.key)[0];
-  Object.assign(item, editableData[key]);
-  delete editableData[key];
-};
-//编辑文件夹名称
-const editFolderName = (key) => {
-  editableData[key] = cloneDeep(dataSource.value.filter(item => key === item.key)[0]);
+const editFolderName = (id) => {
+  editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
 }
+const updateHandle = (id: string) => {
+  const item = dataSource.value.filter(item => id === item.id)[0];
+  Object.assign(item, editableData[id]);
+  const urlStr = `/ai/knowledge/file/update`
+  const sendData = {
+    ...item
+  }
+  http.post(urlStr, sendData).then((result) => {
+    if (result.data) {
+      message.success("重命名成功!");
+    }
+  });
+  delete editableData[id];
+};
+
+// 置顶
+const topFileHandle = async (item) => {
+  const urlStr = `/ai/knowledge/file/update`
+  const sendData = {
+    ...item
+  }
+  sendData['sort'] = 0
+  http.post(urlStr, sendData).then((result) => {
+    if (result.data) {
+      message.success("置顶成功!");
+      getDataSource();
+    } else {
+      message.error("置顶失败,请稍后重试!");
+    }
+  });
+};
 //刪除
-const deleteFiles = () => {
-  
+const deleteFiles = (id) => {
+  const urlStr = `/ai/knowledge/file/delete?id=${id}`
+  http.get(urlStr).then((result) => {
+    if (result.data) {
+      message.success("删除成功!");
+      getDataSource();
+    } else {
+      message.error("删除失败,请稍后重试!");
+    }
+  });
 }
 // 移动:最外层文件禁止多选移动,文件夹类型禁止移动
 const moveFileModel = ref(false);
@@ -384,9 +450,7 @@ const closeMoveFileModel = () => {
 const refreshList = () => {
   if (clickFileDetail.value) {
     // 关闭弹窗后刷新列表
-    getDataSource({
-      id: clickFileDetail.value.id,
-    });
+    getDataSource();
     // 刷新目录
     changeMenu(clickFileDetail.value.fileName);
   } else {
@@ -397,18 +461,6 @@ const refreshList = () => {
   }
 };
 
-// 置顶
-const topFile = async (id: string) => {
-  const res = await topDocs(id);
-  if (res.success) {
-    message.success("置顶成功!");
-    // 刷新列表
-    refreshList();
-  } else {
-    message.error("置顶失败,请稍后重试!");
-  }
-};
-
 // 跳到文件详情页面
 const showFileDetail = (data: any) => {
   clickFileDetail.value = {

+ 3 - 3
ais_search/web/vite.config.js

@@ -41,8 +41,8 @@ export default defineConfig({
     cors: true,
     proxy: {
       '/server': {
-          target: 'http://121.40.148.47:8531/server',
-          // target: 'http://localhost:7503/server',
+          // target: 'http://121.40.148.47:8531/server',
+          target: 'http://localhost:9999/',
           changeOrigin: true,
           rewrite: function (path) { return path.replace(/^\/server/, ''); }
       },
@@ -52,7 +52,7 @@ export default defineConfig({
       //   rewrite: (path) => path.replace(/^\/server/, '')
       // },
       '/chat': {
-        target: 'http://lq.lianqiai.cn:20333/chat',
+        target: 'https://zdzy.zrzyt.zj.gov.cn/aiServer/chat',
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/chat/, '')
       },