Forráskód Böngészése

update:ai辅助生成功能完善

DESKTOP-HI4L4AH\Administrator 5 hónapja
szülő
commit
b68dabad38

+ 9 - 2
config/index.js

@@ -7,18 +7,25 @@ const devEnv = require('./dev.env')
 
 module.exports = {
   dev: {
-
     // Paths
     assetsSubDirectory: 'static',
     assetsPublicPath: '/',
     // 代理列表, 是否开启代理通过[./dev.env.js]配置
     proxyTable: devEnv.OPEN_PROXY === false ? {} : {
       '/proxyApi': {
-        target: 'http://127.0.0.1:8081',
+        target: 'http://121.37.47.26:8081/',
         changeOrigin: true,
         pathRewrite: {
           '/proxyApi': ''
         }
+      },
+      '/aiApi': {
+        // target: 'http://127.0.0.1:8089/',
+        target: 'http://121.37.47.26:8080/',
+        changeOrigin: true,
+        pathRewrite: {
+          '/aiApi': ''
+        }
       }
     },
 

+ 14 - 0
src/api/ai.js

@@ -0,0 +1,14 @@
+import axios from 'axios'
+import $http from '@/utils/httpRequest'
+
+/**
+ * 函数名:ai生成PSRE数据
+ * @parm1  courseName-课程名称
+ * @param2 userMessage-目标导向内容
+ */
+export function generatePSRE (data) {
+  // return axios.get($http.httpUrl('/system/course/' + courseId + '/section'))
+  return axios.post(
+    $http.aiUrl('api/teracherGpsren/ManuallyCreatedPsreByG'),data
+  )
+}

+ 6 - 0
src/api/goalManage.js

@@ -0,0 +1,6 @@
+import axios from 'axios'
+import $http from '@/utils/httpRequest'
+
+export function publishGoal (data) {
+  return axios.put($http.httpUrl('/system/goalInfo'), data)
+}

+ 46 - 23
src/components/education/education-search.vue

@@ -40,33 +40,34 @@
           v-for="item in courseList"
           :key="item.id"
           :label="item.name"
-          :value="item.name">
-        </el-option>
-      </el-select>
-    </el-form-item>
-
-    <el-form-item>
-      <el-select
-        v-if="subjectList.length > 0"
-        v-model="subjectId"
-        filterable
-        clearable
-        placeholder="请选择科目">
-        <el-option
-          v-for="item in subjectList"
-          :key="item.id"
-          :label="item.name"
           :value="item.id">
         </el-option>
       </el-select>
     </el-form-item>
 
-    <el-form-item>
-       <el-input v-model="keyWord" placeholder="输入题目内容" type="text"></el-input>
-    </el-form-item>
+<!--    <el-form-item>-->
+<!--      <el-select-->
+<!--        v-if="subjectList.length > 0"-->
+<!--        v-model="subjectId"-->
+<!--        filterable-->
+<!--        clearable-->
+<!--        placeholder="请选择科目">-->
+<!--        <el-option-->
+<!--          v-for="item in subjectList"-->
+<!--          :key="item.id"-->
+<!--          :label="item.name"-->
+<!--          :value="item.id">-->
+<!--        </el-option>-->
+<!--      </el-select>-->
+<!--    </el-form-item>-->
+
+<!--    <el-form-item>-->
+<!--       <el-input v-model="keyWord" placeholder="输入题目内容" type="text"></el-input>-->
+<!--    </el-form-item>-->
 
     <el-form-item>
-      <el-button v-if="hasPermission([permission])" type="success" icon="el-icon-search" @click="searchQuestion" >搜索</el-button>
+      <el-button v-if="hasPermission([permission])" type="success" icon="el-icon-search" @click="search()" >搜索</el-button>
+      <el-button v-if="hasPermission([permission])" type="primary" icon="el-icon-plus" @click="create()">创建</el-button>
     </el-form-item>
   </div>
 </template>
@@ -74,8 +75,8 @@
 <script>
   import {getGradeInfoList} from '@/api/gradeInfo'
   import {getSubjectInfoList} from '@/api/subjectInfo'
-  import {getCourseList} from "../../utils/education-api";
-  export default {
+  import {getCourseList} from '../../utils/education-api'
+export default {
     name: 'educationSearch',
     props: {
       school_type_list: {
@@ -99,12 +100,16 @@
     data () {
       return {
         schoolType: null,
+        // 年级
         gradeInfoId: null,
         courseList: [],
+        // 课程ID
         courseId: null,
+        // 科目ID
         subjectId: null,
         schoolTypeList: [],
         gradeInfoList: [],
+        // 输入内容
         keyWord: '',
         subjectList: [],
         currentPage: 1,
@@ -158,15 +163,33 @@
           that.totalCount = response.data.data.total
         })
       },
-
+      search () {
+        let form = {
+          schoolType: this.schoolType,
+          gradeInfoId: this.gradeInfoId,
+          courseId: this.courseId,
+          subjectId: this.subjectId,
+          keyWord: this.keyWord
+        }
+        // 调试
+        console.log('触发搜索按钮')
+        this.$emit('search', form)
+      },
       searchQuestion () {
         let form = {
           schoolType: this.schoolType,
           gradeInfoId: this.gradeInfoId,
+          courseId: this.courseId,
           subjectId: this.subjectId,
           keyWord: this.keyWord
         }
+        // 调试
+        // console.log('触发搜索按钮')
         this.$emit('click', form)
+      },
+      create () {
+        // 通知给父组件所绑定的创建方法
+        this.$emit('create')
       }
     }
   }

+ 111 - 42
src/components/education/question-preview.vue

@@ -1,39 +1,95 @@
 <template>
     <div>
-      <el-dialog title="试题预览" @closed="closeQuestionDialog" :visible.sync="dialogFormVisible">
-
-        <div class="content" v-html="questionInfoData.content"></div>
-
-        <div v-if="questionInfoData.questionType === 1">
-          <div v-for="(item, index) in questionInfoData.optionList" :key="index" class="radio_item">
-            <el-radio :label="item.label">
-              {{item.label}}. &nbsp;
-              <label v-html="item.option_name"></label>
-            </el-radio>
-          </div>
-        </div>
-
-        <div v-if="questionInfoData.questionType === 6">
-          <div class="radio_item">
-            <el-radio label="1">对</el-radio>
-          </div>
-          <div class="radio_item">
-            <el-radio label="1">错</el-radio>
-          </div>
-        </div>
-
-        <div v-if="questionInfoData.questionType === 2">
-          <div v-for="(item, index) in questionInfoData.optionList" :key="index" class="radio_item">
-            <el-checkbox :label="item.label">
-              {{item.label}}. &nbsp;
-              <label v-html="item.option_name"></label>
-            </el-checkbox>
-          </div>
-        </div>
-
-        <div slot="footer" class="dialog-footer">
-          <el-button type="primary" @click="close()">确 定</el-button>
-        </div>
+      <el-dialog title="详情" @closed="closeQuestionDialog" :visible.sync="dialogFormVisible">
+
+<!--        <div class="content" v-html="questionInfoData.content"></div>-->
+
+<!--        <div v-if="questionInfoData.questionType === 1">-->
+<!--          <div v-for="(item, index) in questionInfoData.optionList" :key="index" class="radio_item">-->
+<!--            <el-radio :label="item.label">-->
+<!--              {{item.label}}. &nbsp;-->
+<!--              <label v-html="item.option_name"></label>-->
+<!--            </el-radio>-->
+<!--          </div>-->
+<!--        </div>-->
+
+<!--        <div v-if="questionInfoData.questionType === 6">-->
+<!--          <div class="radio_item">-->
+<!--            <el-radio label="1">对</el-radio>-->
+<!--          </div>-->
+<!--          <div class="radio_item">-->
+<!--            <el-radio label="1">错</el-radio>-->
+<!--          </div>-->
+<!--        </div>-->
+
+<!--        <div v-if="questionInfoData.questionType === 2">-->
+<!--          <div v-for="(item, index) in questionInfoData.optionList" :key="index" class="radio_item">-->
+<!--            <el-checkbox :label="item.label">-->
+<!--              {{item.label}}. &nbsp;-->
+<!--              <label v-html="item.option_name"></label>-->
+<!--            </el-checkbox>-->
+<!--          </div>-->
+<!--        </div>-->
+
+<!--        <div slot="footer" class="dialog-footer">-->
+<!--          <el-button type="primary" @click="close()">确 定</el-button>-->
+<!--        </div>-->
+        <el-form :model="form">
+         <el-row>
+           <el-col :span="18">
+<!--             G 目标导向-->
+             <el-form-item label="目标" prop="question_name" label-width="140px" >
+               <el-input disabled v-model="form.gOriented" placeholder="" type="textarea" autosize></el-input>
+             </el-form-item>
+           </el-col>
+         </el-row>
+<!--          P 问题定义-->
+          <el-row>
+            <el-col :span="18">
+              <el-form-item label="问题定义(评价标准)" prop="question_name" label-width="140px" >
+                <el-input disabled v-model="form.pScoreStd" placeholder="" type="textarea" autosize></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+<!--          S 系统拆解-->
+          <el-row>
+            <el-col :span="18">
+              <el-form-item label="系统拆解(评价标准)" prop="question_name" label-width="140px" >
+                <el-input disabled v-model="form.sScoreStd" placeholder="" type="textarea" autosize></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+<!--          R 结果整合-->
+          <el-row>
+            <el-col :span="18">
+              <el-form-item label="结果整合(评价标准)" prop="question_name" label-width="140px" >
+                <el-input disabled v-model="form.eScoreStd" placeholder="" type="textarea" autosize></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+<!--          R 结果评估-->
+          <el-row>
+            <el-col :span="18">
+              <el-form-item label="结果评估(评价标准)" prop="question_name" label-width="140px" >
+                <el-input disabled v-model="form.rScoreStd" placeholder="" type="textarea" autosize></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+<!--       N   总结新知识-->
+<!--          <el-row>-->
+<!--            <el-col :span="18">-->
+<!--              <el-form-item label="总结新知识(评价标准)" prop="question_name" label-width="140px" >-->
+<!--                <el-input disabled v-model="form.nScoreStd" placeholder="" type="textarea" autosize></el-input>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-row>-->
+<!--          <el-form-item label="活动区域" :label-width="formLabelWidth">-->
+<!--            <el-select v-model="form.region" placeholder="请选择活动区域">-->
+<!--              <el-option label="区域一" value="shanghai"></el-option>-->
+<!--              <el-option label="区域二" value="beijing"></el-option>-->
+<!--            </el-select>-->
+<!--          </el-form-item>-->
+        </el-form>
       </el-dialog>
     </div>
 </template>
@@ -58,26 +114,39 @@
           this.dialogFormVisible = val
         },
 
-        questionInfo (val) {
-          this.questionInfoData = val
-          let options = this.questionInfoData.options
-          if (options) {
-            let optionList = JSON.parse(options)
-            this.questionInfoData.optionList = optionList
-          }
+        questionInfo: {
+          handler (val) {
+            // console.log("监听数据变化",val)
+            if (val) {
+              this.questionInfoData = { ...val } // 使用展开运算符创建新对象
+              this.form = { ...val }
+              let options = this.questionInfoData.options
+              if (options) {
+                let optionList = JSON.parse(options)
+                this.questionInfoData.optionList = optionList
+              }
+            }
+          },
+          immediate: true // 立即执行
         }
       },
 
       data () {
         return {
           dialogFormVisible: false,
-          questionInfoData: {}
+          questionInfoData: {},
+          form: {
+
+          }
         }
       },
 
       mounted () {
         this.questionInfoData = this.questionInfo
+        this.form = this.questionInfo
         this.dialogFormVisible = this.openFlag
+        // 调试
+        console.log('查看题目信息', this.questionInfoData)
       },
 
       methods: {

+ 10 - 0
src/utils/httpRequest.js

@@ -41,6 +41,16 @@ http.httpUrl = (actionName) => {
   return (process.env.NODE_ENV !== 'production' && process.env.OPEN_PROXY ? '/proxyApi/' : window.SITE_CONFIG.baseUrl) + actionName
 }
 
+// todo:window.SITE_CONFIG.baseUrl后面需要进行修改
+/**
+ * ai服务请求地址处理
+ * @param {*} actionName action方法名称
+ */
+http.aiUrl = (actionName) => {
+  // 非生产环境 && 开启代理, 接口前缀统一使用[/proxyApi/]前缀做代理拦截!
+  return (process.env.NODE_ENV !== 'production' && process.env.OPEN_PROXY ? '/aiApi/' : window.SITE_CONFIG.aiBaseUrl) + actionName
+}
+
 /**
  * 获取请求url
  * @param {*} actionName action方法名称

+ 26 - 0
src/utils/util.js

@@ -0,0 +1,26 @@
+/**
+ *通过id获取列表中对应对象的属性值
+ * @param list
+ * @param id
+ * @param idField
+ * @returns {*|null}
+ */
+export function findItemById (list, id, idField = 'id') {
+  if (!list || !Array.isArray(list)) {
+    return null
+  } else {
+    return list.find(item => item[idField] === id)
+  }
+}
+
+/**
+ *通过id获取列表中对应对象的属性值
+ * @param list-列表
+ * @param id-唯一标识
+ * @param idField-唯一标识字段
+ * @returns {*|null}
+ */
+export function getItemPropertyById (list, id, property, idField = 'id') {
+  const item = findItemById(list, id, idField)
+  return item ? item[property] : ''
+}

+ 297 - 253
src/views/education/goalOriented.vue

@@ -1,59 +1,30 @@
 <template>
   <div>
     <el-tabs v-model="activeName" @tab-click="handleClick">
-      <el-tab-pane label="目标管理" name="questions_list">
+      <el-tab-pane label="目标管理" name="goal_manage">
         <el-form :model="query" :inline="true">
-          <education-search
-            @click="searchGobalInfo"
-            :school_type_list="schoolTypeList"
-            permission="system:question:list">
+          <education-search @search="searchGobalInfo" @create="createGPSAREN()" :school_type_list="schoolTypeList" permission="system:question:list">
           </education-search>
         </el-form>
-        <el-table
-          v-loading="tableLoading"
-          border
-          :data="goalInfoList"
-          style="width: 100%">
-          <el-table-column
-            type="selection"
-            width="55">
+        <el-table v-loading="tableLoading" border :data="goalInfoList" style="width: 100%">
+          <el-table-column type="selection" width="55">
           </el-table-column>
 
-          <el-table-column
-            prop="gOriented"
-            align="center"
-            :show-overflow-tooltip="true"
-            label="目标"
-            min-width="150">
+          <el-table-column prop="gOriented" align="center" :show-overflow-tooltip="true" label="目标" min-width="130">
             <template slot-scope="scope">
               <div v-html="scope.row.gOriented"></div>
             </template>
           </el-table-column>
 
-          <el-table-column
-            v-if="showTableHeader"
-            prop="courseName"
-            align="center"
-            width="100"
-            label="课程">
+          <el-table-column v-if="showTableHeader" prop="courseName" align="center" width="120" label="课程">
           </el-table-column>
 
-          <el-table-column
-            v-if="showTableHeader"
-            prop="courseSectionName"
-            align="center"
-            width="100"
-            label="章节">
-          </el-table-column>
+          <!-- <el-table-column v-if="showTableHeader" prop="courseSectionName" align="center" width="100" label="章节">
+          </el-table-column> -->
 
-          <el-table-column
-            v-if="showTableHeader"
-            align="center"
-            sortable
-            label="阶段"
-            width="100">
+          <el-table-column v-if="showTableHeader" align="center" sortable label="阶段" width="100">
             <template slot-scope="scope">
-              <el-tag size="small">{{scope.row.schoolType | getSchoolTypeName}}</el-tag>
+              <el-tag size="small">{{ scope.row.schoolType | getSchoolTypeName }}</el-tag>
             </template>
           </el-table-column>
 
@@ -75,28 +46,17 @@
             </template>
           </el-table-column> -->
 
-          <el-table-column
-            prop="createDate"
-            align="center"
-            label="创建时间">
+          <el-table-column prop="createDate" align="center" label="创建时间">
             <template slot-scope="scope">
-              <span>{{ scope.row.createDate | xFormatDate}}</span>
+              <span>{{ scope.row.createDate | xFormatDate }}</span>
             </template>
           </el-table-column>
 
-          <el-table-column
-            header-align="center"
-            align="center"
-            width="200"
-            label="操作">
+          <el-table-column header-align="center" align="center" width="200" label="操作">
             <template slot-scope="scope">
 
-              <el-button
-                size="small"
-                icon="el-icon-view"
-                @click="lookQuestion(scope.row)"
-                type="text">预览</el-button>
-
+              <el-button size="small" icon="el-icon-view" @click="lookQuestion(scope.row)" type="text">预览</el-button>
+              <el-button size="small" icon="el-icon-s-promotion" @click="release(scope.row)" type="text" :disabled="scope.row.publishFlag === 1" >{{ scope.row.publishFlag === 0 ? '发布' : '已发布' }}</el-button>
               <!-- <el-button
                 size="small"
                 icon="el-icon-edit"
@@ -104,160 +64,102 @@
                 @click="updateQuestion(scope.row)"
                 type="text">修改</el-button> -->
 
-              <el-button
-                size="small"
-                icon="el-icon-delete"
-                v-if="hasPermission(['system:question:deleteById'])"
-                @click="deleteById(scope.row)"
-                type="text">删除</el-button>
+              <el-button size="small" icon="el-icon-delete" v-if="hasPermission(['system:question:deleteById'])"
+                @click="deleteById(scope.row)" type="text">删除</el-button>
             </template>
           </el-table-column>
         </el-table>
 
-        <el-pagination
-          background
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-          :current-page="currentPage"
-          :page-sizes="[10, 20, 30, 40]"
-          :page-size="pageSize"
-          :total="totalCount"
+        <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
+          :current-page="currentPage" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize" :total="totalCount"
           layout="total, sizes, prev, pager, next, jumper">
         </el-pagination>
 
-        <question-preview
-          @closeQuestionPreview="closeQuestionPreview"
-          :questionInfo="rowQuestion"
+        <question-preview @closeQuestionPreview="closeQuestionPreview" :questionInfo="rowQuestion"
           :openFlag="questionPreviewFlag">
         </question-preview>
 
       </el-tab-pane>
 
-      <el-tab-pane label="手动添加" name="questions_form">
-        <el-form :model="form" :rules="rules" ref="form" label-width="100px" class="demo-ruleForm">
-          <el-col :span="12">
-            <el-form-item label="阶段:" prop="schoolType">
-              <el-select
-                clearable filterable
-                @change="changeSchoolType"
-                v-model="form.schoolType"
-                placeholder="请选择阶段">
-                <el-option
-                  v-for="item in schoolTypeList"
-                  :key="item.id"
-                  :label="item.value"
-                  :value="item.code">
-                </el-option>
-              </el-select>
-            </el-form-item>
-
-            <el-col :span="12">
-              <el-form-item label="科目:" prop="subjectId">
-                <el-select @change="changeSubject" clearable filterable v-model="form.subjectId" placeholder="请选择科目">
-                  <el-option
-                    v-for="item in subjectList"
-                    :key="item.id"
-                    :label="item.name"
-                    :value="item.id">
-                  </el-option>
-                </el-select>
-              </el-form-item>
-            </el-col>
-
-
-
-          </el-col>
-
-          <el-col :span="12">
-            <el-form-item label="年级:" prop="gradeId">
-              <el-select clearable filterable @change="changeGradeType" v-model="form.gradeId" placeholder="请选择年级">
-                <el-option
-                  v-for="item in changeGradeTypeList"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="课程:"  prop="courseId">
-              <el-select clearable filterable  v-model="form.courseId" placeholder="请选择课程类型">
-                <el-option
-                  v-for="item in courseList"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id">
-                </el-option>
-              </el-select>
-            </el-form-item>
-
-          </el-col>
-
-
-          <el-col :span="24">
-            <el-form-item label="知识标签" prop="knowPoints" placeholder="请选择试题知识点">
-              <el-popover
-                style="width: 40%"
-                ref="treeListPopover"
-                placement="bottom-start"
-                trigger="click"
-                v-model="visible"
-                popper-class="mod-menu__icon-popover">
-                <div class="mod-menu__icon-inner">
-                  <div class="mod-menu__icon-list">
-                    <el-tree
-                      :data="treeLanguagePointsList"
-                      show-checkbox
-                      ref="treeLanguagePoints"
-                      @check-change="handleCheckChange"
-                      v-loading="loading"
-                      lazy
-                      :props="{ children: 'children', label: 'name'}"
-                      :check-strictly="true"
-                      :load="loadLanguagePointsChildren"
-                      node-key="id">
-                    </el-tree>
-                  </div>
-                </div>
-              </el-popover>
-
-              <el-tag
-                v-for="tag in selectedLanguagePoints"
-                :key="tag.id"
-                closable
-                @close="removeLanguagePoints(tag)"
-                type="success">
-                {{tag.label}}
-              </el-tag>
-
-              <el-input
-                v-popover:treeListPopover
-                v-model="form.knowPoints"
-                @input="handleInputSplit"
-                :readonly="false" placeholder="请至少选择一个知识点,使用逗号分隔"
-                class="icon-list__input">
-              </el-input>
-              <span style="color:#ff0000;font-size: 12px;">请至少选择一个知识点,使用逗号分隔</span>
-            </el-form-item>
-          </el-col>
-
+      <el-tab-pane label="手动添加" name="create_goal" >
+        <el-form :model="form" :rules="rules" ref="form" label-width="100px" class="demo-ruleForm" v-loading="psren_loading">
+         <el-row>
+           <el-col :span="12">
+             <el-form-item label="阶段:" prop="schoolType">
+               <el-select clearable filterable @change="changeSchoolType" v-model="form.schoolType" placeholder="请选择阶段">
+                 <el-option v-for="item in schoolTypeList" :key="item.id" :label="item.value" :value="item.code">
+                 </el-option>
+               </el-select>
+             </el-form-item>
+             <el-form-item label="科目:" prop="subjectId">
+               <el-select @change="changeSubject" clearable filterable v-model="form.subjectId" placeholder="请选择科目">
+                 <el-option v-for="item in subjectList" :key="item.id" :label="item.name" :value="item.id">
+                 </el-option>
+               </el-select>
+             </el-form-item>
+           </el-col>
+
+           <el-col :span="12">
+             <el-form-item label="年级:" prop="gradeId">
+               <el-select clearable filterable @change="changeGradeType" v-model="form.gradeId" placeholder="请选择年级">
+                 <el-option v-for="item in changeGradeTypeList" :key="item.id" :label="item.name" :value="item.id">
+                 </el-option>
+               </el-select>
+             </el-form-item>
+             <!--            课程-->
+             <el-form-item label="课程:" prop="courseId">
+               <el-select clearable filterable v-model="form.courseId" @change="$forceUpdate()" placeholder="请选择课程">
+                 <el-option v-for="item in courseList" :key="item.id" :label="item.name" :value="item.id">
+                 </el-option>
+               </el-select>
+             </el-form-item>
+           </el-col>
+         </el-row>
+
+          <!-- 知识标签 -->
+<!--          <el-col :span="6">-->
+<!--            <el-form-item label="知识标签" prop="knowPoints" placeholder="请选择试题知识点">-->
+<!--              <el-popover style="width: 20%" ref="treeListPopover" placement="bottom-start" trigger="click"-->
+<!--                v-model="visible" popper-class="mod-menu__icon-popover">-->
+<!--                <div class="mod-menu__icon-inner">-->
+<!--                  <div class="mod-menu__icon-list">-->
+<!--                    <el-tree :data="treeLanguagePointsList" show-checkbox ref="treeLanguagePoints"-->
+<!--                      @check-change="handleCheckChange" v-loading="loading" lazy-->
+<!--                      :props="{ children: 'children', label: 'name' }" :check-strictly="true"-->
+<!--                      :load="loadLanguagePointsChildren" node-key="id">-->
+<!--                    </el-tree>-->
+<!--                  </div>-->
+<!--                </div>-->
+<!--              </el-popover>-->
+
+<!--              <el-tag v-for="tag in selectedLanguagePoints" :key="tag.id" closable @close="removeLanguagePoints(tag)"-->
+<!--                type="success">-->
+<!--                {{ tag.label }}-->
+<!--              </el-tag>-->
+
+<!--              <el-input v-popover:treeListPopover v-model="form.knowPoints" @input="handleInputSplit" :readonly="false"-->
+<!--                placeholder="请至少选择一个知识点,使用逗号分隔" class="icon-list__input">-->
+<!--              </el-input>-->
+<!--              <span style="color:#ff0000;font-size: 12px;">请至少选择一个知识点,使用逗号分隔</span>-->
+<!--            </el-form-item>-->
+<!--          </el-col>-->
+<!--          <el-col :span="6" style="margin-left: 20px;">-->
+<!--            <el-button @click="getTabAuto()">自动获取标签</el-button>-->
+<!--          </el-col>-->
+          <!-- 导向目标 -->
           <el-col :span="24">
             <el-form-item label="导向目标:" prop="gOriented">
-              <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入导向目标"
-                v-model="form.gOriented">
+              <el-input type="textarea" :rows="5" placeholder="请输入导向目标" v-model="form.gOriented">
               </el-input>
               <!-- <script id="editor" ref="ueditor" type="text/plain">{{form.content}}</script> -->
             </el-form-item>
           </el-col>
-
-          <el-col :span="24">
-            <el-form-item label="参考定义:" >
-              <el-input
-                type="textarea"
-                :rows="5"
-                v-model="form.pScoreStd">
+          <el-col :span="24" style="padding-left: 100px;">
+            <el-button @click="applyAI()">AI辅助生成</el-button>
+          </el-col>
+          <el-col :span="24" style="margin-top: 20px;">
+            <el-form-item label="参考定义:">
+              <el-input type="textarea" :rows="5" v-model="form.pScoreStd">
               </el-input>
               <span style="color:#ff0000;font-size: 12px;">问题定义评价参考标准</span>
             </el-form-item>
@@ -265,10 +167,7 @@
 
           <el-col :span="24">
             <el-form-item label="参考拆解:">
-              <el-input
-                type="textarea"
-                :rows="5"
-                v-model="form.sScoreStd">
+              <el-input type="textarea" :rows="5" v-model="form.sScoreStd">
               </el-input>
               <span style="color:#ff0000;font-size: 12px;">系统拆解评价参考标准</span>
             </el-form-item>
@@ -276,11 +175,7 @@
 
           <el-col :span="24">
             <el-form-item label="结果整合:">
-              <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入拆解提示"
-                v-model="form.rScoreStd">
+              <el-input type="textarea" :rows="5" placeholder="请输入拆解提示" v-model="form.rScoreStd">
               </el-input>
               <span style="color:#ff0000;font-size: 12px;">系统拆解评价参考标准</span>
             </el-form-item>
@@ -288,23 +183,15 @@
 
           <el-col :span="24">
             <el-form-item label="结果评估:">
-              <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入拆解提示"
-                v-model="form.eScoreStd">
+              <el-input type="textarea" :rows="5" placeholder="请输入拆解提示" v-model="form.eScoreStd">
               </el-input>
               <!-- <script id="analysisEditor" ref="analysisEditor" type="text/plain">{{form.analysis}}</script> -->
             </el-form-item>
           </el-col>
 
           <el-col :span="24">
-            <el-form-item label="总结知识:">
-              <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入拆解提示"
-                v-model="form.nScoreStd">
+            <el-form-item label="知识标签:">
+              <el-input type="textarea" :rows="5" placeholder="请输入拆解提示" v-model="form.knowPoints">
               </el-input>
               <!-- <script id="analysisEditor" ref="analysisEditor" type="text/plain">{{form.analysis}}</script> -->
             </el-form-item>
@@ -312,7 +199,8 @@
 
           <el-col :span="24">
             <el-form-item>
-              <el-button type="success" :disabled="uploadVideoRunning" v-if="form.id" @click="saveOrUpdateQuestions">修改</el-button>
+              <el-button type="success" :disabled="uploadVideoRunning" v-if="form.id"
+                @click="saveOrUpdateQuestions">修改</el-button>
               <el-button type="success" :disabled="uploadVideoRunning" v-else @click="saveOrUpdate">保 存</el-button>
             </el-form-item>
           </el-col>
@@ -326,21 +214,27 @@
 <script>
 import questionPreview from '@/components/education/question-preview'
 
-import {getDictValueByType} from '@/api/dict'
-import {getGradeInfoList} from '@/api/gradeInfo'
-import {selectByParentId, selectFirstPoints} from '@/api/languagePoints'
-import {getSubjectInfoList} from '@/api/subjectInfo'
+import { getDictValueByType } from '@/api/dict'
+import {generatePSRE} from '@/api/ai'
+import { getGradeInfoList } from '@/api/gradeInfo'
+import { selectByParentId, selectFirstPoints } from '@/api/languagePoints'
+import { getSubjectInfoList } from '@/api/subjectInfo'
 import educationSearch from '@/components/education/education-search'
 import AiQuestion from '../../components/education/ai-question.vue'
 // import event from '../../utils/eventbus'
 
 import { formatDate } from '../../utils/date'
+import {publishGoal} from '../../api/goalManage'
+import {getItemPropertyById} from '../../utils/util'
+import axios from 'axios'
 let thisPage = null
 export default {
   name: 'question',
-  components: {educationSearch, questionPreview, AiQuestion},
+  components: { educationSearch, questionPreview, AiQuestion },
   data () {
     return {
+      // psren请求状态
+      psren_loading: false,
       questionPreviewFlag: false,
       gradeInfoList: [],
       Input_text: '',
@@ -361,7 +255,7 @@ export default {
       totalCount: 0,
       pageSize: 10,
       labelName: '添加试题',
-      activeName: 'questions_list',
+      activeName: 'goal_manage',
       answerList: [],
       showTableHeader: true,
       treeLanguagePointsOrigin: [],
@@ -389,6 +283,7 @@ export default {
         content: '',
         subjectId: '',
         gradeId: '',
+        courseId: '',
         schoolType: ''
       },
       uploadVideoRunning: false, // 是否正在上传教学视频
@@ -429,9 +324,9 @@ export default {
           required: true, message: '请选择课程', trigger: 'blur'
         },
 
-        gOriented: {
-          required: true, message: '请输入导向目标', trigger: 'blur'
-        },
+        // gOriented: {
+        //   required: true, message: '请输入导向目标', trigger: 'blur'
+        // },
         pScoreStd: {
           required: true, message: '请输入拆解提示', trigger: 'blur'
         },
@@ -474,32 +369,79 @@ export default {
   },
 
   watch: {
-    // 阶段类型,查询年级
-    'form.schoolType' (val) {
-      let params = {
-        schoolType: val
+    // 阶段类型变化时,查询年级并重置后续选项
+    'form.schoolType': {
+      handler (val) {
+        // 重置依赖于schoolType的字段
+        this.form.gradeId = ''
+        this.form.subjectId = ''
+        this.form.courseId = ''
+
+        // 清空相关列表
+        this.changeGradeTypeList = []
+        this.subjectList = []
+        this.courseList = []
+
+        if (val) {
+          let params = {
+            schoolType: val
+          }
+          getGradeInfoList(params).then(response => {
+            this.changeGradeTypeList = response.data.data.dataList || []
+          }).catch(error => {
+            console.error('获取年级列表失败:', error)
+            this.changeGradeTypeList = []
+          })
+        }
       }
-      getGradeInfoList(params).then(response => {
-        this.changeGradeTypeList = response.data.data.dataList
-      })
+      // immediate: true // 如果需要在初始时也执行
     },
 
-    // 年级变化,查询科目
-    'form.gradeId' (val) {
-      let params = {
-        gradeInfoId: val
+    // 年级变化时,查询科目并重置后续选项
+    'form.gradeId': {
+      handler (val) {
+        // 重置依赖于gradeId的字段
+        this.form.subjectId = ''
+        this.form.courseId = ''
+
+        // 清空相关列表
+        this.subjectList = []
+        this.courseList = []
+
+        if (val) {
+          let params = {
+            gradeInfoId: val
+          }
+          getSubjectInfoList(params).then(response => {
+            this.subjectList = response.data.data.dataList || []
+          }).catch(error => {
+            console.error('获取科目列表失败:', error)
+            this.subjectList = []
+          })
+        }
       }
-      getSubjectInfoList(params).then(response => {
-        this.subjectList = response.data.data.dataList
-      })
+      // immediate: true
     },
-    // 科目变化 ,查询课程
-    'form.subjectId' (val) {
-      let params = {
-        gradeInfoId: this.form.gradeId,
-        subjectId: val
+
+    // 科目变化时,查询课程
+    'form.subjectId': {
+      handler (val) {
+        console.log('学科变化', val)
+        // 重置依赖于subjectId的字段
+        this.form.courseId = ''
+
+        // 清空相关列表
+        this.courseList = []
+
+        if (val && this.form.gradeId) {
+          let params = {
+            gradeInfoId: this.form.gradeId,
+            subjectId: val
+          }
+          this.getCourseList(params)
+        }
       }
-      this.getCourseList(params)
+      // immediate: true
     }
   },
 
@@ -522,6 +464,12 @@ export default {
   },
 
   methods: {
+
+    // 调试课程选择框
+    deBug (val) {
+      this.form.courseId = val
+      console.log('选中课程', val)
+    },
     // 知识点输入以及逗号分隔
     handleInputSplit () {
       const inputValue = this.form.knowPoints.trim()
@@ -554,17 +502,27 @@ export default {
     // 获取课程
     getCourseList (_params) {
       let that = this
-      let q = this.query
-      if (!_params) {
-        q = Object.assign(q, _params)
+      let q = { ...this.query } // 创建查询参数副本
+
+      if (_params) {
+        q = { ...q, ..._params }
       }
 
+      // 显示加载状态
+      this.loading = true
+
       that.axios.get(that.$http.httpUrl('/system/course'), {
         params: q
       }).then(function (response) {
+        that.courseList = response.data.data.dataList || []
+        console.log('课程数据', that.courseList)
+        that.totalCount = response.data.data.total || 0
+      }).catch(function (error) {
+        console.error('获取课程列表失败:', error)
+        that.courseList = []
+        that.totalCount = 0
+      }).finally(() => {
         that.loading = false
-        that.courseList = response.data.data.dataList
-        that.totalCount = response.data.data.total
       })
     },
     // 获取目标
@@ -575,6 +533,7 @@ export default {
           pageNumber: that.currentPage,
           pageSize: that.pageSize,
           subjectId: null,
+          courseId: that.query.courseId,
           gradeId: that.query.gradeId,
           schoolType: that.query.schoolType
         }
@@ -607,8 +566,11 @@ export default {
                   type: 'success',
                   message: response.data.message
                 })
-                that.clearForm()
+                // todo 先不执行clearForm 以防有冲突
+                // that.clearForm()
                 that.getGoalInfoList()
+                // 跳转到目标管理页面
+                that.activeName = 'goal_manage'
               }
             }).catch(function (error) {
               console.log(error)
@@ -697,12 +659,55 @@ export default {
       let option = this.form.optionList[this.optionEditorIndex]
       this.optionEditorInstance.setContent(option.option_name)
     },
-
+   /** *****************列表操作************************* */
     // 试题预览
     lookQuestion (item) {
       this.questionPreviewFlag = true
       this.rowQuestion = item
     },
+    // 发布目标信息到学生端
+    release (row) {
+      // 弹出对话框是否确定发布
+      this.$confirm('确定要发布吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let data = {
+          courseId: row.courseId,
+          gradeId: row.gradeId,
+          gOriented: row.gOriented,
+          pScoreStd: row.pScoreStd,
+          sScoreStd: row.sScoreStd,
+          rScoreStd: row.rScoreStd,
+          eScoreStd: row.eScoreStd,
+          nScoreStd: row.nScoreStd,
+          publishFlag: 1
+        }
+        this.publishGPSREN(data)
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消发布'
+        })
+      })
+
+      console.log('点击发布')
+    },
+    publishGPSREN (data) {
+      publishGoal(data).then((res) => {
+        console.log(res)
+      //   if (res.data.code === 200) {
+      //     this.$message.success('发布成功')
+      //   } else {
+      //     this.$message.error(res.data.message)
+      //   }
+      // }).catch((error) => {
+      //   console.log(error)
+      })
+    },
+
+     /** *****************列表操作************************* */
 
     changeSubject (val) {
       /*  let params = {
@@ -718,11 +723,18 @@ export default {
       this.query.subjectId = val.subjectId
       this.query.schoolType = val.schoolType
       this.query.gradeId = val.gradeId
+      this.query.courseId = val.courseId
       this.query.content = val.keyWord
       this.currentPage = 0
+      console.log('表单数据', val)
       // this.getGoalInfoList()
       this.getGoalInfoList()
     },
+    // 手动创建GPSREN
+    createGPSAREN () {
+        // 跳转到手动添加面板
+      this.activeName = 'create_goal'
+    },
 
     // 模板下载
     downTemplate () {
@@ -961,7 +973,7 @@ export default {
       })
     },
     clearForm (that) {
-      that.answerList = []
+      // that.answerList = []
       that.form = {
         languagePointsInfoId: [],
         analysis: '',
@@ -991,7 +1003,7 @@ export default {
       }
       return true
     },
-
+   /** *****************手动添加**************************/
     save (that) {
       let params = this.form
       debugger
@@ -1025,8 +1037,37 @@ export default {
         }).catch(function (error) {
           console.log(error)
         })
+    },
+    // 自动获取标签
+    // todo:该功能暂时隐藏
+    getTabAuto () {
+    },
+    // AI辅助生成
+    applyAI () {
+      this.psren_loading = true
+      let courseName = getItemPropertyById(this.courseList, this.form.courseId, 'name')
+      let data = {
+        memoryId: 1,
+        courseName: courseName,
+        userMessage: this.form.gOriented
+      }
+      // 直接发起请求
+      // this.axios.post(this.$http.aiUrl('api/teracherGpsren/ManuallyCreatedPsreByG'), data)
+      generatePSRE(data).then((res) => {
+        console.log('ai返回的数据内容', res)
+        if (res.data.code === 1) {
+          this.psren_loading = false
+          this.form.knowPoints = res.data.data.knowledge
+          this.form.pScoreStd = res.data.data.p
+          this.form.sScoreStd = res.data.data.s
+          this.form.rScoreStd = res.data.data.r
+          this.form.eScoreStd = res.data.data.e
+        }
+      }).catch((error) => {
+        console.log(error)
+      })
     }
-
+    /** *****************手动添加************************* */
   },
 
   filters: {
@@ -1049,7 +1090,7 @@ export default {
     },
 
     xFormatDate (val) {
-      return formatDate(val, "yyyy-MM-DD")
+      return formatDate(val, 'yyyy-MM-DD')
     }
   }
 }
@@ -1058,9 +1099,11 @@ export default {
 .el-tag {
   margin-left: 5px;
 }
+
 .mod-menu__icon-popover {
   width: 40%;
 }
+
 .edui-default .edui-editor-toolbarbox {
   position: relative !important;
 }
@@ -1068,7 +1111,8 @@ export default {
 .mod-demo-ueditor {
   position: relative;
   z-index: 510;
-  > .el-alert {
+
+  >.el-alert {
     margin-bottom: 10px;
   }
 }

+ 133 - 15
src/views/main.vue

@@ -10,14 +10,17 @@
         </div>
       </template>
     </div>
-    <div class="assistant" @click="openAssistant()">
-      <div index="1" @click=""
-        style="width: 50px; display: inline-flex;justify-content: center;align-items: center;flex-direction: column;">
+    <div
+      class="assistant"
+      @mousedown="startDrag"
+      :style="assistantStyle"
+    >
+      <div index="1"        style="width: 50px; display: inline-flex;justify-content: center;align-items: center;flex-direction: column;">
         <el-image style="width:40px;height:40px;" :src="AiLogo"></el-image>
         <div style="color: #333;font-weight: bold;">AI助手</div>
       </div>
     </div>
- 
+
       <el-dialog fullscreen :show-close="true" :close-on-click-modal="false" :visible.sync="dialogFormVisible">
         <div slot="title" style="display: flex;justify-content: flex-start;align-items: center;">
           <el-image style="width:26px;height: 14px;"
@@ -25,7 +28,7 @@
           <span style="color: #6c94e7;font-weight: 600;">助手</span>
         </div>
         <ai-assistant></ai-assistant>
-      </el-dialog> 
+      </el-dialog>
   </div>
 
 </template>
@@ -42,7 +45,15 @@ export default {
     return {
       AiLogo,
       dialogFormVisible: false,
-      loading: true
+      loading: true,
+      // 添加拖拽相关数据
+      isDragging: false,
+      dragOffset: { x: 0, y: 0 },
+      dragStart: { x: 0, y: 0 }, // 记录拖拽起始位置
+      assistantPosition: {
+        x: window.innerWidth - 70, // 默认靠右
+        y: window.innerHeight / 2   // 默认居中
+      }
     }
   },
   components: {
@@ -66,6 +77,14 @@ export default {
     userName: {
       get() { return this.$store.state.user.name },
       set(val) { this.$store.commit('user/updateName', val) }
+    },
+    // 添加助手样式计算属性
+    assistantStyle() {
+      return {
+        left: this.assistantPosition.x + 'px',
+        top: this.assistantPosition.y + 'px',
+        cursor: 'move'
+      }
     }
   },
 
@@ -78,7 +97,11 @@ export default {
   },
   methods: {
     openAssistant() {
-      this.dialogFormVisible = true
+      console.log("拖拽状态", this.isDragging)
+      // 只有在非拖拽状态下才打开助手
+      if (!this.isDragging) {
+        this.dialogFormVisible = true;
+      }
     },
     // 重置窗口可视高度
     resetDocumentClientHeight() {
@@ -94,6 +117,104 @@ export default {
         this.userName = userInfo.login_name
       }
       this.loading = false
+    },
+    // 开始拖拽
+    startDrag(event) {
+      console.log("开始拖拽")
+      // 防止点击事件触发拖拽
+      if (event.target.closest('.el-image')) return;
+      if (event.button !== 0) return;
+      //设置拖拽状态
+      this.isDragging = false;
+      const assistant = event.currentTarget;
+      const rect = assistant.getBoundingClientRect();
+      // 记录初始位置
+      this.dragStart.x = event.clientX;
+      this.dragStart.y = event.clientY;
+      // 计算鼠标相对于元素的位置
+      this.dragOffset.x = event.clientX - rect.left;
+      this.dragOffset.y = event.clientY - rect.top;
+
+      // 添加全局事件监听器
+      document.addEventListener('mousemove', this.onDrag);
+      document.addEventListener('mouseup', this.stopDrag);
+
+      // 防止文本选择
+      event.preventDefault();
+    },
+
+    // 拖拽过程中
+    onDrag(event) {
+      console.log("鼠标拖拽", this.isDragging)
+      // if (!this.isDragging) return;
+
+      // 计算新的位置
+      // let newX = event.clientX - this.dragOffset.x;
+      // let newY = event.clientY - this.dragOffset.y;
+      // 计算鼠标移动距离
+      const deltaX = Math.abs(event.clientX - this.dragStart.x);
+      const deltaY = Math.abs(event.clientY - this.dragStart.y);
+      // 如果移动距离超过阈值(5px),则认为是拖拽操作
+      if (!this.isDragging && (deltaX > 5 || deltaY > 5)) {
+        this.isDragging = true;
+        // 添加拖拽时的视觉反馈
+        document.body.style.cursor = 'move';
+        document.body.style.userSelect = 'none';
+      }
+      // 如果是拖拽状态,则更新位置
+      if (this.isDragging) {
+        // 计算新的位置
+        let newX = event.clientX - this.dragOffset.x;
+        let newY = event.clientY - this.dragOffset.y;
+
+        // 获取窗口尺寸
+        const windowWidth = window.innerWidth;
+        const windowHeight = window.innerHeight;
+        const assistantWidth = 50;
+        const assistantHeight = 70;
+
+        // 边界检查
+        newX = Math.max(0, Math.min(newX, windowWidth - assistantWidth));
+        newY = Math.max(0, Math.min(newY, windowHeight - assistantHeight));
+
+        // 更新位置
+        this.assistantPosition.x = newX;
+        this.assistantPosition.y = newY;
+      }
+    },
+
+    // 停止拖拽
+    stopDrag() {
+      console.log("结束拖拽")
+      // 移除全局事件监听器
+      document.removeEventListener('mousemove', this.onDrag);
+      document.removeEventListener('mouseup', this.stopDrag);
+
+
+      // 恢复光标样式
+      document.body.style.cursor = '';
+      document.body.style.userSelect = '';
+
+      // 如果不是拖拽状态,则认为是点击操作
+      if (!this.isDragging) {
+        this.openAssistant();
+      }
+
+      // 重置拖拽状态
+      this.isDragging = false;
+    },
+
+    // 保存位置到本地存储(可选)
+    saveAssistantPosition() {
+      localStorage.setItem('assistantPosition', JSON.stringify(this.assistantPosition));
+    },
+
+    // 从本地存储加载位置(可选)
+    loadAssistantPosition() {
+      const savedPosition = localStorage.getItem('assistantPosition');
+      if (savedPosition) {
+        this.assistantPosition = JSON.parse(savedPosition);
+      }
     }
   }
 }
@@ -103,13 +224,9 @@ export default {
   max-width: 1200px;
 }
 .assistant {
-  position: fixed;
-  margin: auto;
-  right: 20px;
-  top: 0;
-  bottom: 0;
-  height: 70px;
+  position: fixed; /* 改为 fixed 以相对于视窗定位 */
   width: 50px;
+  height: 70px;
   background-color: #b9d5ed;
   box-shadow: 5px 5px 5px 0 rgba(0, 0, 0, 0.5);
   border-radius: 5px;
@@ -118,6 +235,7 @@ export default {
   display: flex;
   justify-content: end;
   align-items: end;
-  cursor: pointer;
+  cursor: move;
+  user-select: none; /* 防止拖拽时选择文本 */
 }
-</style>
+</style>