From 96aaeb495edfbc4a41dce4b7f7a416a8204a5455 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 28 四月 2026 11:04:38 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
---
src/views/fileManagement/document/index.vue | 8
src/views/fileManagement/return/index.vue | 33
src/views/fileManagement/borrow/index.vue | 33
src/layout/index.vue | 264 +++++-----
src/components/AIChatSidebar/index.vue | 1206 ++++++++++++++++++++++++++++++++++++++++++++++
vite.config.js | 2
6 files changed, 1,387 insertions(+), 159 deletions(-)
diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
new file mode 100644
index 0000000..d14978c
--- /dev/null
+++ b/src/components/AIChatSidebar/index.vue
@@ -0,0 +1,1206 @@
+<template>
+ <div class="ai-chat-sidebar-wrapper">
+ <!-- 鎮诞鍥炬爣 -->
+ <div class="ai-chat-trigger" @click="toggleSidebar" v-show="!visible">
+ <el-tooltip content="AI 鍔╂墜" placement="left">
+ <div class="trigger-icon">
+ <el-icon :size="30" color="#fff"><Cpu /></el-icon>
+ </div>
+ </el-tooltip>
+ </div>
+
+ <!-- 渚ц竟鏍忓璇濇 -->
+ <el-drawer
+ v-model="visible"
+ :size="drawerSize"
+ direction="rtl"
+ :with-header="true"
+ class="ai-chat-drawer"
+ :modal="false"
+ :show-close="true"
+ :append-to-body="false"
+ @close="handleClose"
+ >
+ <template #header>
+ <div class="drawer-header">
+ <div class="header-left">
+ <el-icon :size="20" class="header-icon"><Cpu /></el-icon>
+ <span class="title">AI 鏅鸿兘鍔╂墜</span>
+ </div>
+ <div class="header-actions">
+ <el-tooltip content="浼氳瘽鍘嗗彶" placement="bottom">
+ <el-button link @click="toggleHistory">
+ <el-icon :size="18"><Timer /></el-icon>
+ </el-button>
+ </el-tooltip>
+ <el-tooltip content="寮�鍚柊浼氳瘽" placement="bottom">
+ <el-button link @click="newChat">
+ <el-icon :size="18"><Plus /></el-icon>
+ </el-button>
+ </el-tooltip>
+ </div>
+ </div>
+ </template>
+
+ <div class="chat-container">
+ <!-- 鍘嗗彶浼氳瘽鍒楄〃 -->
+ <div v-if="showHistory" class="history-panel">
+ <div class="history-header">
+ <span>鏈�杩戜細璇�</span>
+ <el-button link type="primary" @click="showHistory = false">杩斿洖瀵硅瘽</el-button>
+ </div>
+ <el-skeleton :loading="loadingSessions" animated>
+ <template #template>
+ <div v-for="i in 5" :key="i" style="padding: 10px">
+ <el-skeleton-item variant="p" style="width: 80%" />
+ </div>
+ </template>
+ <div class="session-list">
+ <div
+ v-for="session in sessions"
+ :key="session.memoryId"
+ :class="['session-item', { active: uuid === session.memoryId }]"
+ @click="selectSession(session)"
+ >
+ <el-icon><ChatDotSquare /></el-icon>
+ <span class="session-name" :title="session.lastMessage || '鏂颁細璇�'">
+ {{ session.lastMessage || '鏂颁細璇�' }}
+ </span>
+ <el-button
+ link
+ type="danger"
+ class="delete-btn"
+ @click.stop="handleDeleteSession(session.memoryId)"
+ >
+ <el-icon><Delete /></el-icon>
+ </el-button>
+ </div>
+ <el-empty v-if="sessions.length === 0" description="鏆傛棤鍘嗗彶浼氳瘽" />
+ </div>
+ </el-skeleton>
+ </div>
+
+ <div v-else class="chat-main">
+ <div class="message-list" ref="messageListRef">
+ <div
+ v-for="(message, index) in messages"
+ :key="index"
+ :class="['message-item', message.isUser ? 'user-message' : 'bot-message']"
+ >
+ <div class="avatar">
+ <el-icon v-if="message.isUser"><User /></el-icon>
+ <el-icon v-else><Cpu /></el-icon>
+ </div>
+ <div class="message-content">
+ <!-- 鏂囨湰鍐呭 -->
+ <div class="text-box" v-html="message.htmlContent"></div>
+
+ <!-- 鍥捐〃鍐呭 -->
+ <div v-if="message.chartOptions && message.chartRenderReady" class="charts-wrapper">
+ <div
+ v-for="(option, key) in message.chartOptions"
+ :key="key"
+ class="chart-item"
+ :id="`ai-chart-${index}-${key}`"
+ ></div>
+ </div>
+
+ <!-- 琛ㄦ牸鍐呭 -->
+ <div v-if="message.type === 'todo_list' && message.tableData" class="table-wrapper">
+ <el-table :data="message.tableData.items" border stripe size="small" style="width: 100%">
+ <el-table-column
+ v-for="col in message.tableData.columns"
+ :key="col"
+ :prop="col"
+ :label="columnLabelMap[col] || col"
+ min-width="100"
+ show-overflow-tooltip
+ />
+ </el-table>
+ </div>
+
+ <!-- 鎵撳瓧涓姩鐢� -->
+ <div v-if="message.isTyping" class="typing-indicator">
+ <span class="dot"></span>
+ <span class="dot"></span>
+ <span class="dot"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="input-area">
+ <div class="input-actions">
+ <el-button link type="primary" size="small" @click="newChat">
+ <el-icon><Plus /></el-icon>鏂颁細璇�
+ </el-button>
+ <el-button v-if="isSending" link type="danger" size="small" @click="stopGeneration">
+ <el-icon><VideoPause /></el-icon>鍋滄鐢熸垚
+ </el-button>
+ <el-upload
+ class="file-upload-trigger"
+ action="#"
+ :auto-upload="false"
+ :show-file-list="false"
+ :on-change="handleFileChange"
+ :disabled="isSending"
+ >
+ <el-button link type="primary" size="small" :disabled="isSending">
+ <el-icon><Upload /></el-icon>鍒嗘瀽鏂囦欢
+ </el-button>
+ </el-upload>
+ </div>
+ <div class="input-box">
+ <div v-if="selectedFile" class="selected-file-tag">
+ <el-icon><Document /></el-icon>
+ <span class="file-name">{{ selectedFile.name }}</span>
+ <el-icon class="remove-file" @click="removeSelectedFile"><Close /></el-icon>
+ </div>
+ <el-input
+ v-model="inputMessage"
+ type="textarea"
+ :rows="selectedFile ? 2 : 3"
+ placeholder="璇疯緭鍏ユ偍鐨勯棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)"
+ resize="none"
+ @keydown.enter.exact.prevent="sendMessage"
+ />
+ <el-button
+ type="primary"
+ class="send-btn"
+ :disabled="isSending || (!inputMessage.trim() && !selectedFile)"
+ @click="sendMessage"
+ >
+ 鍙戦��
+ </el-button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </el-drawer>
+ </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue'
+import request from '@/utils/request'
+import * as echarts from 'echarts'
+import { Cpu, User, Plus, Loading, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close } from '@element-plus/icons-vue'
+import { ElMessage } from 'element-plus'
+
+const visible = ref(false)
+const windowWidth = ref(window.innerWidth)
+const drawerSize = computed(() => {
+ if (windowWidth.value < 768) return '100%'
+ if (windowWidth.value < 1200) return '500px'
+ return '600px'
+})
+const messageListRef = ref(null)
+const isSending = ref(false)
+const currentAbortController = ref(null)
+const inputMessage = ref('')
+const selectedFile = ref(null)
+const messages = ref([])
+const uuid = ref('')
+const chartInstances = ref({})
+const resizeHandlers = ref([])
+const outputState = ref({})
+
+// 鍘嗗彶浼氳瘽鐩稿叧
+const showHistory = ref(false)
+const sessions = ref([])
+const loadingSessions = ref(false)
+
+const toggleHistory = () => {
+ showHistory.value = !showHistory.value
+ if (showHistory.value) {
+ loadSessions()
+ }
+}
+
+const loadSessions = async () => {
+ loadingSessions.value = true
+ try {
+ const res = await request.get('/xiaozhi/history/sessions')
+ if (res.code === 200) {
+ sessions.value = res.data || []
+ }
+ } catch (err) {
+ console.error('Failed to load sessions', err)
+ } finally {
+ loadingSessions.value = false
+ }
+}
+
+const selectSession = async (session) => {
+ showHistory.value = false
+ uuid.value = session.memoryId
+ localStorage.setItem('ai_chat_uuid', uuid.value)
+
+ // 鍔犺浇浼氳瘽娑堟伅
+ try {
+ const res = await request.get(`/xiaozhi/history/messages/${uuid.value}`)
+ if (res.code === 200) {
+ disposeCharts()
+ messages.value = []
+ const historyMsgs = res.data || []
+
+ // 閲嶆柊鏋勯�犳秷鎭垪琛ㄥ苟瑙f瀽
+ historyMsgs.forEach((msg, idx) => {
+ const isUser = msg.role === 'user'
+ const botMsgIndex = messages.value.length
+
+ const messageObj = {
+ isUser,
+ content: msg.content,
+ htmlContent: '',
+ isTyping: false,
+ chartOptions: null,
+ chartRenderReady: false,
+ type: '',
+ tableData: null
+ }
+
+ messages.value.push(messageObj)
+
+ if (!isUser) {
+ outputState.value[botMsgIndex] = {
+ isPaused: false,
+ jsonBlockStartPos: -1,
+ jsBlockStartPos: -1,
+ blockEndPos: -1,
+ hasRenderedChart: false
+ }
+
+ // 瑙f瀽鍘嗗彶娑堟伅涓殑 JSON
+ const jsonRegex = /\{"success":\s*true,[\s\S]*\}/
+ const jsonMatch = msg.content.match(jsonRegex)
+ if (jsonMatch) {
+ try {
+ const parsedData = JSON.parse(jsonMatch[0])
+ if (parsedData.success) {
+ messageObj.type = parsedData.type || ''
+ if (messageObj.type === 'todo_list' && parsedData.data) {
+ messageObj.tableData = parsedData.data
+ }
+ if (parsedData.charts && Object.keys(parsedData.charts).length > 0) {
+ messageObj.chartOptions = parsedData.charts
+ messageObj.chartRenderReady = true
+ renderCharts(botMsgIndex, messageObj.chartOptions)
+ }
+ }
+ } catch (err) {}
+ }
+
+ updateOutputState(msg.content, botMsgIndex)
+ messageObj.htmlContent = convertStreamOutput(msg.content, botMsgIndex)
+ } else {
+ messageObj.htmlContent = convertTextToHtml(msg.content)
+ }
+ })
+ scrollToBottom()
+ }
+ } catch (err) {
+ console.error('Failed to load messages', err)
+ }
+}
+
+const handleDeleteSession = async (memoryId) => {
+ try {
+ const res = await request.delete(`/xiaozhi/history/${memoryId}`)
+ if (res.code === 200) {
+ loadSessions()
+ if (uuid.value === memoryId) {
+ newChat()
+ }
+ }
+ } catch (err) {
+ console.error('Failed to delete session', err)
+ }
+}
+
+const columnLabelMap = {
+ approveId: '瀹℃壒缂栧彿',
+ approveType: '瀹℃壒绫诲瀷',
+ approveUserName: '瀹℃壒浜�',
+ approveUserCurrentName: '褰撳墠澶勭悊浜�',
+ approveReason: '瀹℃壒鍘熷洜',
+ approveStatus: '瀹℃壒鐘舵��',
+ createTime: '鍒涘缓鏃堕棿'
+}
+
+onMounted(() => {
+ initUUID()
+ // 鍒濆娆㈣繋
+ if (messages.value.length === 0) {
+ hello()
+ }
+ window.addEventListener('resize', handleWindowResize)
+})
+
+onUnmounted(() => {
+ disposeCharts()
+ window.removeEventListener('resize', handleWindowResize)
+})
+
+const handleWindowResize = () => {
+ windowWidth.value = window.innerWidth
+}
+
+const toggleSidebar = () => {
+ visible.value = !visible.value
+ if (visible.value) {
+ scrollToBottom()
+ }
+}
+
+const handleClose = () => {
+ visible.value = false
+}
+
+const initUUID = () => {
+ let storedUUID = localStorage.getItem('ai_chat_uuid')
+ if (!storedUUID) {
+ storedUUID = Math.random().toString(36).substring(2, 10) + Date.now().toString(36).substring(4)
+ localStorage.setItem('ai_chat_uuid', storedUUID)
+ }
+ uuid.value = storedUUID
+}
+
+const hello = () => {
+ sendRequest('浣犲ソ')
+}
+
+const newChat = () => {
+ disposeCharts()
+ messages.value = []
+ outputState.value = {}
+ localStorage.removeItem('ai_chat_uuid')
+ initUUID()
+ hello()
+}
+
+const disposeCharts = () => {
+ Object.values(chartInstances.value).forEach(chart => chart.dispose())
+ resizeHandlers.value.forEach(handler => window.removeEventListener('resize', handler))
+ chartInstances.value = {}
+ resizeHandlers.value = []
+}
+
+const scrollToBottom = () => {
+ nextTick(() => {
+ if (messageListRef.value) {
+ messageListRef.value.scrollTop = messageListRef.value.scrollHeight
+ }
+ })
+}
+
+const handleFileChange = (file) => {
+ if (!file) return
+ const rawFile = file.raw
+ if (rawFile) {
+ // 闄愬埗鏂囦欢澶у皬锛屼緥濡� 10MB
+ const isLt10M = rawFile.size / 1024 / 1024 < 10
+ if (!isLt10M) {
+ ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!')
+ return
+ }
+ selectedFile.value = rawFile
+ }
+}
+
+const removeSelectedFile = () => {
+ selectedFile.value = null
+}
+
+const analyzeFile = async (file, message = '') => {
+ if (isSending.value) return
+ isSending.value = true
+ currentAbortController.value = new AbortController()
+
+ const userMsg = message ? `${message}\n[涓婁紶鏂囦欢鍒嗘瀽] ${file.name}` : `[涓婁紶鏂囦欢鍒嗘瀽] ${file.name}`
+ messages.value.push({
+ isUser: true,
+ content: userMsg,
+ htmlContent: convertTextToHtml(userMsg),
+ isTyping: false
+ })
+
+ const botMsgIndex = messages.value.length
+ messages.value.push({
+ isUser: false,
+ content: '',
+ htmlContent: '',
+ isTyping: true,
+ chartOptions: null,
+ chartRenderReady: false,
+ type: '',
+ tableData: null
+ })
+
+ outputState.value[botMsgIndex] = {
+ isPaused: false,
+ jsonBlockStartPos: -1,
+ jsBlockStartPos: -1,
+ blockEndPos: -1,
+ hasRenderedChart: false
+ }
+
+ scrollToBottom()
+
+ const formData = new FormData()
+ formData.append('file', file)
+ formData.append('memoryId', uuid.value)
+ if (message.trim()) {
+ formData.append('message', message.trim())
+ }
+
+ request.post('/xiaozhi/analyze-file', formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ },
+ signal: currentAbortController.value.signal,
+ onDownloadProgress: (e) => {
+ const fullText = e.target ? e.target.responseText : (e.event ? e.event.target.responseText : '')
+ if (!fullText) return
+
+ const currentMsg = messages.value[botMsgIndex]
+ if (!currentMsg) return
+
+ currentMsg.content = fullText
+
+ // 瑙f瀽 JSON 鏁版嵁锛堥拡瀵瑰祵鍏ュ紡 JSON锛�
+ const jsonRegex = /\{"success":\s*true,[\s\S]*\}/
+ const jsonMatch = fullText.match(jsonRegex)
+
+ if (jsonMatch) {
+ try {
+ const parsedData = JSON.parse(jsonMatch[0])
+ if (parsedData.success) {
+ currentMsg.type = parsedData.type || ''
+ if (currentMsg.type === 'todo_list' && parsedData.data) {
+ currentMsg.tableData = parsedData.data
+ }
+ if (parsedData.charts && Object.keys(parsedData.charts).length > 0) {
+ currentMsg.chartOptions = parsedData.charts
+ currentMsg.chartRenderReady = true
+ if (!outputState.value[botMsgIndex].hasRenderedChart) {
+ renderCharts(botMsgIndex, currentMsg.chartOptions)
+ outputState.value[botMsgIndex].hasRenderedChart = true
+ }
+ }
+ }
+ } catch (err) {}
+ }
+
+ updateOutputState(fullText, botMsgIndex)
+ currentMsg.htmlContent = convertStreamOutput(fullText, botMsgIndex)
+ scrollToBottom()
+ }
+ }).then(() => {
+ const currentMsg = messages.value[botMsgIndex]
+ currentMsg.isTyping = false
+ isSending.value = false
+ currentAbortController.value = null
+
+ // 鏈�缁堣В鏋愮‘淇濆浘琛ㄦ覆鏌�
+ if (currentMsg.chartOptions && !outputState.value[botMsgIndex].hasRenderedChart) {
+ renderCharts(botMsgIndex, currentMsg.chartOptions)
+ outputState.value[botMsgIndex].hasRenderedChart = true
+ }
+ }).catch(err => {
+ if (err.name === 'CanceledError' || err.name === 'AbortError') {
+ console.log('Analysis aborted by user')
+ return
+ }
+ console.error('File analysis error:', err)
+ const errorMsg = '鎶辨瓑锛屾枃浠跺垎鏋愯繃绋嬩腑閬囧埌浜嗕竴鐐归棶棰橈紝璇风◢鍚庡啀璇曘��'
+ if (messages.value[botMsgIndex]) {
+ messages.value[botMsgIndex].content = errorMsg
+ messages.value[botMsgIndex].htmlContent = convertTextToHtml(errorMsg)
+ messages.value[botMsgIndex].isTyping = false
+ }
+ isSending.value = false
+ currentAbortController.value = null
+ })
+}
+
+const sendMessage = () => {
+ const msg = inputMessage.value?.trim() || ''
+ if ((msg || selectedFile.value) && !isSending.value) {
+ if (selectedFile.value) {
+ analyzeFile(selectedFile.value, msg)
+ selectedFile.value = null
+ } else {
+ sendRequest(msg)
+ }
+ inputMessage.value = ''
+ }
+}
+
+const stopGeneration = () => {
+ if (currentAbortController.value) {
+ currentAbortController.value.abort()
+ currentAbortController.value = null
+ isSending.value = false
+
+ // 灏嗘渶鍚庝竴鏉℃秷鎭爣璁颁负闈炴墦瀛楃姸鎬�
+ const lastMsg = messages.value[messages.value.length - 1]
+ if (lastMsg && !lastMsg.isUser) {
+ lastMsg.isTyping = false
+ }
+ }
+}
+
+const sendRequest = (message) => {
+ isSending.value = true
+ currentAbortController.value = new AbortController()
+
+ // 鐢ㄦ埛娑堟伅
+ if (messages.value.length > 0) {
+ messages.value.push({
+ isUser: true,
+ content: message,
+ htmlContent: convertTextToHtml(message),
+ isTyping: false
+ })
+ }
+
+ // 鏈哄櫒浜哄崰浣�
+ const botMsgIndex = messages.value.length
+ const botMsg = {
+ isUser: false,
+ content: '',
+ htmlContent: '',
+ isTyping: true,
+ chartOptions: null,
+ chartRenderReady: false,
+ type: '',
+ tableData: null
+ }
+ messages.value.push(botMsg)
+
+ outputState.value[botMsgIndex] = {
+ isPaused: false,
+ jsonBlockStartPos: -1,
+ jsBlockStartPos: -1,
+ blockEndPos: -1,
+ hasRenderedChart: false
+ }
+
+ scrollToBottom()
+
+ request.post('/xiaozhi/chat',
+ { memoryId: uuid.value, message },
+ {
+ signal: currentAbortController.value.signal,
+ onDownloadProgress: (e) => {
+ // 鍏煎涓嶅悓鐗堟湰鐨� axios 鑾峰彇鍝嶅簲鏂囨湰鐨勬柟寮�
+ const fullText = e.target ? e.target.responseText : (e.event ? e.event.target.responseText : '')
+ if (!fullText) return
+
+ const currentMsg = messages.value[botMsgIndex]
+ if (!currentMsg) return
+
+ currentMsg.content = fullText
+
+ // 瑙f瀽 JSON 鏁版嵁锛堥拡瀵瑰祵鍏ュ紡 JSON锛�
+ const jsonRegex = /\{"success":\s*true,[\s\S]*\}/
+ const jsonMatch = fullText.match(jsonRegex)
+
+ if (jsonMatch) {
+ try {
+ const parsedData = JSON.parse(jsonMatch[0])
+ if (parsedData.success) {
+ currentMsg.type = parsedData.type || ''
+ if (currentMsg.type === 'todo_list' && parsedData.data) {
+ currentMsg.tableData = parsedData.data
+ }
+ if (parsedData.charts && Object.keys(parsedData.charts).length > 0) {
+ currentMsg.chartOptions = parsedData.charts
+ currentMsg.chartRenderReady = true
+ if (!outputState.value[botMsgIndex].hasRenderedChart) {
+ renderCharts(botMsgIndex, currentMsg.chartOptions)
+ outputState.value[botMsgIndex].hasRenderedChart = true
+ }
+ }
+ }
+ } catch (err) {}
+ }
+
+ updateOutputState(fullText, botMsgIndex)
+ currentMsg.htmlContent = convertStreamOutput(fullText, botMsgIndex)
+ scrollToBottom()
+ }
+ }
+ ).then(() => {
+ const currentMsg = messages.value[botMsgIndex]
+ currentMsg.isTyping = false
+ isSending.value = false
+ currentAbortController.value = null
+
+ // 鏈�缁堣В鏋�
+ const fullText = currentMsg.content
+ const jsonRegex = /\{"success":\s*true,[\s\S]*\}/
+ const jsonMatch = fullText.match(jsonRegex)
+ if (jsonMatch) {
+ try {
+ const parsedData = JSON.parse(jsonMatch[0])
+ if (parsedData.success) {
+ currentMsg.type = parsedData.type || ''
+ if (currentMsg.type === 'todo_list' && parsedData.data) {
+ currentMsg.tableData = parsedData.data
+ }
+ if (parsedData.charts && Object.keys(parsedData.charts).length > 0) {
+ currentMsg.chartOptions = parsedData.charts
+ currentMsg.chartRenderReady = true
+ if (!outputState.value[botMsgIndex].hasRenderedChart) {
+ renderCharts(botMsgIndex, currentMsg.chartOptions)
+ outputState.value[botMsgIndex].hasRenderedChart = true
+ }
+ }
+ currentMsg.htmlContent = convertStreamOutput(fullText, botMsgIndex)
+ }
+ } catch (err) {}
+ }
+
+ // 鍏滃簳娓叉煋
+ if (currentMsg.chartOptions && !outputState.value[botMsgIndex].hasRenderedChart) {
+ renderCharts(botMsgIndex, currentMsg.chartOptions)
+ }
+ }).catch(err => {
+ if (err.name === 'CanceledError' || err.name === 'AbortError') {
+ console.log('Request aborted by user')
+ return
+ }
+ console.error('AI Chat Error:', err)
+ const errorMsg = '鎶辨瓑锛屾垜鐜板湪閬囧埌浜嗕竴鐐归棶棰橈紝璇风◢鍚庡啀璇曘��'
+ if (messages.value[botMsgIndex]) {
+ messages.value[botMsgIndex].content = errorMsg
+ messages.value[botMsgIndex].htmlContent = convertTextToHtml(errorMsg)
+ messages.value[botMsgIndex].isTyping = false
+ }
+ isSending.value = false
+ currentAbortController.value = null
+ })
+}
+
+const updateOutputState = (text, msgIndex) => {
+ const state = outputState.value[msgIndex]
+ if (state.jsonBlockStartPos === -1) {
+ const pos = text.indexOf('```json')
+ if (pos !== -1) { state.jsonBlockStartPos = pos; state.isPaused = true }
+ }
+ if (state.jsBlockStartPos === -1) {
+ const pos = text.indexOf('```javascript') !== -1 ? text.indexOf('```javascript') : text.indexOf('```js')
+ if (pos !== -1) { state.jsBlockStartPos = pos; state.isPaused = true }
+ }
+ if ((state.jsonBlockStartPos !== -1 || state.jsBlockStartPos !== -1) && state.blockEndPos === -1) {
+ const startCheck = state.jsonBlockStartPos !== -1 ? state.jsonBlockStartPos + 7 : state.jsBlockStartPos + (text.includes('javascript') ? 13 : 5)
+ const endPos = text.indexOf('```', startCheck)
+ if (endPos !== -1) { state.blockEndPos = endPos + 3; state.isPaused = false }
+ }
+}
+
+const convertTextToHtml = (text) => {
+ if (!text) return ''
+ return text
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/\n/g, '<br>')
+}
+
+const convertStreamOutput = (output, msgIndex) => {
+ if (!output) return ''
+ const state = outputState.value[msgIndex]
+ let display = output
+
+ const jsonRegex = /\{"success":\s*true,[\s\S]*\}/
+ const jsonMatch = output.match(jsonRegex)
+ if (jsonMatch) {
+ try {
+ const parsed = JSON.parse(jsonMatch[0])
+ display = output.replace(jsonMatch[0], '').trim()
+ if (!display && parsed.description) display = parsed.description
+ } catch (e) {
+ const start = output.search(/\{"success":\s*true/)
+ display = output.substring(0, start) + '... (姝e湪鐢熸垚鏁版嵁鍥捐〃)'
+ }
+ }
+
+ if (state.jsonBlockStartPos !== -1 && state.blockEndPos === -1) {
+ display = display.substring(0, state.jsonBlockStartPos)
+ } else if (state.jsBlockStartPos !== -1 && state.blockEndPos === -1) {
+ display = display.substring(0, state.jsBlockStartPos)
+ }
+
+ display = display.replace(/```(javascript|js)([\s\S]*?)```/g, '<pre class="code-block js-code">$2</pre>')
+ display = display.replace(/```([\s\S]*?)```/g, '<pre class="code-block">$1</pre>')
+
+ return convertTextToHtml(display)
+}
+
+const renderCharts = (msgIndex, chartOptions) => {
+ nextTick(() => {
+ Object.keys(chartOptions).forEach(key => {
+ const id = `ai-chart-${msgIndex}-${key}`
+ const tryInit = (count = 0) => {
+ const dom = document.getElementById(id)
+ if (dom) {
+ if (chartInstances.value[id]) chartInstances.value[id].dispose()
+ const chart = echarts.init(dom)
+ chartInstances.value[id] = chart
+ chart.setOption(chartOptions[key])
+ const handler = () => chart.resize()
+ resizeHandlers.value.push(handler)
+ window.addEventListener('resize', handler)
+ } else if (count < 10) {
+ setTimeout(() => tryInit(count + 1), 200)
+ }
+ }
+ tryInit()
+ })
+ })
+}
+
+watch(messages, () => scrollToBottom(), { deep: true })
+</script>
+
+<style scoped lang="scss">
+.ai-chat-sidebar-wrapper {
+ position: fixed;
+ inset: 0;
+ z-index: 2000;
+ pointer-events: none;
+
+ :deep(.el-drawer__container) {
+ pointer-events: none;
+ }
+
+ :deep(.el-drawer) {
+ pointer-events: auto;
+ }
+}
+
+.ai-chat-trigger {
+ pointer-events: auto;
+ position: fixed;
+ right: 20px;
+ bottom: 100px;
+ width: 60px;
+ height: 60px;
+ background: linear-gradient(135deg, #409eff 0%, #007aff 100%);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ box-shadow: 0 4px 12px rgba(0, 122, 255, 0.4);
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ z-index: 2001;
+
+ &:hover {
+ transform: scale(1.1) translateY(-5px);
+ box-shadow: 0 8px 20px rgba(0, 122, 255, 0.5);
+ }
+
+ .trigger-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+.ai-chat-drawer {
+ :deep(.el-drawer__body) {
+ padding: 0;
+ overflow: hidden;
+ }
+ :deep(.el-drawer__header) {
+ margin-bottom: 0;
+ padding: 12px 16px;
+ background: #fff;
+ border-bottom: 1px solid #ebeef5;
+ color: #303133;
+ }
+}
+
+.drawer-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ padding-right: 32px;
+
+ .header-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ .header-icon {
+ color: #409eff;
+ }
+
+ .title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+ }
+
+ .header-actions {
+ display: flex;
+ gap: 8px;
+ }
+}
+
+.chat-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background-color: #f5f7fa;
+ position: relative;
+}
+
+.history-panel {
+ position: absolute;
+ inset: 0;
+ background: #fff;
+ z-index: 10;
+ display: flex;
+ flex-direction: column;
+
+ .history-header {
+ padding: 16px;
+ border-bottom: 1px solid #ebeef5;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: 600;
+ font-size: 14px;
+ }
+
+ .session-list {
+ flex: 1;
+ overflow-y: auto;
+ padding: 8px;
+
+ .session-item {
+ display: flex;
+ align-items: center;
+ padding: 12px;
+ margin-bottom: 4px;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.2s;
+ gap: 10px;
+ position: relative;
+ border: 1px solid transparent;
+
+ &:hover {
+ background-color: #f5f7fa;
+ .delete-btn {
+ opacity: 1;
+ }
+ }
+
+ &.active {
+ background-color: #ecf5ff;
+ border-color: #d9ecff;
+ color: #409eff;
+ }
+
+ .el-icon {
+ font-size: 16px;
+ flex-shrink: 0;
+ }
+
+ .session-name {
+ flex: 1;
+ font-size: 13px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .delete-btn {
+ opacity: 0;
+ transition: opacity 0.2s;
+ padding: 4px;
+ &:hover {
+ color: #f56c6c;
+ }
+ }
+ }
+ }
+}
+
+.chat-main {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ flex: 1;
+ overflow: hidden;
+}
+
+.message-list {
+ flex: 1;
+ overflow-y: auto;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #dcdfe6;
+ border-radius: 3px;
+ }
+}
+
+.message-item {
+ display: flex;
+ gap: 12px;
+ width: 100%;
+
+ .avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ font-size: 20px;
+ }
+
+ .message-content {
+ flex: 1;
+ overflow-x: hidden; // 淇敼涓� hidden锛屽唴閮ㄥ鍣ㄥ鐞嗘粴鍔�
+ display: flex;
+ flex-direction: column;
+ max-width: calc(100% - 48px); // 鍑忓幓澶村儚鍜岄棿璺�
+
+ .text-box {
+ padding: 12px 16px;
+ border-radius: 12px;
+ font-size: 14px;
+ line-height: 1.6;
+ word-break: break-word;
+ max-width: 100%;
+ width: fit-content;
+ overflow-x: auto;
+ &::-webkit-scrollbar {
+ height: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #dcdfe6;
+ border-radius: 3px;
+ }
+ }
+ }
+
+ &.bot-message {
+ .message-content {
+ align-items: flex-start;
+ }
+ .avatar {
+ background-color: #409eff;
+ color: #fff;
+ }
+ .text-box {
+ background-color: #fff;
+ color: #303133;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+ }
+ }
+
+ &.user-message {
+ flex-direction: row-reverse;
+ .message-content {
+ align-items: flex-end;
+ }
+ .avatar {
+ background-color: #95d475;
+ color: #fff;
+ }
+ .text-box {
+ background-color: #409eff;
+ color: #fff;
+ }
+ }
+}
+
+.charts-wrapper {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ overflow-x: auto;
+ width: 100%;
+ padding-bottom: 8px;
+ &::-webkit-scrollbar {
+ height: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #dcdfe6;
+ border-radius: 3px;
+ }
+}
+
+.chart-item {
+ width: 100%;
+ min-width: 300px;
+ height: 300px;
+ background: #fff;
+ border-radius: 8px;
+ padding: 10px;
+}
+
+.table-wrapper {
+ margin-top: 10px;
+ background: #fff;
+ border-radius: 8px;
+ overflow: hidden;
+ overflow-x: auto;
+ width: 100%;
+ &::-webkit-scrollbar {
+ height: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #dcdfe6;
+ border-radius: 3px;
+ }
+ .el-table {
+ min-width: 300px;
+ }
+}
+
+.input-area {
+ padding: 16px;
+ background-color: #fff;
+ border-top: 1px solid #dcdfe6;
+
+ .input-actions {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 8px;
+ align-items: center;
+
+ .file-upload-trigger {
+ display: inline-flex;
+ align-items: center;
+ }
+}
+
+ .input-box {
+ padding: 12px;
+ position: relative;
+ background: #fff;
+ border: 1px solid #dcdfe6;
+ border-radius: 8px;
+ margin: 0 16px 16px;
+ transition: border-color 0.2s;
+
+ &:focus-within {
+ border-color: #409eff;
+ }
+
+ .selected-file-tag {
+ display: flex;
+ align-items: center;
+ background: #f0f7ff;
+ border: 1px solid #d9ecff;
+ border-radius: 4px;
+ padding: 4px 8px;
+ margin-bottom: 8px;
+ gap: 6px;
+ width: fit-content;
+ max-width: 100%;
+
+ .el-icon {
+ color: #409eff;
+ font-size: 14px;
+ }
+
+ .file-name {
+ font-size: 12px;
+ color: #606266;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .remove-file {
+ cursor: pointer;
+ color: #909399;
+ transition: color 0.2s;
+ &:hover {
+ color: #f56c6c;
+ }
+ }
+ }
+
+ :deep(.el-textarea__inner) {
+ padding: 0;
+ border: none;
+ box-shadow: none;
+ background: transparent;
+ font-family: inherit;
+ font-size: 14px;
+ line-height: 1.5;
+ color: #303133;
+ &::placeholder {
+ color: #c0c4cc;
+ }
+ }
+
+ .send-btn {
+ position: absolute;
+ right: 12px;
+ bottom: 12px;
+ padding: 8px 16px;
+ }
+ }
+}
+
+.typing-indicator {
+ display: flex;
+ gap: 4px;
+ padding: 8px 12px;
+ background: #fff;
+ border-radius: 12px;
+ width: fit-content;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+ margin-top: 4px;
+ .dot {
+ width: 6px;
+ height: 6px;
+ background-color: #909399;
+ border-radius: 50%;
+ animation: typing 1.4s infinite ease-in-out;
+ &:nth-child(2) { animation-delay: 0.2s; }
+ &:nth-child(3) { animation-delay: 0.4s; }
+ }
+}
+
+@keyframes typing {
+ 0%, 80%, 100% { transform: scale(0); }
+ 40% { transform: scale(1); }
+}
+
+.code-block {
+ background: #2d2d2d;
+ color: #ccc;
+ padding: 12px;
+ border-radius: 6px;
+ font-family: monospace;
+ margin: 8px 0;
+ overflow-x: auto;
+ &.js-code {
+ color: #f08d49;
+ }
+}
+</style>
diff --git a/src/layout/index.vue b/src/layout/index.vue
index d3580d0..a1bb724 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -1,131 +1,133 @@
-<template>
- <div :class="classObj"
- class="app-wrapper"
- :style="{ '--current-color': theme }">
- <div v-if="device === 'mobile' && sidebar.opened"
- class="drawer-bg"
- @click="handleClickOutside" />
- <sidebar v-if="!sidebar.hide"
- class="sidebar-container" />
- <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }"
- class="main-container">
- <div :class="{ 'fixed-header': fixedHeader }">
- <navbar @setLayout="setLayout" />
- <tags-view v-if="needTagsView" />
- </div>
- <app-main />
- <settings ref="settingRef" />
- </div>
- </div>
-</template>
-
-<script setup>
- import { useWindowSize } from "@vueuse/core";
- import Sidebar from "./components/Sidebar/index.vue";
- import { AppMain, Navbar, Settings, TagsView } from "./components";
- import defaultSettings from "@/settings";
-
- import useAppStore from "@/store/modules/app";
- import useSettingsStore from "@/store/modules/settings";
-
- const settingsStore = useSettingsStore();
- const theme = computed(() => settingsStore.theme);
- const sideTheme = computed(() => settingsStore.sideTheme);
- const sidebar = computed(() => useAppStore().sidebar);
- const device = computed(() => useAppStore().device);
- const needTagsView = computed(() => settingsStore.tagsView);
- const fixedHeader = computed(() => settingsStore.fixedHeader);
-
- const classObj = computed(() => ({
- hideSidebar: !sidebar.value.opened,
- openSidebar: sidebar.value.opened,
- withoutAnimation: sidebar.value.withoutAnimation,
- mobile: device.value === "mobile",
- }));
-
- const { width, height } = useWindowSize();
- const WIDTH = 992; // refer to Bootstrap's responsive design
-
- watch(
- () => device.value,
- () => {
- if (device.value === "mobile" && sidebar.value.opened) {
- useAppStore().closeSideBar({ withoutAnimation: false });
- }
- }
- );
-
- watchEffect(() => {
- if (width.value - 1 < WIDTH) {
- useAppStore().toggleDevice("mobile");
- useAppStore().closeSideBar({ withoutAnimation: true });
- } else {
- useAppStore().toggleDevice("desktop");
- }
- });
-
- function handleClickOutside() {
- useAppStore().closeSideBar({ withoutAnimation: false });
- }
-
- const settingRef = ref(null);
- function setLayout() {
- settingRef.value.openSetting();
- }
-</script>
-
-<style lang="scss" scoped>
- @import "@/assets/styles/mixin.scss";
- @import "@/assets/styles/variables.module.scss";
-
- .app-wrapper {
- @include clearfix;
- position: relative;
- height: 100%;
- width: 100%;
- background: radial-gradient(
- circle at top,
- rgba(223, 232, 226, 0.95),
- transparent 32%
- ),
- linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%);
-
- &.mobile.openSidebar {
- position: fixed;
- top: 0;
- }
- }
-
- .drawer-bg {
- background: #000;
- opacity: 0.3;
- width: 100%;
- top: 0;
- height: 100%;
- position: absolute;
- z-index: 999;
- }
-
- .fixed-header {
- position: fixed;
- top: 0px;
- padding-top: 12px;
- right: 16px;
- z-index: 9;
- width: calc(100% - #{$base-sidebar-width} - 32px);
- transition: width 0.28s, right 0.28s;
- padding-bottom: 8px;
- background-color: #f3f6f4;
- }
- .hideSidebar .fixed-header {
- width: calc(100% - 100px);
- }
-
- .sidebarHide .fixed-header {
- width: calc(100% - 32px);
- }
-
- .mobile .fixed-header {
- width: 100%;
- }
-</style>
+<template>
+ <div :class="classObj"
+ class="app-wrapper"
+ :style="{ '--current-color': theme }">
+ <div v-if="device === 'mobile' && sidebar.opened"
+ class="drawer-bg"
+ @click="handleClickOutside" />
+ <sidebar v-if="!sidebar.hide"
+ class="sidebar-container" />
+ <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }"
+ class="main-container">
+ <div :class="{ 'fixed-header': fixedHeader }">
+ <navbar @setLayout="setLayout" />
+ <tags-view v-if="needTagsView" />
+ </div>
+ <app-main />
+ <settings ref="settingRef" />
+ </div>
+ <AIChatSidebar />
+ </div>
+</template>
+
+<script setup>
+ import { useWindowSize } from "@vueuse/core";
+ import Sidebar from "./components/Sidebar/index.vue";
+ import { AppMain, Navbar, Settings, TagsView } from "./components";
+ import AIChatSidebar from "@/components/AIChatSidebar/index.vue";
+ import defaultSettings from "@/settings";
+
+ import useAppStore from "@/store/modules/app";
+ import useSettingsStore from "@/store/modules/settings";
+
+ const settingsStore = useSettingsStore();
+ const theme = computed(() => settingsStore.theme);
+ const sideTheme = computed(() => settingsStore.sideTheme);
+ const sidebar = computed(() => useAppStore().sidebar);
+ const device = computed(() => useAppStore().device);
+ const needTagsView = computed(() => settingsStore.tagsView);
+ const fixedHeader = computed(() => settingsStore.fixedHeader);
+
+ const classObj = computed(() => ({
+ hideSidebar: !sidebar.value.opened,
+ openSidebar: sidebar.value.opened,
+ withoutAnimation: sidebar.value.withoutAnimation,
+ mobile: device.value === "mobile",
+ }));
+
+ const { width, height } = useWindowSize();
+ const WIDTH = 992; // refer to Bootstrap's responsive design
+
+ watch(
+ () => device.value,
+ () => {
+ if (device.value === "mobile" && sidebar.value.opened) {
+ useAppStore().closeSideBar({ withoutAnimation: false });
+ }
+ }
+ );
+
+ watchEffect(() => {
+ if (width.value - 1 < WIDTH) {
+ useAppStore().toggleDevice("mobile");
+ useAppStore().closeSideBar({ withoutAnimation: true });
+ } else {
+ useAppStore().toggleDevice("desktop");
+ }
+ });
+
+ function handleClickOutside() {
+ useAppStore().closeSideBar({ withoutAnimation: false });
+ }
+
+ const settingRef = ref(null);
+ function setLayout() {
+ settingRef.value.openSetting();
+ }
+</script>
+
+<style lang="scss" scoped>
+ @import "@/assets/styles/mixin.scss";
+ @import "@/assets/styles/variables.module.scss";
+
+ .app-wrapper {
+ @include clearfix;
+ position: relative;
+ height: 100%;
+ width: 100%;
+ background: radial-gradient(
+ circle at top,
+ rgba(223, 232, 226, 0.95),
+ transparent 32%
+ ),
+ linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%);
+
+ &.mobile.openSidebar {
+ position: fixed;
+ top: 0;
+ }
+ }
+
+ .drawer-bg {
+ background: #000;
+ opacity: 0.3;
+ width: 100%;
+ top: 0;
+ height: 100%;
+ position: absolute;
+ z-index: 999;
+ }
+
+ .fixed-header {
+ position: fixed;
+ top: 0px;
+ padding-top: 12px;
+ right: 16px;
+ z-index: 9;
+ width: calc(100% - #{$base-sidebar-width} - 32px);
+ transition: width 0.28s, right 0.28s;
+ padding-bottom: 8px;
+ background-color: #f3f6f4;
+ }
+ .hideSidebar .fixed-header {
+ width: calc(100% - 100px);
+ }
+
+ .sidebarHide .fixed-header {
+ width: calc(100% - 32px);
+ }
+
+ .mobile .fixed-header {
+ width: 100%;
+ }
+</style>
diff --git a/src/views/fileManagement/borrow/index.vue b/src/views/fileManagement/borrow/index.vue
index 8983665..c7d8e0d 100644
--- a/src/views/fileManagement/borrow/index.vue
+++ b/src/views/fileManagement/borrow/index.vue
@@ -100,16 +100,14 @@
</el-col>
<el-col :span="12">
<el-form-item label="鍊熼槄涔︾睄锛�" prop="documentationId">
- <!-- <el-select v-model="borrowForm.documentationId" placeholder="璇烽�夋嫨鍊熼槄涔︾睄" style="width: 100%" @change="handleScanContent">
- <el-option
- v-for="item in documentList"
- :key="item.id"
- :label="item.docName || item.name"
- :value="item.id"
- />
- </el-select> -->
<div style="display: flex; gap: 10px;">
- <el-select v-model="borrowForm.documentationId" placeholder="璇烽�夋嫨鍊熼槄涔︾睄" style="flex: 1;width: 100px;" @change="handleSelectChange">
+ <el-select
+ v-if="borrowOperationType !== 'edit'"
+ v-model="borrowForm.documentationId"
+ placeholder="璇烽�夋嫨鍊熼槄涔︾睄"
+ style="flex: 1;width: 100px;"
+ @change="handleSelectChange"
+ >
<el-option
v-for="item in documentList"
:key="item.id"
@@ -118,6 +116,13 @@
/>
</el-select>
<el-input
+ v-else
+ v-model="currentEditDocName"
+ style="flex: 1;width: 100px;"
+ disabled
+ />
+ <el-input
+ v-if="borrowOperationType !== 'edit'"
v-model="scanContent"
placeholder="鎵爜杈撳叆"
style="width: 100px;"
@@ -205,6 +210,7 @@
const selectedRows = ref([]);
const documentList = ref([]); // 鏂囨。鍒楄〃锛岀敤浜庡�熼槄涔︾睄閫夋嫨
const scanContent = ref() // 鎵爜鍐呭
+const currentEditDocName = ref(''); // 缂栬緫鏃跺瓨鍌ㄧ殑鏂囨。鍚嶇О
// 鍒嗛〉鐩稿叧
const pagination = reactive({
currentPage: 1,
@@ -282,6 +288,7 @@
{
name: "缂栬緫",
type: "text",
+ disabled: (row) => row.borrowStatus === '褰掕繕',
clickFun: (row) => {
openBorrowDia('edit', row)
},
@@ -428,13 +435,16 @@
if (type === "edit") {
// 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
Object.assign(borrowForm, data);
+ // 瀛樺偍鏂囨。鍚嶇О鐢ㄤ簬鏄剧ず
+ currentEditDocName.value = data.docName || '';
} else {
// 鏂板妯″紡锛屾竻绌鸿〃鍗�
Object.keys(borrowForm).forEach(key => {
borrowForm[key] = "";
});
- // 璁剧疆榛樿鐘舵��
- borrowForm.borrowStatus = "鍊熼槄";
+ currentEditDocName.value = ''; // 娓呯┖缂栬緫鏃剁殑鏂囨。鍚嶇О
+ // 璁剧疆榛樿鐘舵��
+ borrowForm.borrowStatus = "鍊熼槄";
// 璁剧疆褰撳墠鏃ユ湡涓哄�熼槄鏃ユ湡
borrowForm.borrowDate = new Date().toISOString().split('T')[0];
}
@@ -445,6 +455,7 @@
proxy.$refs.borrowFormRef.resetFields();
borrowDia.value = false;
scanContent.value = ''; // 娓呯┖鎵爜鍐呭
+ currentEditDocName.value = ''; // 娓呯┖缂栬緫鏃剁殑鏂囨。鍚嶇О
};
// 鎻愪氦鍊熼槄琛ㄥ崟
diff --git a/src/views/fileManagement/document/index.vue b/src/views/fileManagement/document/index.vue
index c31b044..f4eac2d 100644
--- a/src/views/fileManagement/document/index.vue
+++ b/src/views/fileManagement/document/index.vue
@@ -862,12 +862,14 @@
documentForm[key] = "";
});
documentForm.attachments = []; // 鏂板妯″紡涓嬩篃娓呯┖闄勪欢
- // 璁剧疆榛樿鍊� - 浣跨敤瀛楀吀鏁版嵁鐨勭涓�涓�夐」浣滀负榛樿鍊�
+ // 璁剧疆榛樿鍊� - 鏂囨。鐘舵�侀粯璁よ缃负"姝e父"
if (document_status.value && document_status.value.length > 0) {
- documentForm.docStatus = document_status.value[0].value;
+ const normalStatus = document_status.value.find(item => item.label === '姝e父');
+ documentForm.docStatus = normalStatus ? normalStatus.value : document_status.value[0].value;
}
if (document_urgency.value && document_urgency.value.length > 0) {
- documentForm.urgencyLevel = document_urgency.value[0].value;
+ const normalUrgency = document_urgency.value.find(item => item.label === '鏅��');
+ documentForm.urgencyLevel = normalUrgency ? normalUrgency.value : document_urgency.value[0].value;
}
}
};
diff --git a/src/views/fileManagement/return/index.vue b/src/views/fileManagement/return/index.vue
index bc86c56..097ab29 100644
--- a/src/views/fileManagement/return/index.vue
+++ b/src/views/fileManagement/return/index.vue
@@ -103,16 +103,14 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="鏂囨。锛�" prop="borrowId">
- <!-- <el-select v-model="returnForm.borrowId" placeholder="璇烽�夋嫨鏂囨。" style="flex: 1;" @change="handleDocumentChange">
- <el-option
- v-for="item in documentList"
- :key="item.id"
- :label="item.docName || item.name"
- :value="item.id"
- />
- </el-select> -->
<div style="display: flex; gap: 10px;">
- <el-select v-model="returnForm.borrowId" placeholder="璇烽�夋嫨鏂囨。" style="width: 120px;" @change="handleDocumentChange">
+ <el-select
+ v-if="returnOperationType !== 'edit'"
+ v-model="returnForm.borrowId"
+ placeholder="璇烽�夋嫨鏂囨。"
+ style="width: 120px;"
+ @change="handleDocumentChange"
+ >
<el-option
v-for="item in documentList"
:key="item.id"
@@ -121,6 +119,13 @@
/>
</el-select>
<el-input
+ v-else
+ v-model="currentEditDocName"
+ style="width: 120px;"
+ disabled
+ />
+ <el-input
+ v-if="returnOperationType !== 'edit'"
v-model="scanContent"
placeholder="鎵爜杈撳叆"
style="flex: 1;"
@@ -215,6 +220,7 @@
const documentList = ref([]); // 鏂囨。鍒楄〃
const borrowInfoList = ref([]); // 鍊熼槄淇℃伅鍒楄〃
const scanContent = ref(); // 鎵爜鍐呭
+const currentEditDocName = ref(''); // 缂栬緫鏃跺瓨鍌ㄧ殑鏂囨。鍚嶇О
// 鍒嗛〉鐩稿叧
const pagination = reactive({
@@ -286,6 +292,7 @@
{
name: "缂栬緫",
type: "text",
+ disabled: (row) => row.borrowStatus === '褰掕繕',
clickFun: (row) => {
openReturnDia('edit', row)
},
@@ -396,15 +403,14 @@
if (type === "edit") {
// 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
Object.assign(returnForm, data);
- // 缂栬緫妯″紡涓嬶紝鏂囨。閫夋嫨鍚庤嚜鍔ㄥ~鍏呭�熼槄浜哄拰搴斿綊杩樻棩鏈�
- if (returnForm.borrowId) {
- handleDocumentChange(returnForm.borrowId);
- }
+ // 瀛樺偍鏂囨。鍚嶇О鐢ㄤ簬鏄剧ず
+ currentEditDocName.value = data.docName || '';
} else {
// 鏂板妯″紡锛屾竻绌鸿〃鍗�
Object.keys(returnForm).forEach(key => {
returnForm[key] = "";
});
+ currentEditDocName.value = ''; // 娓呯┖缂栬緫鏃剁殑鏂囨。鍚嶇О
// 璁剧疆榛樿鐘舵��
returnForm.borrowStatus = "褰掕繕";
// 璁剧疆褰撳墠鏃ユ湡涓哄綊杩樻棩鏈�
@@ -418,6 +424,7 @@
returnDia.value = false;
scanContent.value = ''; // 娓呯┖鎵爜鍐呭
borrowInfoList.value = []; // 娓呯┖鍊熼槄淇℃伅鍒楄〃
+ currentEditDocName.value = ''; // 娓呯┖缂栬緫鏃剁殑鏂囨。鍚嶇О
};
// 鎻愪氦褰掕繕琛ㄥ崟
diff --git a/vite.config.js b/vite.config.js
index dc687a8..ac18ec5 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -8,7 +8,7 @@
const { VITE_APP_ENV } = env;
const baseUrl =
env.VITE_APP_ENV === "development"
- ? "http://1.15.17.182:9003"
+ ? "http://localhost:7005"
: env.VITE_BASE_API;
const javaUrl =
env.VITE_APP_ENV === "development"
--
Gitblit v1.9.3