From 8b87a2bc403fa27a2755d223cf9ff94dbac3fa11 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Mon, 3 Nov 2025 02:12:05 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manage/components/ChatInput/history.js | 121 ++++++++++++++++++ .../manage/components/ChatInput/index.vue | 17 ++- 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 resources/assets/js/pages/manage/components/ChatInput/history.js diff --git a/resources/assets/js/pages/manage/components/ChatInput/history.js b/resources/assets/js/pages/manage/components/ChatInput/history.js new file mode 100644 index 000000000..7ec915bc2 --- /dev/null +++ b/resources/assets/js/pages/manage/components/ChatInput/history.js @@ -0,0 +1,121 @@ +const HISTORY_LIMIT = 50; +const HISTORY_STORAGE_KEY = 'chat-input-history'; + +export default { + data() { + return { + historyList: [], + historyIndex: 0, + historyCurrent: '', + }; + }, + + methods: { + refreshHistoryContext() { + this.historyCurrent = ''; + this.historyList = []; + this.historyIndex = 0; + this.loadInputHistory(); + }, + + async loadInputHistory() { + try { + const history = await $A.IDBValue(HISTORY_STORAGE_KEY); + if (Array.isArray(history)) { + this.historyList = history; + } else if (history && typeof history === 'object') { + this.historyList = Object.values(history).filter(item => typeof item === 'string'); + } else { + this.historyList = []; + } + } catch (error) { + this.historyList = []; + } + this.historyIndex = this.historyList.length; + }, + + persistInputHistory(content) { + if (!content || $A.filterInvalidLine(content) === '') { + return; + } + const history = Array.isArray(this.historyList) ? [...this.historyList] : []; + const last = history[history.length - 1]; + if (last === content) { + this.historyIndex = history.length; + this.historyCurrent = ''; + return; + } + const existIndex = history.indexOf(content); + if (existIndex !== -1) { + history.splice(existIndex, 1); + } + history.push(content); + if (history.length > HISTORY_LIMIT) { + history.splice(0, history.length - HISTORY_LIMIT); + } + this.historyList = history; + this.historyIndex = history.length; + this.historyCurrent = ''; + $A.IDBSet(HISTORY_STORAGE_KEY, history).catch(() => {}); + }, + + applyHistoryContent(content) { + if (!this.quill) { + return; + } + if (content) { + this.setContent(content); + } else { + this.quill.setText(''); + } + this._content = content || ''; + this.$emit('input', this._content); + this.$nextTick(() => { + const length = this.quill.getLength(); + this.quill.setSelection(Math.max(length - 1, 0), 0); + }); + }, + + navigateHistory(direction, range) { + if (!this.quill || !this.historyList.length) { + return true; + } + if (!range || range.length !== 0) { + return true; + } + if (direction === 'up') { + if (range.index > 0) { + return true; + } + if (this.historyIndex === this.historyList.length) { + this.historyCurrent = this.value; + } + if (this.historyIndex > 0) { + this.historyIndex--; + } else { + this.historyIndex = 0; + } + this.applyHistoryContent(this.historyList[this.historyIndex] || ''); + return false; + } + if (direction === 'down') { + const endIndex = Math.max(this.quill.getLength() - 1, 0); + if (range.index < endIndex) { + return true; + } + if (this.historyIndex === this.historyList.length) { + return true; + } + if (this.historyIndex < this.historyList.length - 1) { + this.historyIndex++; + this.applyHistoryContent(this.historyList[this.historyIndex] || ''); + } else { + this.historyIndex = this.historyList.length; + this.applyHistoryContent(this.historyCurrent || ''); + } + return false; + } + return true; + }, + }, +}; diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue index 9a4c8c4c0..2d744146f 100755 --- a/resources/assets/js/pages/manage/components/ChatInput/index.vue +++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue @@ -344,6 +344,7 @@ import {inputLoadAdd, inputLoadIsLast, inputLoadRemove} from "./one"; import {languageList, languageName} from "../../../../language"; import {isMarkdownFormat} from "../../../../utils/markdown"; import emitter from "../../../../store/events"; +import historyMixin from "./history"; const globalRangeIndexs = {}; @@ -351,6 +352,7 @@ export default { name: 'ChatInput', components: {ChatEmoji}, directives: {touchmouse, touchclick, TransferDom, clickoutside, longpress}, + mixins: [historyMixin], props: { value: { type: [String, Number], @@ -541,6 +543,7 @@ export default { }, mounted() { this.init(); + this.refreshHistoryContext(); // this.recordInter = setInterval(_ => { if (this.recordState === 'ing') { @@ -786,6 +789,7 @@ export default { this.fileList = {}; this.reportList = {}; this.loadInputDraft() + this.refreshHistoryContext(); }, taskId() { this.selectRange = null; @@ -795,6 +799,7 @@ export default { this.fileList = {}; this.reportList = {}; this.loadInputDraft() + this.refreshHistoryContext(); }, draftData() { @@ -983,7 +988,7 @@ export default { toolbar: false, keyboard: this.simpleMode ? {} : { bindings: { - 'short enter': { + 'enter-short': { key: "Enter", shortKey: true, handler: _ => { @@ -1015,6 +1020,14 @@ export default { } return true; } + }, + 'history-up': { + key: 38, + handler: range => this.navigateHistory('up', range) + }, + 'history-down': { + key: 40, + handler: range => this.navigateHistory('down', range) } } }, @@ -1504,6 +1517,8 @@ export default { if (type === 'normal') { type = '' } + const content = this.value; + this.persistInputHistory(content); if (type) { this.$emit('on-send', null, type) } else {