Bläddra i källkod

Merge branch 'master' of https://git.citupro.com/zhengnaiwen_citu/dataAI

zhengnaiwen_citu 1 månad sedan
förälder
incheckning
0a1aa7c6ed
4 ändrade filer med 15413 tillägg och 49 borttagningar
  1. 15312 1
      package-lock.json
  2. 3 1
      package.json
  3. 80 36
      src/views/home/dataChartEditChat.vue
  4. 18 11
      src/views/home/homeSide.vue

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 15312 - 1
package-lock.json


+ 3 - 1
package.json

@@ -17,6 +17,7 @@
     "core-js": "^3.8.3",
     "echarts": "^5.4.3",
     "element-resize-detector": "^1.2.4",
+    "file-saver": "^2.0.5",
     "fs": "0.0.1-security",
     "js-base64": "^3.7.4",
     "lodash": "^4.17.21",
@@ -33,7 +34,8 @@
     "vuex": "^3.6.2",
     "webpack-bundle-analyzer": "^4.10.1",
     "whatwg-fetch": "^3.6.20",
-    "write-file-webpack-plugin": "^4.5.1"
+    "write-file-webpack-plugin": "^4.5.1",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@babel/core": "^7.24.6",

+ 80 - 36
src/views/home/dataChartEditChat.vue

@@ -71,7 +71,7 @@
                   {{ item.content.sql }}
                 </div>
                 <div class="mt-3" v-if="item.content.query_result && item.content.query_result.columns.length">
-                  <div>
+                  <div class="text-right">
                     <v-menu
                       v-model="item.showMenu"
                       :close-on-content-click="false"
@@ -85,10 +85,10 @@
                           v-bind="attrs"
                           text
                           color="primary"
-                        >我要画图</v-btn>
+                        >数据作图</v-btn>
                       </template>
                       <div class="white">
-                        <v-banner>图配置</v-banner>
+                        <v-banner>图配置</v-banner>
                         <div class="pa-3">
                           <v-autocomplete
                             v-model="item.model.typeAxis"
@@ -119,6 +119,12 @@
                         </div>
                       </div>
                     </v-menu>
+                    <v-btn
+                      text
+                      color="primary"
+                      :loading="exportLoading"
+                      @click="onExport(item.content.query_result)"
+                    >数据下载</v-btn>
                   </div>
                   <v-card flat outlined height="324">
                     <div class="pa-3">
@@ -210,7 +216,7 @@
             <v-icon>mdi-send</v-icon>
           </v-btn>
         </div>
-        <div v-if="!react">
+        <!-- <div v-if="!react">
           <v-chip-group
             active-class="primary--text"
             column
@@ -225,7 +231,7 @@
               {{ chip.text }}
             </v-chip>
           </v-chip-group>
-        </div>
+        </div> -->
       </div>
     </div>
   </div>
@@ -237,6 +243,8 @@ import {
   // getAskThroughReact,
   addFeedback
 } from '@/api/dataChart'
+import * as XLSX from 'xlsx'
+import { saveAs } from 'file-saver'
 import { mapGetters } from 'vuex'
 export default {
   name: 'dataChartEditChat',
@@ -247,11 +255,12 @@ export default {
   },
   data () {
     return {
-      routingMode: undefined,
-      chips: [
-        { text: '聊天模式', value: 'chat_direct' },
-        { text: '数据库模式', value: 'database_direct' }
-      ],
+      // routingMode: undefined,
+      // chips: [
+      //   { text: '聊天模式', value: 'chat_direct' },
+      //   { text: '数据库模式', value: 'database_direct' }
+      // ],
+      exportLoading: false,
       loading: false,
       disabled: false,
       question: '',
@@ -303,18 +312,17 @@ export default {
       return new Promise((resolve, reject) => {
         // 先关闭现有连接
         this.stopSSE()
-        const query = this.react
-          ? {
-              question: encodeURIComponent(ask.question),
-              user_id: this.userInfo.id,
-              conversation_id: this.conversationId
-            }
-          : {
-              question: encodeURIComponent(ask.question),
-              user_id: this.userInfo.id,
-              routing_mode: this.routingMode,
-              conversation_id: this.conversationId
-            }
+        const query = {
+          question: encodeURIComponent(ask.question),
+          user_id: this.userInfo.id,
+          conversation_id: this.conversationId
+        }
+        // : {
+        //     question: encodeURIComponent(ask.question),
+        //     user_id: this.userInfo.id,
+        //     // routing_mode: this.routingMode,
+        //     conversation_id: this.conversationId
+        //   }
         const queryStr = Object.keys(query).reduce((acc, key) => {
           if (query[key] === undefined) {
             return acc
@@ -464,26 +472,62 @@ export default {
         this.abortController = null
       }
       this.items.splice(1, this.items.length - 1, ...data.messages.map(e => {
-        if (e.role === 'user') {
+        if (e.role === 'assistant' || e.role === 'ai') {
+          if (!this.react) {
+            e.metadata.response = e.content
+          }
+
           return {
-            type: 2,
-            user: '游客',
-            content: e.content
+            type: 1,
+            content: this.react ? e.content : e.metadata,
+            showSnackbar: false,
+            dataValidation: false,
+            question: e.content, // 记录当前问题
+            showMenu: false,
+            model: {
+              dataAxis: null,
+              typeAxis: null
+            }
           }
         }
         return {
-          type: 1,
-          content: e.metadata,
-          showSnackbar: false,
-          dataValidation: false,
-          question: e.content, // 记录当前问题
-          showMenu: false,
-          model: {
-            dataAxis: null,
-            typeAxis: null
-          }
+          type: 2,
+          user: '游客',
+          content: e.content
         }
       }))
+    },
+    onExport ({ columns, rows }) {
+      const sheetName = 'Sheet1'
+      const fileName = '数据下载'
+      this.exportLoading = true
+      try {
+        // 准备Excel数据
+        const excelData = [columns]
+
+        // 添加数据行
+        rows.forEach(item => {
+          const row = columns.map(header => item[header])
+          excelData.push(row)
+        })
+
+        // 创建工作簿
+        const ws = XLSX.utils.aoa_to_sheet(excelData)
+        const wb = XLSX.utils.book_new()
+        XLSX.utils.book_append_sheet(wb, ws, sheetName)
+
+        // 生成Excel文件并下载
+        const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
+        const blob = new Blob([excelBuffer], {
+          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+        })
+        saveAs(blob, `${fileName}.xlsx`)
+      } catch (error) {
+        console.log(error)
+        this.$snackbar.error('Excel导出失败')
+      } finally {
+        this.exportLoading = false
+      }
     }
   }
 }

+ 18 - 11
src/views/home/homeSide.vue

@@ -7,7 +7,13 @@
     <template v-slot:prepend>
       <v-list-item :light="!react">
         <v-list-item-content>
-          <v-list-item-title class="text-h6">AI取数 <small class="indigo--text">{{ react ? '(REACT模式)' : '' }}</small></v-list-item-title>
+          <v-list-item-title class="text-h6">
+            AI取数
+            <small class="indigo--text">{{ react ? '(思考模式)' : '(取数模式)' }}</small>
+            <v-btn icon small color="indigo" @click="handleReact">
+              <v-icon>mdi-swap-horizontal</v-icon>
+            </v-btn>
+          </v-list-item-title>
           <!-- <v-list-item-subtitle>Logged In</v-list-item-subtitle> -->
         </v-list-item-content>
       </v-list-item>
@@ -59,20 +65,18 @@
             v-for="(item, index) in fabItems"
             :key="index"
           >
-            <v-btn fab :color="item.color" x-small depressed @click="$router.push(item.to)">
+            <v-btn  disabled light fab :color="item.color" x-small depressed @click="$router.push(item.to)">
               <v-icon>{{ item.icon }}</v-icon>
             </v-btn>
-            <div class="text-caption" :class="item.textColor">
+            <div class="text-caption" >
+            <!-- <div class="text-caption" :class="item.textColor"> -->
               {{ item.text }}
             </div>
           </div>
         </div>
-        <v-btn class="mb-3" color="indigo" block @click="$router.push('/my-chart')">
+        <v-btn class="mb-3" light color="indigo" block @click="$router.push('/my-chart')" disabled>
           我的图表
         </v-btn>
-        <v-btn class="mb-3" block color="indigo" @click="handleReact">
-          切换{{ react ? 'ASK模式' : 'REACT模式' }}
-        </v-btn>
         <v-btn block color="indigo" @click="handleLogout">
           Logout
         </v-btn>
@@ -148,12 +152,15 @@ export default {
         return
       }
       this.lastSelected = index
+      this.loading = true
       try {
         const getApi = this.react ? getConversationsByIdThroughReact : getConversationsById
         const { data } = await getApi(this.conversationList[index].conversation_id)
         this.$emit('update', data)
       } catch (error) {
         this.$snackbar.error(error)
+      } finally {
+        this.loading = false
       }
     },
 
@@ -162,12 +169,12 @@ export default {
     },
     handleReact () {
       if (this.react) {
-        // this.$router.push('/home')
-        window.open('/home', '_blank')
+        this.$router.push('/home')
+        // window.open('/home', '_blank')
         return
       }
-      window.open('/react', '_blank')
-      // this.$router.push('/react')
+      // window.open('/react', '_blank')
+      this.$router.push('/react')
     }
   }
 }

Vissa filer visades inte eftersom för många filer har ändrats