|
@@ -160,15 +160,14 @@
|
|
|
>
|
|
|
<div class="left-panel-content">
|
|
|
<span class="back_icon" @click="onBackHandle"></span>
|
|
|
+ <div class="title" @click="resetAnswer()">
|
|
|
+ {{ inputText }}
|
|
|
+ </div>
|
|
|
+ <div class="jsz" v-if="!showResult">
|
|
|
+ <Spin />
|
|
|
+ {{ hintText }}
|
|
|
+ </div>
|
|
|
<div v-for="(item, index) in hzData" :key="index">
|
|
|
- <div class="title" @click="resetAnswer(index)">
|
|
|
- {{ item.name }}
|
|
|
- </div>
|
|
|
- <div class="jsz" v-if="item.loading && !showResult">
|
|
|
- <Spin />
|
|
|
- {{ hintText }}
|
|
|
- </div>
|
|
|
-
|
|
|
<div class="tab-content" v-if="!showResult">
|
|
|
<div class="summary-content">
|
|
|
<div class="summary-icon">
|
|
@@ -509,7 +508,6 @@ export default {
|
|
|
detailData: null,
|
|
|
cyyqLayer: null,
|
|
|
legend: [],
|
|
|
- mockInterval: null,
|
|
|
};
|
|
|
},
|
|
|
mounted() {
|
|
@@ -517,7 +515,9 @@ export default {
|
|
|
this.$nextTick(() => {
|
|
|
this.activeIndex = 0;
|
|
|
this.initMap();
|
|
|
- // this.mockTestData();
|
|
|
+
|
|
|
+ // this.testStubXgdk();
|
|
|
+
|
|
|
});
|
|
|
},
|
|
|
created() {
|
|
@@ -631,9 +631,7 @@ export default {
|
|
|
if (this.interval) {
|
|
|
clearInterval(this.interval);
|
|
|
}
|
|
|
- if (this.mockInterval) {
|
|
|
- clearInterval(this.mockInterval);
|
|
|
- }
|
|
|
+
|
|
|
this.inputText = "";
|
|
|
},
|
|
|
onStopSendHandle () {
|
|
@@ -739,11 +737,9 @@ export default {
|
|
|
this.radarShow = false;
|
|
|
}
|
|
|
},
|
|
|
- resetAnswer(index) {
|
|
|
- if (index == 0) {
|
|
|
+ resetAnswer() {
|
|
|
this.input = this.inputText;
|
|
|
this.questionModal = true;
|
|
|
- }
|
|
|
},
|
|
|
|
|
|
hideModal() {
|
|
@@ -1054,62 +1050,97 @@ export default {
|
|
|
});
|
|
|
},
|
|
|
getDetailByIdList(idList, func) {
|
|
|
- let layerName = null;
|
|
|
- let that = this;
|
|
|
- //公告地块
|
|
|
- if (this.dSource == "2") {
|
|
|
- layerName = "ecgap_klyzy";
|
|
|
- idList = idList.map((ele) => ele.id);
|
|
|
- this.klyzyQuery(idList, (res) => {
|
|
|
- let result = res.map((ele) => {
|
|
|
- let viewObj = {
|
|
|
+ // 参数判空处理
|
|
|
+ if (!Array.isArray(idList) || idList.length === 0) {
|
|
|
+ if (typeof func === 'function') func([]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (typeof func !== 'function') {
|
|
|
+ // 如果回调不是函数,直接返回
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const isGgdk = this.dSource == "2";
|
|
|
+ const isKg = this.dSource == "1";
|
|
|
+ const that = this;
|
|
|
+
|
|
|
+ // 公共处理函数
|
|
|
+ function processResult(res, type) {
|
|
|
+ if (!Array.isArray(res) || res.length === 0) {
|
|
|
+ func([]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const result = res.map((ele) => {
|
|
|
+ let viewObj = {};
|
|
|
+ if (type === 'ggdk') {
|
|
|
+ viewObj = {
|
|
|
id: ele.id,
|
|
|
name: ele.dkmc,
|
|
|
tdyt: ele.tdyt,
|
|
|
- dkmj: ele.dkmj.toFixed(2),
|
|
|
+ dkmj: ele.dkmj ? ele.dkmj.toFixed(2) : '',
|
|
|
center_wkt: ele.center_wkt,
|
|
|
geom: ele.geom,
|
|
|
wzxx: "",
|
|
|
};
|
|
|
if (ele.center_wkt) {
|
|
|
- let geojson = wkt.parse(ele.center_wkt);
|
|
|
- if (ele.tdyt.indexOf("工业") > -1) {
|
|
|
- that.getGyydWzxx(geojson.coordinates, viewObj);
|
|
|
- } else {
|
|
|
- that.getNoGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ try {
|
|
|
+ const geojson = wkt.parse(ele.center_wkt);
|
|
|
+ if (ele.tdyt && ele.tdyt.indexOf("工业") > -1) {
|
|
|
+ that.getGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ } else {
|
|
|
+ that.getNoGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // wkt 解析失败
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return viewObj;
|
|
|
- });
|
|
|
- func(result);
|
|
|
- });
|
|
|
- } else if (this.dSource == "1") {
|
|
|
- //控制性详细规划
|
|
|
- layerName = "kzxxxgh";
|
|
|
- idList = idList.map((ele) => ele.id);
|
|
|
- this.kgQuery(idList, (res) => {
|
|
|
- let result = res.map((ele) => {
|
|
|
- let viewObj = {
|
|
|
+ } else if (type === 'kg') {
|
|
|
+ viewObj = {
|
|
|
id: ele.id,
|
|
|
name: ele.ydxz,
|
|
|
- tdyt: `${ele.ydxz}(${ele.yddm})`,
|
|
|
- dkmj: (ele.pfmarea * 0.0015).toFixed(2),
|
|
|
+ tdyt: ele.ydxz && ele.yddm ? `${ele.ydxz}(${ele.yddm})` : ele.ydxz || '',
|
|
|
+ dkmj: ele.pfmarea ? (ele.pfmarea * 0.0015).toFixed(2) : '',
|
|
|
center_wkt: ele.center_wkt,
|
|
|
geom: ele.geom,
|
|
|
wzxx: "",
|
|
|
};
|
|
|
- let geojson = wkt.parse(ele.center_wkt);
|
|
|
- if (ele.ydxz.indexOf("工业") > -1) {
|
|
|
- that.getGyydWzxx(geojson.coordinates, viewObj);
|
|
|
- } else {
|
|
|
- that.getNoGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ if (ele.center_wkt) {
|
|
|
+ try {
|
|
|
+ const geojson = wkt.parse(ele.center_wkt);
|
|
|
+ if (ele.ydxz && ele.ydxz.indexOf("工业") > -1) {
|
|
|
+ that.getGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ } else {
|
|
|
+ that.getNoGyydWzxx(geojson.coordinates, viewObj);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // wkt 解析失败
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- return viewObj;
|
|
|
- });
|
|
|
- func(result);
|
|
|
+ }
|
|
|
+ return viewObj;
|
|
|
});
|
|
|
+ func(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isGgdk) {
|
|
|
+ // 公告地块
|
|
|
+ const ids = idList.map((ele) => ele && ele.id).filter(Boolean);
|
|
|
+ if (ids.length === 0) {
|
|
|
+ func([]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.klyzyQuery(ids, (res) => processResult(res, 'ggdk'));
|
|
|
+ } else if (isKg) {
|
|
|
+ // 控制性详细规划
|
|
|
+ const ids = idList.map((ele) => ele && ele.id).filter(Boolean);
|
|
|
+ if (ids.length === 0) {
|
|
|
+ func([]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.kgQuery(ids, (res) => processResult(res, 'kg'));
|
|
|
+ } else {
|
|
|
+ // 其他类型暂不处理
|
|
|
+ func([]);
|
|
|
}
|
|
|
},
|
|
|
getGyydWzxx(point, viewObj) {
|
|
@@ -1711,9 +1742,9 @@ export default {
|
|
|
send: _.debounce(async function () {
|
|
|
let that = this;
|
|
|
this.showResult = false;
|
|
|
- //不显示查询时地图上的雷达扫描效果
|
|
|
- this.radarShow = false;
|
|
|
this.zhuiwen = false;
|
|
|
+
|
|
|
+ // Clean up existing connections and resources
|
|
|
if (this.eventSource) {
|
|
|
this.eventSource.close();
|
|
|
this.loading = false;
|
|
@@ -1731,35 +1762,18 @@ export default {
|
|
|
if (this.interval) {
|
|
|
clearInterval(this.interval);
|
|
|
}
|
|
|
+
|
|
|
this.activeIndex = 0;
|
|
|
var question = this.wt.trim();
|
|
|
- // if (this.zwinputText != "") {
|
|
|
- // //追问的时候,暂时不用历史数据
|
|
|
- // // question = question + ",其中" + this.zwinputText.trim();
|
|
|
- // question = this.zwinputText.trim();
|
|
|
- // }
|
|
|
-
|
|
|
- //todo
|
|
|
- if (
|
|
|
- question.indexOf("控制性详细规划") == -1 &&
|
|
|
- question.indexOf("公告地块") == -1
|
|
|
- ) {
|
|
|
+
|
|
|
+ // Add data source context if needed
|
|
|
+ if (question.indexOf("控制性详细规划") == -1 && question.indexOf("公告地块") == -1) {
|
|
|
if (this.dSource == "1") {
|
|
|
question += ",数据表是控制性详细规划";
|
|
|
} else if (this.dSource == "2") {
|
|
|
question += ",数据表是公告地块";
|
|
|
}
|
|
|
}
|
|
|
- let mock = false;
|
|
|
-
|
|
|
- this.interval = setInterval(
|
|
|
- () => {
|
|
|
- if (this.activeIndex < this.steps.length - 1) {
|
|
|
- this.activeIndex = this.activeIndex + 1;
|
|
|
- }
|
|
|
- },
|
|
|
- mock ? 1000 : 5000
|
|
|
- );
|
|
|
|
|
|
this.querQuestion = question;
|
|
|
this.summary = "";
|
|
@@ -1773,187 +1787,123 @@ export default {
|
|
|
timestamp: new Date().getTime(),
|
|
|
});
|
|
|
|
|
|
- //清空输入框文字
|
|
|
- // this.inputText = "";
|
|
|
-
|
|
|
- //发送请求
|
|
|
- //建立SSE连接
|
|
|
+ // Setup request
|
|
|
this.loading = true;
|
|
|
this.startTime = new Date().getTime();
|
|
|
this.checkInterval = setInterval(() => {
|
|
|
this.checkTimeOut();
|
|
|
}, this.gInterval);
|
|
|
- // 建立连接
|
|
|
- // let eventSource = new EventSource(
|
|
|
- // `${window.ApplicationConfig.subscribeUrl}${this.inputText.trim()}`
|
|
|
- // );
|
|
|
- if (!this.ctrlAbout) {
|
|
|
- this.ctrlAbout = new AbortController();
|
|
|
- }
|
|
|
- this.btnSendDisabled = true;
|
|
|
- //todo
|
|
|
- const signal = this.ctrlAbout.signal;
|
|
|
- await fetchEventSource(window.ApplicationConfig.subscribeUrl, {
|
|
|
- method: "POST",
|
|
|
- openWhenHidden: true,
|
|
|
- headers: {
|
|
|
- "Content-Type": "application/json",
|
|
|
- },
|
|
|
- body: JSON.stringify({
|
|
|
- data: question,
|
|
|
- history: this.histories.toArray().flat() || [],
|
|
|
- }),
|
|
|
- signal: signal,
|
|
|
- async onmessage(msg) {
|
|
|
- const { data } = msg;
|
|
|
- if (data) {
|
|
|
- that.handleData({ data: data }, question);
|
|
|
- }
|
|
|
- },
|
|
|
|
|
|
- onerror(err) {
|
|
|
- console.log("请求报错--");
|
|
|
- that.checkTimeOut();
|
|
|
- },
|
|
|
- }).catch((err) => {
|
|
|
- console.log(err);
|
|
|
- console.log("请求报错:" + err);
|
|
|
- that.checkTimeOut();
|
|
|
- });
|
|
|
- }, 500),
|
|
|
- handleData(e, question) {
|
|
|
- let T = this;
|
|
|
- if (e.data != "[FINISH]" && e.data != "[DONE]") {
|
|
|
- const responseData = JSON.parse(e.data);
|
|
|
- const responses = responseData["agent_responses"];
|
|
|
- // console.log("responses: ", responses);
|
|
|
- const lastRes = responses[responses.length - 1];
|
|
|
- var lastUpRes = null;
|
|
|
- responses.forEach((item, index) => {
|
|
|
- if (
|
|
|
- item.exec_res &&
|
|
|
- typeof item.exec_res === "string" &&
|
|
|
- item.exec_res.indexOf("\n```json\n") > -1
|
|
|
- ) {
|
|
|
- lastUpRes = responses[index];
|
|
|
- // console.log("lastUpRes: ", lastUpRes);
|
|
|
- }
|
|
|
- });
|
|
|
- const user_request = responseData.user_request;
|
|
|
- const conversationId = lastRes["agent_id"];
|
|
|
- let message = T.messages.find(({ id }) => id === conversationId);
|
|
|
- const executed = lastRes["executed"];
|
|
|
- const agentName = lastRes["agent_name"];
|
|
|
- const agentNameCn = lastRes["agent_name_cn"];
|
|
|
- const execRes = lastRes["exec_res"];
|
|
|
-
|
|
|
- const lastChoice = lastRes.choices[lastRes.choices.length - 1];
|
|
|
- const choiceId = lastChoice["choice_id"];
|
|
|
- let choiceMessage = T.messages.find(({ id }) => id === choiceId);
|
|
|
- if (window.ApplicationConfig.aiAgent.indexOf(agentName) >= 0) {
|
|
|
- if (message) {
|
|
|
- if (lastChoice.role === "assistant" && !lastChoice.history) {
|
|
|
- }
|
|
|
+ // 每次请求都新建 AbortController,避免 signal 复用导致无法再次请求
|
|
|
+ this.ctrlAbout = new AbortController();
|
|
|
|
|
|
- if (
|
|
|
- agentName != "summary" &&
|
|
|
- lastChoice.role === "assistant" &&
|
|
|
- !executed
|
|
|
- ) {
|
|
|
- T.loading = false;
|
|
|
- T.hzData.forEach((item, index) => {
|
|
|
- if (index == T.hzData.length - 1) {
|
|
|
- T.hzData[index].summary = lastChoice.content
|
|
|
- .replaceAll("\n```json\n", "")
|
|
|
- .replaceAll("```json\n", "")
|
|
|
- .replaceAll("\n```\n", "");
|
|
|
- T.$forceUpdate();
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- if (agentName === "summary") {
|
|
|
- if (!executed) {
|
|
|
- T.loading = false;
|
|
|
- this.hintText = "结果整理中...";
|
|
|
- } else if (execRes) {
|
|
|
- // T.summary = execRes;
|
|
|
- T.showResult = true;
|
|
|
- T.radarShow = false;
|
|
|
- T.loading = false;
|
|
|
- if (lastUpRes) {
|
|
|
- var exec_res = lastUpRes.exec_res
|
|
|
- .replaceAll("\n```json\n", "")
|
|
|
- .replaceAll("```json\n", "")
|
|
|
- .replaceAll("\n```\n", "");
|
|
|
- exec_res = JSON.parse(exec_res);
|
|
|
- var dk = exec_res;
|
|
|
- console.log("dk: ", dk);
|
|
|
-
|
|
|
- T.getDetailByIdList(dk, (data) => {
|
|
|
- T.clearMark();
|
|
|
- T.addGdLayer(data);
|
|
|
- T.xgdk = data;
|
|
|
- T.showXgdkCenterPoint();
|
|
|
- //todo 展开
|
|
|
- T.mContentVisabled = true;
|
|
|
- T.xgdk.forEach((item) => {
|
|
|
- item["show"] = true;
|
|
|
- });
|
|
|
- });
|
|
|
+ try {
|
|
|
+ const response = await fetch(window.ApplicationConfig.landAnalysisUrl, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ },
|
|
|
+ body: JSON.stringify({
|
|
|
+ description: question
|
|
|
+ }),
|
|
|
+ signal: this.ctrlAbout.signal
|
|
|
+ });
|
|
|
|
|
|
- T.answer = e.data;
|
|
|
+ await this.handleStreamResponse(response);
|
|
|
+ } catch (err) {
|
|
|
+ if (err.name === 'AbortError') {
|
|
|
+ // 请求被取消,静默处理
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ console.error('Request error:', err);
|
|
|
+ this.checkTimeOut();
|
|
|
+ } finally {
|
|
|
+ this.loading = false;
|
|
|
+ this.btnSendDisabled = false;
|
|
|
+ if (this.checkInterval) {
|
|
|
+ clearInterval(this.checkInterval);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 500),
|
|
|
|
|
|
- // T.burialPoint();
|
|
|
+ async handleStreamResponse(response) {
|
|
|
+ const reader = response.body.getReader();
|
|
|
+ const decoder = new TextDecoder();
|
|
|
+
|
|
|
+ this.hzData = [];
|
|
|
+ let sqlGenSummary = '';
|
|
|
+ let sqlGenIndex = -1;
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ const { value, done } = await reader.read();
|
|
|
+ if (done) break;
|
|
|
+
|
|
|
+ const chunk = decoder.decode(value);
|
|
|
+ const lines = chunk.split('\n').filter(line => line.trim());
|
|
|
+
|
|
|
+ for (const line of lines) {
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(line);
|
|
|
+ let contentToAdd = '';
|
|
|
+ switch (data.type) {
|
|
|
+ case 'sql_generation':
|
|
|
+ contentToAdd = typeof data.content === 'string' ? data.content : JSON.stringify(data.content);
|
|
|
+ if (sqlGenIndex === -1) {
|
|
|
+ sqlGenSummary = contentToAdd;
|
|
|
+ this.hzData.push({ type: 'sql_generation', summary: sqlGenSummary });
|
|
|
+ sqlGenIndex = this.hzData.length - 1;
|
|
|
} else {
|
|
|
- T.xgdk = [];
|
|
|
- T.clearMark();
|
|
|
+ sqlGenSummary += contentToAdd;
|
|
|
+ this.hzData[sqlGenIndex].summary = sqlGenSummary;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'result':
|
|
|
+ if (data.data && data.data.sql) {
|
|
|
+ contentToAdd = typeof data.data.sql === 'string' ? data.data.sql : JSON.stringify(data.data.sql);
|
|
|
+ this.hzData.push({ type: 'result', summary: contentToAdd });
|
|
|
}
|
|
|
- T.activeIndex = T.steps.length - 1;
|
|
|
- // T.hintText = "检索完成";
|
|
|
- T.hzData.forEach((item, index) => {
|
|
|
- if (index == T.hzData.length - 1) {
|
|
|
- T.hzData[index].summary = execRes;
|
|
|
- T.hzData[index].loading = false;
|
|
|
- T.zwinputText = "";
|
|
|
+ // 保持原有地块处理逻辑
|
|
|
+ if (data.data && data.data.exec_result) {
|
|
|
+ try {
|
|
|
+ this.getDetailByIdList(data.data.exec_result, (detailData) => {
|
|
|
+ if (Array.isArray(detailData) && detailData.length > 0) {
|
|
|
+ this.clearMark();
|
|
|
+ this.addGdLayer(detailData);
|
|
|
+ this.xgdk = detailData;
|
|
|
+ this.showXgdkCenterPoint();
|
|
|
+ this.mContentVisabled = true;
|
|
|
+ this.xgdk.forEach((item) => {
|
|
|
+ item["show"] = true;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 无有效地块数据时,清空相关内容
|
|
|
+ this.clearMark();
|
|
|
+ this.xgdk = [];
|
|
|
+ this.mContentVisabled = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('Error processing result data:', e);
|
|
|
}
|
|
|
- });
|
|
|
- clearInterval(T.checkInterval);
|
|
|
- }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'end':
|
|
|
+ contentToAdd = typeof data.content === 'string' ? data.content : JSON.stringify(data.content);
|
|
|
+ this.hzData.push({ type: 'end', summary: contentToAdd });
|
|
|
+ this.loading = false;
|
|
|
+ this.showResult = true;
|
|
|
+ this.radarShow = false;
|
|
|
+ this.activeIndex = this.steps.length - 1;
|
|
|
+ this.btnSendDisabled = false;
|
|
|
+ break;
|
|
|
}
|
|
|
- } else {
|
|
|
- T.messages.push({
|
|
|
- id: conversationId,
|
|
|
- content: "",
|
|
|
- source: "ai",
|
|
|
- loading: true,
|
|
|
- timestamp: new Date().getTime(),
|
|
|
- });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('Error parsing stream data:', e);
|
|
|
}
|
|
|
}
|
|
|
- } else {
|
|
|
- if (e.data == "[FINISH]") {
|
|
|
- console.log("SSE连接关闭");
|
|
|
- T.btnSendDisabled = false;
|
|
|
- T.loading = false;
|
|
|
- T.count = 0;
|
|
|
- if (T.eventSource) {
|
|
|
- T.eventSource.close();
|
|
|
- }
|
|
|
- if (T.interval) {
|
|
|
- clearInterval(T.interval);
|
|
|
- }
|
|
|
- T.messages.forEach((item, index) => {
|
|
|
- if (item.loading) {
|
|
|
- T.messages.splice(index, 1);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- T.loading = false;
|
|
|
-
|
|
|
- T.addHistory(question, T.messages[T.messages.length - 1].content);
|
|
|
- }
|
|
|
}
|
|
|
},
|
|
|
+
|
|
|
/**
|
|
|
* 添加多轮对话效果
|
|
|
* @param question
|
|
@@ -1971,7 +1921,8 @@ export default {
|
|
|
},
|
|
|
]);
|
|
|
},
|
|
|
- mockTestData() {
|
|
|
+ // 打桩/调试用:测试xgdk相关功能
|
|
|
+ testStubXgdk() {
|
|
|
this.showResult = true;
|
|
|
this.showQuery = true;
|
|
|
this.xgdk = [
|
|
@@ -1985,7 +1936,6 @@ export default {
|
|
|
id: 1845,
|
|
|
},
|
|
|
];
|
|
|
- // 备选测试数据
|
|
|
// this.xgdk = [
|
|
|
// {
|
|
|
// id: 7685,
|
|
@@ -1997,6 +1947,7 @@ export default {
|
|
|
// id: 40175,
|
|
|
// },
|
|
|
// ];
|
|
|
+ let that = this;
|
|
|
this.getDetailByIdList(this.xgdk, (data) => {
|
|
|
this.xgdk = data;
|
|
|
this.addGdLayer(this.xgdk);
|