Parcourir la source

feat: 新增对应菜单

whh il y a 8 mois
Parent
commit
1088e965cf

+ 3 - 1
.env.development

@@ -5,5 +5,7 @@ VITE_APP_TITLE = 人工智能运营体决策助手
 VITE_APP_ENV = 'development'
 
 # 管理系统/开发环境
-# VITE_APP_BASE_API = '/dev-api'
 VITE_APP_BASE_API = http://10.0.0.28:8080/
+
+VITE_APP_BASE_TEST = http://10.0.0.28:8080/
+VITE_APP_BASE_PROD = http://192.168.9.54:8080/

+ 5 - 2
.env.production

@@ -5,7 +5,10 @@ VITE_APP_TITLE = 人工智能运营体决策助手
 VITE_APP_ENV = 'production'
 
 # 管理系统/生产环境
-VITE_APP_BASE_API = 'http://10.0.0.28:8080/'
+VITE_APP_BASE_API = 'http://192.168.9.54:8080/'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
-VITE_BUILD_COMPRESS = gzip
+VITE_BUILD_COMPRESS = gzip
+
+VITE_APP_BASE_TEST = http://10.0.0.28:8080/
+VITE_APP_BASE_PROD = http://192.168.9.54:8080/

+ 1 - 1
package.json

@@ -21,7 +21,7 @@
     "@vueup/vue-quill": "1.2.0",
     "@vueuse/core": "10.6.1",
     "axios": "0.27.2",
-    "echarts": "5.4.3",
+    "echarts": "^5.5.0",
     "element-plus": "2.4.3",
     "file-saver": "2.0.5",
     "fuse.js": "6.6.2",

+ 44 - 0
src/api/business/feedback.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询信义意见反馈列表
+export function listFeedback(query) {
+  return request({
+    url: '/business/feedback/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询信义意见反馈详细
+export function getFeedback(id) {
+  return request({
+    url: '/business/feedback/' + id,
+    method: 'get'
+  })
+}
+
+// 新增信义意见反馈
+export function addFeedback(data) {
+  return request({
+    url: '/business/feedback',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改信义意见反馈
+export function updateFeedback(data) {
+  return request({
+    url: '/business/feedback',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除信义意见反馈
+export function delFeedback(id) {
+  return request({
+    url: '/business/feedback/' + id,
+    method: 'delete'
+  })
+}

+ 10 - 1
src/api/daily/index.js

@@ -3,7 +3,16 @@ import request from '@/utils/request';
 // 新增日报
 export function postDaily(data) {
   return request({
-    url: '/business/daily',
+    url: import.meta.env.VITE_APP_BASE_TEST + 'business/daily',
+    method: 'post',
+    data: data
+  })
+}
+
+// 新增日报
+export function postProdDaily(data) {
+  return request({
+    url: import.meta.env.VITE_APP_BASE_PROD + 'business/daily',
     method: 'post',
     data: data
   })

BIN
src/assets/images/chat/bg-raido-check.png


BIN
src/assets/images/chat/img-avatar.png


BIN
src/assets/images/chat/img-user-avatar.png


+ 2 - 0
src/components/chat/ChatAnswer.vue

@@ -18,6 +18,8 @@ const props = defineProps({
 <template>
   <ChatBaseCard class="answer-inner" >
     
+    <slot></slot>
+
     <template #text>
       <ChatText :content="content"></ChatText>
     </template>

+ 312 - 0
src/utils/echartOptions.js

@@ -0,0 +1,312 @@
+import * as echarts from 'echarts';
+
+export const getAreaOptions = ({ xAxisData, seriesList }) => {
+  const series = seriesList.map((data, index) => {
+    const i = !index;
+    return {
+      name: i ? '过去' : '未来',
+      type: 'line',
+      symbol: 'circle',
+      showAllSymbol: true,
+      symbolSize: 5,
+      smooth: true,
+      lineStyle: {
+        normal: {
+          width: 2,
+          color: i ? "rgba(25,163,223,1)" : "rgba(36,175,83,1)", // 线条颜色
+        },
+        borderColor: 'rgba(0,0,0,.4)',
+      },
+      itemStyle: {
+        color: i ? "#b7f9ff" : "#fff",
+        borderColor: i ? "#2185da" : "#2ee055",
+        borderWidth: 1,
+        shadowColor: 'rgba(22, 137, 229)',
+        shadowBlur: 1
+      },
+      areaStyle: {
+        normal: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+            offset: 0,
+            color: i ? "rgba(25,163,223,.3)" : "rgba(48, 209, 136,.3)"
+          },
+          {
+            offset: 1,
+            color: i ? "rgba(25,163,223, 0)" : "rgba(48, 209, 136, 0)"
+          }
+          ], false),
+          shadowColor: 'rgba(25,163,223, 0.5)',
+          shadowBlur: 20
+        }
+      },
+      z: i ? 3 : 2,
+      data,
+    }
+  })
+
+  return {
+    backgroundColor: '#fff',
+    tooltip: {
+      trigger: "axis",
+      zIndex: 10000,
+      show: true,
+      formatter: function (params) {
+        const [item] = params.filter(item => item.value);
+        const color = item.dataIndex <= 5 ? '#2185da' : '#2ee055'
+        console.log(123123)
+        return `
+          <div class="text-[12px]">
+            <p>时间:${item.name + ':00'}</p>
+            <p class="flex items-center space-x-[6px]">
+              <span class="block w-[6px] h-[6px] rounded-full bg-[${color}]"></span>
+              <span>${Number(item.value.toFixed(2))} mg/L</span>
+            </p>
+          </div>
+          `
+      },
+    },
+    grid: {
+      top: '10',
+      left: 60,
+      right: '5%',
+      bottom: '15%',
+    },
+    xAxis: [{
+      type: 'category',
+      boundaryGap: false,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#e0e6f1'
+        },
+      },
+      axisLabel: {
+        textStyle: {
+          color: '#1F2328',
+          fontSize: 12,
+        },
+        formatter: function (data) {
+          return data + ":00"
+        }
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          type: 'dashed',
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      data: xAxisData
+    }],
+    yAxis: [{
+      name: '',
+      nameTextStyle: {
+        fontSize: 12,
+        align: 'right',
+        padding: [10, 5],
+      },
+      min: 0,
+      splitLine: {
+        show: true,
+        lineStyle: {
+          type: 'dashed',
+        },
+      },
+      axisLine: {
+        show: false,
+        lineStyle: {
+          color: "#233653"
+        }
+      },
+      axisLabel: {
+        show: true,
+        textStyle: {
+          color: '#1F2328',
+          padding: 0
+        },
+        formatter: function (value) {
+          if (value === 0) {
+            return value
+          }
+          return value
+        }
+      },
+      axisTick: {
+        show: false,
+      },
+    }],
+    series
+  }
+}
+
+export const getOrderAreaOptions = ({ xAxisData, yAxisData, whichWay }) => {
+
+  const color = [
+    '#0FFEFF',
+    '#FFCA06',
+    '#3DD784',
+    '#3D80FF',
+    '#D35AE8',
+    '#EC2E72',
+    '#8B4513',
+  ];
+
+  const commonYAxisOptions = {
+    name: '',
+    nameTextStyle: {
+      fontSize: 12,
+      align: 'right',
+      padding: [10, 5],
+    },
+    min: 0,
+    splitLine: {
+      show: true,
+      lineStyle: {
+        type: 'dashed',
+      },
+    },
+    axisLine: {
+      show: false,
+      lineStyle: {
+        color: "#233653"
+      }
+    },
+    axisLabel: {
+      show: true,
+      color: '#666',
+      padding: 0,
+      formatter: function (value) {
+        return value
+      }
+    },
+    axisTick: {
+      show: false,
+    },
+  }
+
+  const series = [];
+
+  const arrKey = yAxisData.map(item => item.key);
+  const isIncludeAssignKey = arrKey.includes('csSlqc') || arrKey.includes('jsSlq');
+  const isOneSelfKey = isIncludeAssignKey && arrKey.length === 1;
+
+  yAxisData.map((item, index) => {
+    const itemColor = color[index];
+    let yAxisIndex = Number(item.key === 'csSlqc' || item.key === 'jsSlq')
+
+    if ( isOneSelfKey ) yAxisIndex = 0;
+
+    series.push({
+      name: item.title,
+      type: 'line',
+      symbol: 'circle',
+      showAllSymbol: true,
+      smooth: true,
+      symbolSize: 5,
+      yAxisIndex,
+      lineStyle: {
+        width: 2,
+        color: itemColor,
+        borderColor: 'rgba(0,0,0,.4)',
+      },
+      itemStyle: {
+        color: itemColor,
+        borderColor: itemColor,
+        borderWidth: 3,
+      },
+      tooltip: {
+        valueFormatter: function (value) {
+          const wihteKeyList = ['jsSlq', 'csSlqc'];
+          let unit = '';
+
+          if(wihteKeyList.includes(item.key)) {
+            unit = whichWay === 1 ? ' m³/h' : ' m³/d';
+          } else if (item.key !== 'time') {
+            unit = ' mg/L';
+          }
+
+          return value + unit;
+        },
+      },
+      data: item.list,
+    });
+  });
+
+  return {
+    series,
+    tooltip: {
+      trigger: 'axis',
+    },
+    backgroundColor: '#fff',
+    grid: {
+      top: 40,
+      // left: 40,
+      // right: 50,
+      bottom: 30,
+    },
+    legend: {
+      orient: 'horizontal',
+      fontSize: '20px',
+      icon: 'rect',
+      itemWidth: 6,
+      itemHeight: 2,
+      // formatter: ['{a|{name}}'].join('\n'),
+      formatter: function (name) {
+        const isNeedUnit  = name === '进水水量' || name === '出水水量';
+        return isNeedUnit ? `{a|${name}(次)}` : `{a|${name}}`
+      },
+      textStyle: {
+        rich: {
+          a: {
+            width: 20,
+            color: '#666',
+            fontSize: 10,
+            lineHeight: 18,
+          },
+        },
+      },
+      right: '4',
+      top: '10',
+    },
+    xAxis: [{
+      type: "category",
+      axisLabel: {
+        color: "#666",
+        fontSize: 12,
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: "rgba(127, 214, 255, .4)",
+        },
+      },
+      splitLine: {
+        show: true,
+        interval: '0',
+        lineStyle: {
+          type: 'dashed',
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: false,
+      data: xAxisData
+    }],
+    yAxis: [
+      {
+        ...commonYAxisOptions,
+        position: 'left'
+      },
+      {
+        ...commonYAxisOptions,
+        position: 'right',
+        splitLine: {
+          show: false
+        }
+      }
+    ],
+  }
+}

+ 38 - 0
src/utils/enum.js

@@ -0,0 +1,38 @@
+export const ORDER_OPTION_ENUM = {
+  time:         '日期',
+  jsSlq:        '进水水量',
+  jsCod:        'COD',
+  jsTn:         '总氮',
+  jsTp:         '总磷',
+  jsNh3:        '氨氮',
+  jsSs:         'SS',
+  csSlqc:       '出水水量',
+  csCod:        'COD',
+  csTn:         '总氮',
+  csTp:         '总磷',
+  csNh3:        '氨氮',
+  csSs:         'SS',
+  no3Hlj1Jqr:   '1#好氧池硝酸盐',
+  no3Hlj2Jqr:   '2#好氧池硝酸盐',
+  nh31Jqr:      '1#缺氧氨氮',
+  nh32Jqr:      '2#缺氧氨氮',
+  no3Qyc1Jqr:   '1#缺氧池硝酸盐',
+  no3Qyc2Jqr:   '2#缺氧池硝酸盐',
+  tpRccJqr:     '二沉池正磷酸盐'
+}
+
+export const SIMULATE_ENUM = {
+  COD_in:       '进水COD mg/L',
+  DO_O:         '好氧池末端DO (#1 #2) mg/L',
+  MLSS:         'MLSS (#1 #2) mg/L',
+  Q_in:         '进水流量 m3/h',
+  tyjyl:        '碳源药剂投加量 m³/h',
+  r:            '内回流比(#1 #2) %',
+  cltjl:        '除磷药剂投加量m³/h',
+  gwnl:         '干污泥量',
+  hycxsy_all:   '好氧硝酸盐(#1 #2) mg/L',
+  qyan_all:     '缺氧氨氮(#1 #2) mg/L',
+  qyckxsy_all:  '缺氧硝酸盐 mg/L',
+  T:            '水温 ℃',
+  pH:           'pH'
+}

+ 1 - 1
src/utils/format.js

@@ -1,4 +1,4 @@
-// import { ORDER_OPTION_ENUM } from "./enum";
+import { ORDER_OPTION_ENUM } from "./enum";
 
 
 export const formatToData = (dataSource, warnKey) => {

+ 73 - 11
src/views/business/assistant/index.vue

@@ -9,14 +9,14 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="类型" prop="category">
+      <!-- <el-form-item label="类型" prop="category">
         <el-input
           v-model="queryParams.category"
           placeholder="请输入分类"
           clearable
           @keyup.enter.native="handleQuery"
         />
-      </el-form-item>
+      </el-form-item> -->
       <el-form-item>
         <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
         <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
@@ -112,10 +112,10 @@
       </el-table>
       
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
-        :page.sync="queryParams.pageNum"
-        :limit.sync="queryParams.pageSize"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
         @pagination="getList"
       />
     </el-card>
@@ -130,10 +130,27 @@
           <el-input v-model="form.title" placeholder="请输入标题" />
         </el-form-item>
         <el-form-item label="提示词内容">
-          <editor v-model="form.content" :min-height="192"/>
+          <el-input
+            v-model="form.content"
+            :rows="4"
+            resize="none" 
+            type="textarea"
+            placeholder="提示词内容"
+          />
         </el-form-item>
-        <el-form-item label="banner地址" prop="banner">
-          <el-input v-model="form.banner" placeholder="请输入banner地址" />
+        <el-form-item label="icon地址" prop="banner">
+          <el-upload
+            class="avatar-uploader"
+            :headers="headers"
+            :action="path"
+            :show-file-list="false"
+            :on-success="handleAvatarSuccess"
+            :before-upload="beforeAvatarUpload"
+          >
+            <img v-if="form.banner" :src="form.banner" class="avatar" />
+            <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+          </el-upload>
+          <!-- <el-input v-model="form.banner" placeholder="请输入banner地址" /> -->
         </el-form-item>
         <el-form-item label="排序" prop="sort">
           <el-input v-model="form.sort" placeholder="请输入排序" />
@@ -149,11 +166,17 @@
 
 <script>
 import { listAssistant, getAssistant, delAssistant, addAssistant, updateAssistant } from "@/api/business/assistant";
+import { getToken } from "@/utils/auth";
 
 export default {
   name: "Assistant",
   data() {
     return {
+      path: import.meta.env.VITE_APP_BASE_API + 'qiniuyun/upLoadImage',
+      imageUrl: '',
+      headers: {
+        Authorization: 'Bearer ' + getToken()
+      },
       // 遮罩层
       loading: true,
       // 选中数组
@@ -194,6 +217,17 @@ export default {
     this.getList();
   },
   methods: {
+    handleAvatarSuccess(res) {
+      this.imageUrl = res.data;
+      this.form.banner = res.data;
+    },
+    beforeAvatarUpload (rawFile){
+      if (rawFile.size / 1024 / 1024 > 2) {
+        ElMessage.error('图片大小最大 2MB!')
+        return false
+      }
+      return true
+    },
     /** 查询信义智能体助手配置列表 */
     getList() {
       this.loading = true;
@@ -247,7 +281,7 @@ export default {
     handleAdd() {
       this.reset();
       this.open = true;
-      this.title = "添加智能体助手配置";
+      this.title = "添加智慧办公";
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
@@ -256,7 +290,7 @@ export default {
       getAssistant(id).then(response => {
         this.form = response.data;
         this.open = true;
-        this.title = "修改智能体助手配置";
+        this.title = "修改智慧办公";
       });
     },
     /** 提交按钮 */
@@ -282,7 +316,7 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$modal.confirm('是否确认删除信义智能体助手配置编号为"' + ids + '"的数据项?').then(function() {
+      this.$modal.confirm('是否确认删除数据项?').then(function() {
         return delAssistant(ids);
       }).then(() => {
         this.getList();
@@ -307,4 +341,32 @@ export default {
   word-break: break-all;
   white-space: nowrap;
 }
+.avatar-uploader .el-upload {
+  border: 1px dashed var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 60px;
+  height: 60px;
+  text-align: center;
+}
+</style>
+
+<style scoped>
+.avatar-uploader .avatar {
+  width: 60px;
+  height: 60px;
+  display: block;
+}
 </style>

+ 272 - 0
src/views/business/feedback/index.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="page-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" class="search-form_container">
+      <el-form-item label="问题描述" prop="description">
+        <el-input
+          v-model="queryParams.description"
+          placeholder="请输入问题描述"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="联系方式" prop="phone">
+        <el-input
+          v-model="queryParams.phone"
+          placeholder="请输入联系方式"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-card shadow="never" body-class="card-table_container">
+    <el-row :gutter="10" class="mb8">
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="plus"
+          size="small"
+          @click="handleAdd"
+        >新增</el-button>
+      </el-col> -->
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="edit"
+          size="small"
+          :disabled="single"
+          @click="handleUpdate"
+        >修改</el-button>
+      </el-col> -->
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="delete"
+          size="small"
+          :disabled="multiple"
+          @click="handleDelete"
+        >删除</el-button>
+      </el-col> -->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="download"
+          size="small"
+          @click="handleExport"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="feedbackList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="问题描述" align="center" prop="description" />
+      <el-table-column label="联系方式" align="center" prop="phone" />
+      <el-table-column label="时间" align="center" prop="createTime" />
+      <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button
+            size="small"
+            type="primary"
+            text
+            icon="edit"
+            @click="handleUpdate(scope.row)"
+          >修改</el-button>
+          <el-button
+            size="small"
+            type="primary"
+            text
+            icon="delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+        </template>
+      </el-table-column> -->
+    </el-table>
+    
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </el-card>
+    <!-- 添加或修改信义意见反馈对话框 -->
+    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="问题描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="联系方式" prop="phone">
+          <el-input v-model="form.phone" placeholder="请输入联系方式" />
+        </el-form-item>
+        <el-form-item label="删除标志" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除标志" />
+        </el-form-item>
+        <el-form-item label="乐观锁" prop="revision">
+          <el-input v-model="form.revision" placeholder="请输入乐观锁" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listFeedback, getFeedback, delFeedback, addFeedback, updateFeedback } from "@/api/business/feedback";
+
+export default {
+  name: "Feedback",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 信义意见反馈表格数据
+      feedbackList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        description: null,
+        phone: null,
+        revision: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询信义意见反馈列表 */
+    getList() {
+      this.loading = true;
+      listFeedback(this.queryParams).then(response => {
+        this.feedbackList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        description: null,
+        phone: null,
+        delFlag: null,
+        revision: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加信义意见反馈";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFeedback(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改信义意见反馈";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateFeedback(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFeedback(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除信义意见反馈编号为"' + ids + '"的数据项?').then(function() {
+        return delFeedback(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('business/feedback/export', {
+        ...this.queryParams
+      }, `feedback_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>

+ 521 - 0
src/views/business/forecast/index.vue

@@ -0,0 +1,521 @@
+<template>
+  <!-- 水质报警 -->
+  <div class="page-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
+      class="search-form_container">
+      <!-- <el-form-item label="预警内容" prop="unknown">
+        <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item> -->
+      <el-form-item label="预警类型" prop="category">
+        <el-select v-model="queryParams.category">
+          <el-option value="" label="全部"></el-option>
+          <el-option key="出水COD" value="出水COD" label="出水COD"></el-option>
+          <el-option key="出水SS" value="出水SS" label="出水SS"></el-option>
+          <el-option key="出水总氮" value="出水总氮" label="出水总氮"></el-option>
+          <el-option key="出水总磷" value="出水总磷" label="出水总磷"></el-option>
+          <el-option key="出水氨氮" value="出水氨氮" label="出水氨氮"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="预警状态" prop="warningStatus">
+        <el-select v-model="queryParams.warningStatus">
+          <el-option value="" label="全部"></el-option>
+          <el-option :key="item.label" :value="item.val" :label="item.label" v-for="item in warningStatus"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-card shadow="never" body-class="card-table_container">
+      <el-row :gutter="10" class="mb8">
+        <!-- <el-col :span="1.5">
+          <el-button type="primary" plain icon="plus" size="small" @click="handleAdd">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="success" plain icon="edit" size="small" :disabled="single"
+            @click="handleUpdate">修改</el-button>
+        </el-col> -->
+        <el-col :span="1.5">
+          <el-button type="danger" plain icon="delete" size="small" :disabled="multiple"
+            @click="handleDelete">删除</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="warning" plain icon="download" size="small" @click="handleExport">导出</el-button>
+        </el-col>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      </el-row>
+      <el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="预警类型" align="center" prop="category" />
+        <el-table-column label="预警内容" align="center" prop="reason" />
+        <el-table-column label="现在值" align="center" prop="warningVal">
+          <template #default="scope">
+            <span>{{ Number(scope.row.warningVal.toFixed(2)) }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="预测值" align="center" prop="forecastVal">
+          <template #default="scope">
+            <span style="color: red;">{{ scope.row.forecastVal }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="管控值" align="center" prop="controlVal">
+          <template #default="scope">
+            <span>{{ scope.row.controlVal }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="标准值" align="center" prop="designVal">
+          <template #default="scope">
+            <span>{{ scope.row.designVal }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="预警次数" align="center" prop="counts" />
+        <el-table-column label="预警时间" align="center" prop="updateTime" />
+        <el-table-column label="超标时间" align="center" prop="time" />
+        <el-table-column label="状态" align="center" prop="status" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
+          <template #default="scope">
+            <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">查看记录</el-button>
+            <!-- <el-button size="small" type="text" icon="edit" @click="handleUpdate(scope.row)">修改</el-button> -->
+            <!-- <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+      
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <el-dialog title="生化报警记录" v-model="recordVisible" width="880px" append-to-body class="chat-dialog_container" @opened="opened">
+      <el-scrollbar height="600px">
+        <ChatBaseCard>
+          <div class="waring-answer-wrapper">
+            <dl class="message-inner warning-info_medium flex flex-col justify-between">
+              <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.title }}</dt>
+              <dd v-for="item, index in textDataSources?.list" :key="index"><span
+                  :class="{ 'text-[#F44C49]': item.isWarning }">{{ item.label }}: {{ item.value }}</span></dd>
+            </dl>
+            <div class="table-inner">
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前进水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="jsTableData" style="width: 100%" size="small">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前出水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="csTableData" style="width: 100%" size="small">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+            </div>
+          </div>
+          
+          <div class="echart-warpper flex justify-center text-center pt-[50px]">
+            <div class="">
+              <span class="#1A2029 font-bold">{{ chartTitle }}</span>
+              <div id="chartContainer" class="w-[660px] h-[200px]" ref="echartRef"></div>
+              <ul class="flex justify-between w-[660px] text-center text-[12px] text-[#666] leading-[18px]">
+                <li class="w-[400px] pl-[30px]">
+                  <span class="inline-block w-[10px] h-[2px] mb-[2px] mr-[4px] bg-[#2185da]"></span>
+                  <span>过去</span>
+                </li>
+                <li class="flex-1 pr-[30px]">
+                  <span class="inline-block w-[10px] h-[2px] mb-[2px] mr-[4px] bg-[#2ee055]"></span>
+                  <span>未来</span>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </ChatBaseCard>
+
+        <ChatAnswer :loading="false" :delay-loading="false" :toggleVisibleIcons="false" :content="answerResult"
+        v-if="answerResult" />
+      </el-scrollbar>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWarn, getWarn } from "@/api/business/water";
+import { formatToData, replaceArray  } from "@/utils/format";
+import * as echarts from 'echarts';
+import { getAreaOptions } from "@/utils/echartOptions";
+import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/business/record";
+import { ChatAsk, ChatAnswer, ChatBaseCard } from "@/components/chat"
+export default {
+  name: "Record",
+  components: { ChatAsk, ChatAnswer, ChatBaseCard },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 信义大模型问答记录表格数据
+      recordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        revision: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      warningStatus: [
+        {
+          val: 0,
+          label: '预警中'
+        },
+        {
+          val: 2,
+          label: '已完成'
+        },
+      ],
+      recordVisible: false,
+      answerResult: [],
+      textDataSources: null,
+      jsTableData: [],
+      csTableData: [],
+      chartTitle: '',
+      echartRef: null,
+      chart: null
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    opened() {
+      this.createLineChat(this.chartsData);
+    },
+    // 创建图表
+    createLineChat(data) {
+      const [xAxisData, yData] = data.reduce((acc, { time, val }) => {
+        acc[0].push(time);
+        acc[1].push(val);
+        return acc;
+      }, [[], []]);
+
+      const seriesPast = replaceArray([...yData], yData.length - 3, 3, null);
+      const seriesFuture = replaceArray([...yData], 0, 5, null);
+      const option = getAreaOptions({xAxisData, seriesList: [seriesPast, seriesFuture]});
+      
+      const chart = echarts.init(this.$refs.echartRef, 'light');
+      chart.setOption(option);
+    },
+    // 查看详情
+    handleRecordDetails({ row }) {
+
+      getWarn(row.id).then(({ data }) => {
+        const showVal = JSON.parse(data.showVal);
+        const { basic, jsData, csData, chartsData, chartsTitle } = showVal;
+        this.answerResult = data.answer;
+
+        this.chartTitle = chartsTitle;
+
+        basic.title = row.reason;
+        this.textDataSources = formatToData(basic, '预测值');
+
+        this.jsTableData = [jsData];
+        this.csTableData = [csData];
+
+        this.recordVisible = true;
+        this.chartsData = chartsData;
+        
+      })
+    },
+    /** 查询信义大模型问答记录列表 */
+    getList() {
+      this.loading = true;
+      const enumType = {
+        '0': { color: 'tips_warning', label: '预警中' },
+        '2': { color: 'tips_close', label: '已完成' },
+      }
+      listWarn({ ...this.queryParams, type: 2 }).then(response => {
+        this.recordList = response.rows.map(item => ({
+          ...item,
+          status: enumType[item.status].label
+        }));
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        delFlag: null,
+        revision: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加信义大模型问答记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改信义大模型问答记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateRecord(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecord(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除该数据项?').then(function () {
+        return delRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('business/record/export', {
+        ...this.queryParams
+      }, `record_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.waring-answer-wrapper {
+  display: flex;
+  justify-content: space-between;
+
+  .message-inner {
+    width: 210px;
+    flex-shrink: 0;
+
+    span {
+      white-space: nowrap;
+    }
+  }
+
+  .table-inner {
+    width: 100%;
+    padding-left: 20px;
+    .warning-table {
+      width: 100%;
+
+      .title {
+        margin-bottom: 8px;
+        line-height: 16px;
+        font-size: 12px;
+        font-weight: bold;
+        color: #1A2029;
+      }
+    }
+  }
+}
+
+.radio-wrapper {
+
+.radio-btn-group {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  text-align: center;
+  color: #5E5E5E;
+
+  .radio-btn {
+    width: 62px;
+    height: 28px;
+    border-radius: 4px;
+    background: #F4F6F8;
+    font-size: 14px;
+    line-height: 26px;
+    cursor: pointer;
+
+    &.active,
+    &:hover {
+      color: #2454FF;
+      background: #E2F1FF;
+    }
+
+    &.active {
+      background: #E2F1FF url('@/assets/images/chat/bg-raido-check.png') right bottom no-repeat;
+    }
+  }
+}
+
+}
+</style>

+ 407 - 0
src/views/business/order/index.vue

@@ -0,0 +1,407 @@
+<template>
+  <!-- 日报工单 -->
+  <div class="page-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
+      class="search-form_container">
+      <el-form-item label="问题内容" prop="question">
+        <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <!-- <el-form-item label="类型" prop="unknown">
+        <el-input v-model="queryParams.module" placeholder="请输入隶属哪个模块" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item> -->
+      <el-form-item>
+        <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-card shadow="never" body-class="card-table_container">
+      <el-row :gutter="10" class="mb8">
+        <!-- <el-col :span="1.5">
+          <el-button type="primary" plain icon="plus" size="small" @click="handleAdd">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="success" plain icon="edit" size="small" :disabled="single"
+            @click="handleUpdate">修改</el-button>
+        </el-col> -->
+        <el-col :span="1.5">
+          <el-button type="danger" plain icon="delete" size="small" :disabled="multiple"
+            @click="handleDelete">删除</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="warning" plain icon="download" size="small" @click="handleExport">导出</el-button>
+        </el-col>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      </el-row>
+      <el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="用户名" align="center" prop="createBy" />
+        <el-table-column label="手机号" align="center" prop="phonenumber" />
+        <!-- <el-table-column label="回答" align="center" prop="showVal" /> -->
+        <el-table-column label="问题内容" align="center" prop="showVal" width="500px" />
+        <el-table-column label="发起时间" align="center" prop="createTime" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
+          <template #default="scope">
+            <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">记录</el-button>
+            <!-- <el-button size="small" type="text" icon="edit" @click="handleUpdate(scope.row)">修改</el-button> -->
+            <!-- <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <el-dialog title="日报记录" v-model="recordVisible" width="900px" append-to-body class="chat-dialog_container" @opened="opened">
+      <el-scrollbar height="600px">
+        <div class="conversation-item" v-show="chatDataSource.length">
+        <div v-for="item in chatDataSource" :key="item.sessionId">
+          <ChatAsk :content="item.showVal" :sessionId="item.sessionId"></ChatAsk>
+          <ChatAnswer
+            :id="item.id"
+            :content="item.answer"
+            :loading="item.loading"
+            :delay-loading="item.delayLoading"
+            :isSatisfied="item.isSatisfied"
+            :toggleVisibleIcons="false"
+            loadingText="数据分析中..."
+          >
+            <main>
+              <div 
+                class="area_inner"
+                v-for="(item, index) in item.echartWithTableData"
+                :key="index"
+              >
+                <div class="echart-warpper pt-[50px]">
+                  <p class="text-center pb-[10px]"><span class="mb-[10px] #1A2029 font-bold">{{ item.title }}</span></p>
+                  <div :id="item.key" class="w-[680px] h-[300px]"></div>
+                </div>
+                
+                <div class="pt-[20px]">
+                  <el-table :data="item.data" style="width: 680px;">
+                    <el-table-column :label="col.title" :prop="col.key" align="center" v-for="col in item.columns" :key="col.key"></el-table-column>
+                  </el-table>
+                </div>
+              </div>
+            </main>
+          </ChatAnswer>
+        </div>
+      </div>
+
+      </el-scrollbar>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/business/record";
+import { ChatAsk, ChatAnswer } from "@/components/chat";
+import { formatEchart, isNumberComprehensive } from '@/utils/format';
+import * as echarts from 'echarts';
+import { getOrderAreaOptions } from "@/utils/echartOptions";
+import { ORDER_OPTION_ENUM } from '@/utils/enum';
+
+export default {
+  name: "Record",
+  components: { ChatAsk, ChatAnswer },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 信义大模型问答记录表格数据
+      recordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        question: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      selectOptions: [
+        { value: 0, label: '专家问答', },
+        { value: 1, label: '水质报警', },
+        { value: 2, label: '生化报警', },
+        { value: 3, label: '预测预警', }
+      ],
+      recordVisible: false,
+      chatDataSource: [],
+      echartData: [],
+      whichWay: null
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+
+    opened() {
+      this.echartData.length && this.createEchart(this.echartData, this.whichWay);
+    },
+
+    // 格式化 echart 和 table 数据
+    formatData(data) {
+      const titleEnum = {
+        jsGroup: '进水指标',
+        csGroup: '出水指标',
+        hyGroup: '化验指标'
+      }
+      const { whichWay, jsGroup, csGroup, hyGroup } = data;
+      return Object.entries({ jsGroup, csGroup, hyGroup }).map(([key, value]) => {
+        if (value.length) {
+          const [xAxisData, yAxisData] = formatEchart(value);
+          const [item] = value;
+          const columns = Object.keys(item).map(k => {
+            const wihteKeyList = ['jsSlq', 'csSlqc'];
+            let unit = '';
+
+            if (wihteKeyList.includes(k)) {
+              unit = whichWay === 1 ? '(m³/h)' : '(m³/d)';
+            } else if (k !== 'time') {
+              unit = '(mg/L)';
+            }
+
+            return {
+              title: ORDER_OPTION_ENUM[k] + unit,
+              key: k,
+              width: '150px',
+              align: 'center'
+            }
+          })
+          const data = value.map(item => {
+            Object.entries(item).forEach(([k, v]) => {
+              !v && v != 0 && (item[k] = '-');
+              if (isNumberComprehensive(v)) {
+                item[k] = v ? Number(v.toFixed(2)) : 0
+              }
+            })
+            return item;
+          })
+
+          return {
+            key: key,
+            title: titleEnum[key],
+            xAxisData,
+            yAxisData,
+            columns,
+            data
+          }
+        }
+      }).filter(Boolean);
+    },
+
+    createEchart (echartData, whichWay) {
+      setTimeout(() => {
+        echartData.forEach(({ key, xAxisData, yAxisData,  }) => {
+          const dom = document.getElementById(key);
+          // chartInstance[key] = echarts.init(dom, null, { width: 680, height: 300 });
+          const echart = echarts.init(dom, null, { width: 680, height: 300 });
+        
+          const option = getOrderAreaOptions({ xAxisData, yAxisData, whichWay });
+        
+          echart.setOption(option);
+        })
+      })
+    },
+
+    // 查看详情
+    handleRecordDetails({ row }) {
+
+      let echartData = [];
+      let whichWay = null;
+    
+      this.chatDataSource = [row].map(item => {
+        if (item.remark) {
+          const remark = JSON.parse(item.remark);
+          whichWay = remark.whichWay;
+          echartData = item.echartWithTableData = this.formatData(remark);
+        }
+
+        return { ...item, loading: false };
+      })
+
+      this.echartData = echartData;
+      this.whichWay = whichWay;
+
+      this.recordVisible = true;
+    },
+    /** 查询信义大模型问答记录列表 */
+    getList() {
+      this.loading = true;
+      const enumType = {
+        '0': { color: '', label: '专家问答' },
+        '1': { color: 'success', label: '水质报警' },
+        '2': { color: 'warning', label: '生化报警' },
+        '3': { color: 'danger', label: '预测预警' }
+      }
+      const enumLike = {
+        0: "否",
+        1: "是",
+        2: "否"
+      }
+      listRecord({ ...this.queryParams, module: 1 }).then(response => {
+        this.recordList = response.rows.map(item => ({ ...item, ...enumType[item.type], satisfied: enumLike[item.isSatisfied] }));
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: '',
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        delFlag: null,
+        revision: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("queryForm");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加信义大模型问答记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改信义大模型问答记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateRecord(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecord(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除该数据项?').then(function () {
+        return delRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('business/record/export', {
+        ...this.queryParams
+      }, `record_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
+
+<style lang="scss" scoped>
+.area_inner {
+  display: flex;
+  align-items: center;
+  flex-flow: column;
+  padding-bottom: 20px;
+  background: #eff8fc;
+}
+
+.list-item {
+  margin-bottom: 16px;
+
+  .title {
+    font-size: 14px;
+    font-weight: bold;
+    line-height: 20px;
+  }
+
+  .item-top {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 10px;
+
+    .num {
+      font-size: 12px;
+      font-weight: 400;
+      color: #B0B7C0;
+    }
+  }
+}
+
+</style>

+ 497 - 0
src/views/business/pymol/index.vue

@@ -0,0 +1,497 @@
+<template>
+  <!-- 生化报警 -->
+  <div class="page-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
+      class="search-form_container">
+      <!-- <el-form-item label="报警内容" prop="unknown">
+        <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item> -->
+      <el-form-item label="报警类型" prop="category">
+        <el-select v-model="queryParams.category">
+          <el-option value="" label="全部"></el-option>
+          <el-option key="内回流比" value="内回流比" label="内回流比"></el-option>
+          <el-option key="外回流比" value="外回流比" label="外回流比"></el-option>
+          <el-option key="污泥浓度" value="污泥浓度" label="污泥浓度"></el-option>
+          <el-option key="污泥负荷" value="污泥负荷" label="污泥负荷"></el-option>
+          <el-option key="碳氮比" value="碳氮比" label="碳氮比"></el-option>
+          <el-option key="碳磷比" value="碳磷比" label="碳磷比"></el-option>
+          <el-option key="BOD比COD" value="BOD比COD" label="BOD比COD"></el-option>
+          <el-option key="好氧区DO#1" value="好氧区DO#1" label="好氧区DO#1"></el-option>
+          <el-option key="好氧区DO#2" value="好氧区DO#2" label="好氧区DO#2"></el-option>
+          <el-option key="气水比" value="气水比" label="气水比"></el-option>
+          <el-option key="污泥浓度MLSS#1" value="污泥浓度MLSS#1" label="污泥浓度MLSS#1"></el-option>
+          <el-option key="污泥浓度MLSS#2" value="污泥浓度MLSS#2" label="污泥浓度MLSS#2"></el-option>
+          <el-option key="挥发性污泥浓度占比(MLVSS/MLSS)" value="挥发性污泥浓度占比(MLVSS/MLSS)" label="挥发性污泥浓度占比(MLVSS/MLSS)"></el-option>
+          <el-option key="二沉池表面负荷" value="二沉池表面负荷" label="二沉池表面负荷"></el-option>
+          <el-option key="二沉池固体负荷" value="二沉池固体负荷" label="二沉池固体负荷"></el-option>
+          <el-option key="反冲洗水量" value="反冲洗水量" label="反冲洗水量"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="报警状态" prop="warningStatus">
+        <el-select v-model="queryParams.warningStatus">
+          <el-option value="" label="全部"></el-option>
+          <el-option :key="item.label" :value="item.val" :label="item.label" v-for="item in warningStatus"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-card shadow="never" body-class="card-table_container">
+      <el-row :gutter="10" class="mb8">
+        <!-- <el-col :span="1.5">
+          <el-button type="primary" plain icon="plus" size="small" @click="handleAdd">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="success" plain icon="edit" size="small" :disabled="single"
+            @click="handleUpdate">修改</el-button>
+        </el-col> -->
+        <el-col :span="1.5">
+          <el-button type="danger" plain icon="delete" size="small" :disabled="multiple"
+            @click="handleDelete">删除</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="warning" plain icon="download" size="small" @click="handleExport">导出</el-button>
+        </el-col>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      </el-row>
+      <el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="报警类型" align="center" prop="category" />
+        <el-table-column label="报警内容" align="center" prop="reason" />
+        <el-table-column label="报警值" align="center" prop="warningVal">
+          <template #default="scope">
+            <span>{{ Number(scope.row.warningVal.toFixed(2)) }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="设计值" align="center" prop="designVal">
+          <template #default="scope">
+            <span style="color: red;">{{ scope.row.designVal }} mg/L</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="报警次数" align="center" prop="counts" />
+        <el-table-column label="报警时间" align="center" prop="time" />
+        <el-table-column label="状态" align="center" prop="status" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
+          <template #default="scope">
+            <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">查看记录</el-button>
+            <!-- <el-button size="small" type="text" icon="edit" @click="handleUpdate(scope.row)">修改</el-button> -->
+            <!-- <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <el-dialog title="生化报警记录" v-model="recordVisible" width="880px" append-to-body class="chat-dialog_container">
+      <el-scrollbar height="600px">
+        <ChatBaseCard>
+          <div class="waring-answer-wrapper">
+            <dl class="message-inner warning-info_medium flex flex-col justify-between">
+              <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.title }}</dt>
+              <dd v-for="item, index in textDataSources?.list" :key="index"><span
+                  :class="{ 'text-[#F44C49]': item.isWarning }">{{ item.label }}: {{ item.value }}</span></dd>
+            </dl>
+            <div class="table-inner">
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前进水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="jsTableData" style="width: 100%" size="small">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+              <div class="warning-table">
+                <div class="title">
+                  <span>当前出水数据:</span>
+                </div>
+                <div class="main">
+                  <el-table :data="csTableData" style="width: 100%" size="small">
+                    <el-table-column prop="流量" label="流量(m³/h)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
+      Number(scope.row['流量'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="COD(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['COD'].exceed ? 'red' : '' }">{{
+      Number(scope.row['COD'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TN(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TN'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TN'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="NH3-N(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['NH3-N'].exceed ? 'red' : '' }">{{
+      Number(scope.row['NH3-N'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="TP(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['TP'].exceed ? 'red' : '' }">{{
+      Number(scope.row['TP'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="SS(mg/L)">
+                      <template #default="scope">
+                        <span :style="{ color: scope.row['SS'].exceed ? 'red' : '' }">{{
+      Number(scope.row['SS'].value.toFixed(2)) }}</span>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </div>
+              </div>
+            </div>
+          </div>
+        </ChatBaseCard>
+
+        <ChatAnswer :loading="false" :delay-loading="false" :toggleVisibleIcons="false" :content="answerResult"
+        v-if="answerResult" />
+      </el-scrollbar>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWarn, getWarn } from "@/api/business/water";
+import { formatToData, replaceArray  } from "@/utils/format";
+import * as echarts from 'echarts';
+import { getAreaOptions } from "@/utils/echartOptions";
+import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/business/record";
+import { ChatAsk, ChatAnswer, ChatBaseCard } from "@/components/chat"
+export default {
+  name: "Record",
+  components: { ChatAsk, ChatAnswer, ChatBaseCard },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 信义大模型问答记录表格数据
+      recordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        revision: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      warningStatus: [
+        {
+          val: 0,
+          label: '预警中'
+        },
+        {
+          val: 2,
+          label: '已完成'
+        },
+      ],
+      recordVisible: false,
+      answerResult: [],
+      textDataSources: null,
+      jsTableData: [],
+      csTableData: [],
+      // chartTitle: '',
+      // echartRef: null,
+      // chart: null
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 查看详情
+    handleRecordDetails({ row }) {
+
+      getWarn(row.id).then(({ data }) => {
+        const showVal = JSON.parse(data.showVal);
+        const { basic, jsData, csData } = showVal;
+
+        this.answerResult = data.answer;
+
+        basic.title = row.reason;
+        this.textDataSources = formatToData(basic, '报警值');
+
+        this.jsTableData = [jsData];
+        this.csTableData = [csData];
+        
+        this.recordVisible = true;
+      })
+    },
+    /** 查询信义大模型问答记录列表 */
+    getList() {
+      this.loading = true;
+      const waterEnum = {
+        '0': {
+          label: '报警中',
+          cls: 'tips_warning'
+        },
+        '1': {
+          label: '用户关闭',
+          cls: 'tips_success'
+        },
+        '2': {
+          label: '系统关闭',
+          cls: 'tips_close'
+        },
+        '3': {
+          label: '应急处理中',
+          cls: 'tips_warning'
+        }
+      }
+      listWarn({ ...this.queryParams, type: 1 }).then(response => {
+        this.recordList = response.rows.map(item => ({
+          ...item,
+          status: waterEnum[item.status].label
+        }));
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        sessionId: null,
+        type: null,
+        module: null,
+        userId: null,
+        showVal: null,
+        question: null,
+        answer: null,
+        warningId: null,
+        counts: null,
+        isStrong: null,
+        isSatisfied: null,
+        isShutdown: null,
+        delFlag: null,
+        revision: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加信义大模型问答记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改信义大模型问答记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateRecord(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecord(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除该数据项?').then(function () {
+        return delRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('business/record/export', {
+        ...this.queryParams
+      }, `record_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.waring-answer-wrapper {
+  display: flex;
+  justify-content: space-between;
+
+  .message-inner {
+    width: 210px;
+    flex-shrink: 0;
+
+    span {
+      white-space: nowrap;
+    }
+  }
+
+  .table-inner {
+    width: 100%;
+    padding-left: 20px;
+    .warning-table {
+      width: 100%;
+
+      .title {
+        margin-bottom: 8px;
+        line-height: 16px;
+        font-size: 12px;
+        font-weight: bold;
+        color: #1A2029;
+      }
+    }
+  }
+}
+
+.radio-wrapper {
+
+.radio-btn-group {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  text-align: center;
+  color: #5E5E5E;
+
+  .radio-btn {
+    width: 62px;
+    height: 28px;
+    border-radius: 4px;
+    background: #F4F6F8;
+    font-size: 14px;
+    line-height: 26px;
+    cursor: pointer;
+
+    &.active,
+    &:hover {
+      color: #2454FF;
+      background: #E2F1FF;
+    }
+
+    &.active {
+      background: #E2F1FF url('@/assets/images/chat/bg-raido-check.png') right bottom no-repeat;
+    }
+  }
+}
+
+}
+</style>

+ 12 - 5
src/views/business/qa/index.vue

@@ -121,10 +121,10 @@
       </el-table>
       
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
-        :page.sync="queryParams.pageNum"
-        :limit.sync="queryParams.pageSize"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
         @pagination="getList"
       />
     </el-card>
@@ -137,7 +137,14 @@
           <el-input v-model="form.question" placeholder="请输入问题" />
         </el-form-item>
         <el-form-item label="提示词">
-          <editor v-model="form.content" :min-height="192"/>
+          <el-input
+            v-model="form.content"
+            :rows="4"
+            resize="none" 
+            type="textarea"
+            placeholder="提示词内容"
+          />
+          <!-- <editor v-model="form.content" :min-height="192"/> -->
         </el-form-item>
         <el-form-item label="类型">
           <el-select v-model="form.type">
@@ -310,7 +317,7 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$modal.confirm('是否确认删除信义推荐问答列编号为"' + ids + '"的数据项?').then(function() {
+      this.$modal.confirm('是否确认删除数据项?').then(function() {
         return delQa(ids);
       }).then(() => {
         this.getList();

+ 3 - 2
src/views/business/record/index.vue

@@ -3,7 +3,7 @@
   <div class="page-container">
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
       class="search-form_container">
-      <el-form-item label="问题内容" prop="unknown">
+      <el-form-item label="问题内容" prop="question">
         <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
       </el-form-item>
       <!-- <el-form-item label="类型" prop="unknown">
@@ -64,7 +64,7 @@
           <template #default="scope">
             <el-button type="primary" text size="small" icon="view" @click="handleRecordDetails(scope)">记录</el-button> 
             <!-- <el-button size="small" type="text" icon="edit" @click="handleUpdate(scope.row)">修改</el-button> -->
-            <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button>
+            <!-- <el-button size="small" type="primary" text icon="delete" @click="handleDelete(scope.row)">删除</el-button> -->
           </template>
         </el-table-column>
       </el-table>
@@ -274,6 +274,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.$refs['queryForm'].resetFields();
       this.resetForm("queryForm");
       this.handleQuery();
     },

+ 43 - 10
src/views/business/water/index.vue

@@ -3,9 +3,39 @@
   <div class="page-container">
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
       class="search-form_container">
-      <el-form-item label="报警内容" prop="unknown">
+      <!-- <el-form-item label="报警内容" prop="unknown">
         <el-input v-model="queryParams.question" placeholder="请输入问题内容" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item> -->
+      <el-form-item label="报警类型" prop="category">
+        <el-select v-model="queryParams.category">
+          <el-option value="" label="全部"></el-option>
+          <el-option key="内回流比" value="内回流比" label="内回流比"></el-option>
+          <el-option key="外回流比" value="外回流比" label="外回流比"></el-option>
+          <el-option key="污泥浓度" value="污泥浓度" label="污泥浓度"></el-option>
+          <el-option key="污泥负荷" value="污泥负荷" label="污泥负荷"></el-option>
+          <el-option key="碳氮比" value="碳氮比" label="碳氮比"></el-option>
+          <el-option key="碳磷比" value="碳磷比" label="碳磷比"></el-option>
+          <el-option key="BOD比COD" value="BOD比COD" label="BOD比COD"></el-option>
+          <el-option key="好氧区DO#1" value="好氧区DO#1" label="好氧区DO#1"></el-option>
+          <el-option key="好氧区DO#2" value="好氧区DO#2" label="好氧区DO#2"></el-option>
+          <el-option key="气水比" value="气水比" label="气水比"></el-option>
+          <el-option key="污泥浓度MLSS#1" value="污泥浓度MLSS#1" label="污泥浓度MLSS#1"></el-option>
+          <el-option key="污泥浓度MLSS#2" value="污泥浓度MLSS#2" label="污泥浓度MLSS#2"></el-option>
+          <el-option key="挥发性污泥浓度占比(MLVSS/MLSS)" value="挥发性污泥浓度占比(MLVSS/MLSS)" label="挥发性污泥浓度占比(MLVSS/MLSS)"></el-option>
+          <el-option key="二沉池表面负荷" value="二沉池表面负荷" label="二沉池表面负荷"></el-option>
+          <el-option key="二沉池固体负荷" value="二沉池固体负荷" label="二沉池固体负荷"></el-option>
+          <el-option key="反冲洗水量" value="反冲洗水量" label="反冲洗水量"></el-option>
+        </el-select>
       </el-form-item>
+      <!-- <el-form-item label="报警原因" prop="reason">
+        <el-select v-model="queryParams.reason">
+          <el-option value="" label="全部"></el-option>
+          <el-option key="出水总磷" value="出水总磷" label="出水总磷"></el-option>
+          <el-option key="出水总磷" value="出水总磷" label="出水总磷"></el-option>
+          <el-option key="出水总磷" value="出水总磷" label="出水总磷"></el-option>
+          <el-option key="出水总磷" value="出水总磷" label="出水总磷"></el-option>
+        </el-select>
+      </el-form-item> -->
       <el-form-item label="报警状态" prop="warningStatus">
         <el-select v-model="queryParams.warningStatus">
           <el-option value="" label="全部"></el-option>
@@ -39,6 +69,7 @@
       <el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="类型" align="center" prop="category" />
+        <el-table-column label="报警原因" align="center" prop="reason" />
         <el-table-column label="报警值" align="center" prop="warningVal">
           <template #default="scope">
             <span style="color: red;">{{ Number(scope.row.warningVal.toFixed(2)) }} mg/L</span>
@@ -67,11 +98,11 @@
         v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
 
-    <el-dialog title="水质报警记录" v-model="recordVisible" width="900px" append-to-body class="chat-dialog_container">
-      <el-scrollbar height="800px">
+    <el-dialog title="水质报警记录" v-model="recordVisible" width="880px" append-to-body class="chat-dialog_container">
+      <el-scrollbar height="600px">
         <ChatBaseCard>
           <div class="waring-answer-wrapper">
-            <dl class="message-inner warning-info_medium ">
+            <dl class="message-inner warning-info_medium flex flex-col justify-between">
               <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.title }}</dt>
               <dd v-for="item, index in textDataSources?.list" :key="index"><span
                   :class="{ 'text-[#F44C49]': item.isWarning }">{{ item.label }}: {{ item.value }}</span></dd>
@@ -82,7 +113,7 @@
                   <span>当前进水数据:</span>
                 </div>
                 <div class="main">
-                  <el-table :data="jsTableData" style="width: 100%">
+                  <el-table :data="jsTableData" style="width: 100%" size="small">
                     <el-table-column prop="流量" label="流量(m³/h)">
                       <template #default="scope">
                         <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
@@ -127,7 +158,7 @@
                   <span>当前出水数据:</span>
                 </div>
                 <div class="main">
-                  <el-table :data="csTableData" style="width: 100%">
+                  <el-table :data="csTableData" style="width: 100%" size="small">
                     <el-table-column prop="流量" label="流量(m³/h)">
                       <template #default="scope">
                         <span :style="{ color: scope.row['流量'].exceed ? 'red' : '' }">{{
@@ -388,8 +419,6 @@ export default {
         this.csTableData = [csData];
         this.textDataSources = formatToData(basic, '报警值');
       })
-      this.chatDataSource = [];
-      this.chatDataSource.push(row);
       this.recordVisible = true;
     },
     /** 查询信义大模型问答记录列表 */
@@ -515,9 +544,12 @@ export default {
 
 <style lang="scss" scoped>
 .waring-answer-wrapper {
+  display: flex;
+  justify-content: space-between;
+  // align-items: flex-start;
 
   .message-inner {
-    width: 194px;
+    width: 210px;
     flex-shrink: 0;
 
     span {
@@ -526,9 +558,10 @@ export default {
   }
 
   .table-inner {
+    width: 100%;
+    padding-left: 20px;
     .warning-table {
       width: 100%;
-      padding-top: 30px;
 
       .title {
         margin-bottom: 8px;

+ 7 - 1
src/views/daily/index.vue

@@ -1,6 +1,6 @@
 <script setup>
 import { schema } from './config.js';
-import { getRecentMsg, getDetailByDay, postDaily } from '@/api/daily';
+import { getRecentMsg, getDetailByDay, postDaily, postProdDaily } from '@/api/daily';
 
 const { proxy } = getCurrentInstance();
 
@@ -54,6 +54,12 @@ const onSubmit = async () => {
           ...unref(formData)
         });
 
+        await postProdDaily({
+          id: dateTime?.id,
+          testDate: unref(testDate),
+          ...unref(formData)
+        })
+
         queryRecent();
 
         proxy.$modal.msgSuccess("提交成功");

+ 2 - 2
src/views/login.vue

@@ -37,7 +37,7 @@
             <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
           </el-input>
         </el-form-item>
-        <el-form-item prop="code" v-if="captchaEnabled">
+        <!-- <el-form-item prop="code" v-if="captchaEnabled">
           <el-input
             v-model="loginForm.code"
             size="large"
@@ -51,7 +51,7 @@
           <div class="login-code">
             <img :src="codeUrl" @click="getCode" class="login-code-img"/>
           </div>
-        </el-form-item>
+        </el-form-item> -->
         <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
         <el-form-item style="width:100%;">
           <el-button