|
|
@@ -0,0 +1,1290 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+
|
|
|
+
|
|
|
+ <el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
|
|
+ <el-form-item label="客服名称" prop="roleName">
|
|
|
+ <el-input v-model="form.roleName" placeholder="请输入角色名" />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ AI角色名字
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="角色类型" prop="roleType">
|
|
|
+ <el-select v-model="form.roleType" placeholder="请选择类型" clearable size="small" style="width: 150px" >
|
|
|
+ <el-option
|
|
|
+ v-for="item in typeOptions"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="String(item.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 选择角色类型:一般选择伴学助手,医生工作室,伴学助手无性别,无性别版本只会叫用户同学,其余的会叫用户先生女士
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="渠道类型" prop="channelType">
|
|
|
+ <el-select v-model="form.channelType" placeholder="请选择类型" clearable size="small" style="width: 150px" >
|
|
|
+ <el-option
|
|
|
+ v-for="item in channelOptions"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="String(item.dictLabel)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 选择进线渠道:只影响新客户进来的首次对话
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="物流提醒" prop="logistics">
|
|
|
+ <el-switch
|
|
|
+ v-model="form.logistics"
|
|
|
+ :active-value="1"
|
|
|
+ :inactive-value="0"
|
|
|
+ active-text="是"
|
|
|
+ inactive-text="否"
|
|
|
+ active-color="#13ce66"
|
|
|
+ inactive-color="#ff4949"
|
|
|
+ />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ AI是否主动发送物流信息,发货和到货的时候会提醒用户
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="禁止夜间回复" prop="forbidStatus">
|
|
|
+ <el-switch
|
|
|
+ v-model="form.forbidStatus"
|
|
|
+ :active-value="1"
|
|
|
+ :inactive-value="0"
|
|
|
+ active-text="是"
|
|
|
+ inactive-text="否"
|
|
|
+ active-color="#13ce66"
|
|
|
+ inactive-color="#ff4949"
|
|
|
+ />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ AI是否规定时间内不回复消息,默认为开启,在结束时间后再进行最后一条消息回复,关闭后一天24小时都进行回复
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="AI是否发送新客先导课" prop="sendCourseStatus">
|
|
|
+ <el-switch
|
|
|
+ v-model="form.sendCourseStatus"
|
|
|
+ :active-value="1"
|
|
|
+ :inactive-value="0"
|
|
|
+ active-text="是"
|
|
|
+ inactive-text="否"
|
|
|
+ active-color="#13ce66"
|
|
|
+ inactive-color="#ff4949"
|
|
|
+ />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ AI与客户聊天中是否发送新客先导课,默认关闭,开启后,与客户聊天会发送新客先导课
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="新客先导课" prop="courseId">
|
|
|
+ <el-popover
|
|
|
+ placement="bottom"
|
|
|
+ width="300"
|
|
|
+ trigger="click"
|
|
|
+ :visible="coursePopoverVisible"
|
|
|
+ @show="onCoursePopoverShow"
|
|
|
+ >
|
|
|
+ <div class="course-select-popover">
|
|
|
+ <el-input
|
|
|
+ v-if="courseFilterable"
|
|
|
+ placeholder="输入关键字过滤"
|
|
|
+ v-model="courseFilterText"
|
|
|
+ size="mini"
|
|
|
+ clearable
|
|
|
+ class="course-filter-input"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+
|
|
|
+ <div class="course-list-container" :style="{ height: courseListHeight + 'px' }">
|
|
|
+ <div
|
|
|
+ ref="courseVirtualList"
|
|
|
+ class="course-virtual-list"
|
|
|
+ @scroll="handleCourseScroll"
|
|
|
+ :style="{ height: courseListHeight + 'px', overflow: 'auto' }"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="course-virtual-content"
|
|
|
+ :style="{
|
|
|
+ height: courseTotalHeight + 'px',
|
|
|
+ position: 'relative',
|
|
|
+ paddingTop: courseOffsetY + 'px'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in courseVisibleItems"
|
|
|
+ :key="`${item.videoId}-${index}`"
|
|
|
+ :style="{
|
|
|
+ height: courseItemHeight + 'px',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ padding: '0 10px'
|
|
|
+ }"
|
|
|
+ :class="[
|
|
|
+ 'course-virtual-item',
|
|
|
+ {
|
|
|
+ 'is-selected': form.courseId === item.videoId,
|
|
|
+ 'is-disabled': item.disabled
|
|
|
+ }
|
|
|
+ ]"
|
|
|
+ @click="handleCourseItemClick(item)"
|
|
|
+ >
|
|
|
+ <span class="course-label" :title="item.title">{{ item.title }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-button slot="reference" style="min-width: 150px; max-width: 300px;">
|
|
|
+ {{ form.courseId ? getCourseTitle(form.courseId) : '请选择课程' }}
|
|
|
+ <i class="el-icon-arrow-down el-icon--right"></i>
|
|
|
+ </el-button>
|
|
|
+ </el-popover>
|
|
|
+
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 选择课程:客户添加聊天后会根据聊天内容发送这节课程
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ <el-form-item label="客服头像" prop="avatar">
|
|
|
+ <ImageUpload v-model="form.avatar" type="image" :num="1" :width="150" :height="150" style="margin-top: 1%;" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="APPKey" >
|
|
|
+ <el-input type="textarea" v-model="form.modeConfigJson.APPKey" placeholder="请输入APPKey(特定key)" />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 根据管理员发送的APPKey填写
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="提示词" >
|
|
|
+ <el-input type="textarea" :rows="3" v-model="form.reminderWords" placeholder="请输入提示词" />
|
|
|
+ <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 输入个人的介绍,并且在最后增加一个自我介绍(用于首次交流触发),模板可以找管理员获取
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <!-- <el-form-item label="标签人设" >
|
|
|
+ <div v-if="tagsFormList.length > 0" style="display: flex; align-items: center; flex-wrap: wrap; width: 100%;">
|
|
|
+ <div style="min-height: 40px; max-height: 200px; overflow-y: auto; width: 100%;">
|
|
|
+ <div style="display: flex; flex-wrap: wrap; width: 100%;">
|
|
|
+ <div v-for="(tagsForm, index) in tagsFormList" :key="tagsForm.id">
|
|
|
+ <el-tag type="success"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ @click="handleEditRoleTag(tagsForm, index)"
|
|
|
+ @close="handleCloseRoleTag(tagsForm, index)"
|
|
|
+ style="margin: 3px;">
|
|
|
+ {{ getTagNames(tagsForm.tagIds) }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="primary" plain
|
|
|
+ icon="el-icon-circle-plus-outline"
|
|
|
+ @click="handleAddTags(form.roleId,form.bindCorpId)"
|
|
|
+ v-hasPermi="['fastGptRole:fastGptRole:edit']"
|
|
|
+ >添加标签人设</el-button>
|
|
|
+ </el-form-item> -->
|
|
|
+
|
|
|
+ <!-- <el-form-item label="修改栏目" prop="contactInfo">
|
|
|
+ <el-select v-model="contactInfo" multiple filterable placeholder="请选择修改栏目" clearable size="small" style="width: 50%" >
|
|
|
+ <el-option
|
|
|
+ v-for="item in externalInfoOptions"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictValue"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item> -->
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer" style="padding-bottom: 40px;">
|
|
|
+ <el-button type="primary" @click="submitForm" style="float: right;margin-right: 20px;">确 定</el-button>
|
|
|
+ <el-button @click="cancel" style="float: right;margin-right: 20px;">取 消</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 修改-->
|
|
|
+ <el-dialog :title="changeTagsOpen.title" :visible.sync="changeTagsOpen.open" width="800px" append-to-body>
|
|
|
+
|
|
|
+ <el-form ref="tagsForm" :model="tagsForm" :rules="tagsFormRules">
|
|
|
+ <el-form-item label="选择标签" prop="tagIds">
|
|
|
+ <div @click="handleChangeTags(changeTagsOpen.roleId)" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 100%">
|
|
|
+ <div style="min-height: 40px; max-height: 200px; overflow-y: auto;">
|
|
|
+ <el-tag type="success"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ v-for="list in tagListFormIndex"
|
|
|
+ :key="list.tagId"
|
|
|
+ @close="handleCloseTag(list)"
|
|
|
+ style="margin: 3px;"
|
|
|
+ >{{list.name}}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="提示词" prop="reminderWords">
|
|
|
+ <el-input type="textarea" :rows="6" v-model="tagsForm.reminderWords" placeholder="请输入AI客服该标签的提示词" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="submitTagsForm(changeTagsOpen.roleId)">确 定</el-button>
|
|
|
+ <el-button @click="cancelTags">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog :title="tagChange.title" :visible.sync="tagChange.open" width="800px" append-to-body>
|
|
|
+ <div v-for="item in tagGroupList" :key="item.id" >
|
|
|
+ <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
|
|
|
+ <span class="name-background">{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="tag-container">
|
|
|
+ <a
|
|
|
+ v-for="tagItem in item.tag"
|
|
|
+ class="tag-box"
|
|
|
+ @click="tagSelection(tagItem)"
|
|
|
+ :class="{ 'tag-selected': tagItem.isSelected }"
|
|
|
+ >
|
|
|
+ {{ tagItem.name }}
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="editTagSubmitForm(tagChange.roleId)">确 定</el-button>
|
|
|
+ <el-button @click="editTagCancel(tagChange.roleId)">取消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 新增-->
|
|
|
+ <el-dialog :title="changeTagsOpenAdd.title" :visible.sync="changeTagsOpenAdd.open" width="800px" append-to-body>
|
|
|
+
|
|
|
+ <el-form ref="tagsFormAdd" :model="tagsFormAdd" :rules="tagsFormAddRules">
|
|
|
+ <el-form-item label="选择标签" prop="tagIds">
|
|
|
+ <div @click="handleChangeTagsAdd(changeTagsOpenAdd.roleId)" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 100%">
|
|
|
+ <div style="min-height: 40px; max-height: 200px; overflow-y: auto;">
|
|
|
+ <el-tag type="success"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ v-for="list in tagListFormIndexAdd"
|
|
|
+ :key="list.tagId"
|
|
|
+ @close="handleCloseTag(list)"
|
|
|
+ style="margin: 3px;"
|
|
|
+ >{{list.name}}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="提示词" prop="reminderWords">
|
|
|
+ <el-input type="textarea" :rows="6" v-model="tagsFormAdd.reminderWords" placeholder="请输入AI客服该标签的提示词" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="submitAddTagsForm(changeTagsOpenAdd.roleId)">确 定</el-button>
|
|
|
+ <el-button @click="cancelAddTags">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog :title="tagChangeAdd.title" :visible.sync="tagChangeAdd.open" width="800px" append-to-body>
|
|
|
+ <div v-for="item in tagGroupList" :key="item.id" >
|
|
|
+ <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
|
|
|
+ <span class="name-background">{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="tag-container">
|
|
|
+ <a
|
|
|
+ v-for="tagItem in item.tag"
|
|
|
+ class="tag-box"
|
|
|
+ @click="tagSelection(tagItem)"
|
|
|
+ :class="{ 'tag-selected': tagItem.isSelected }"
|
|
|
+ >
|
|
|
+ {{ tagItem.name }}
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="addTagSubmitForm(tagChangeAdd.roleId)">确 定</el-button>
|
|
|
+ <el-button @click="addTagCancel(tagChangeAdd.roleId)">取消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { listFastGptRole, getFastGptRole, delFastGptRole, addFastGptRole, updateFastGptRole, exportFastGptRole,getAllRoleType,getAllCourseList } from "@/api/fastGpt/fastGptRole";
|
|
|
+import {allListTagGroup} from "@/api/qw/tagGroup";
|
|
|
+import {listTag} from "@/api/qw/tag";
|
|
|
+import {
|
|
|
+ addFastGptRoleTag,
|
|
|
+ delFastGptRoleTag,
|
|
|
+ getListByRoleId,
|
|
|
+ updateFastGptRoleTag
|
|
|
+} from "@/api/fastGpt/fastGptRoleTag";
|
|
|
+import source from "echarts/src/data/Source";
|
|
|
+import ImageUpload from "@/views/qw/sop/ImageUpload.vue";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "fastGptRoleUpdate",
|
|
|
+ components: {ImageUpload},
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ logisticsOptions: [
|
|
|
+ { label: '是', value: 1 },
|
|
|
+ { label: '否', value: 0 }
|
|
|
+ ],
|
|
|
+ // 遮罩层
|
|
|
+ loading: true,
|
|
|
+ // 导出遮罩层
|
|
|
+ exportLoading: false,
|
|
|
+ //AI客服类型
|
|
|
+ typeOptions: [],
|
|
|
+
|
|
|
+ // 课程选择相关数据
|
|
|
+ coursePopoverVisible: false,
|
|
|
+ courseFilterText: '',
|
|
|
+ courseFilterable: true,
|
|
|
+ courseListHeight: 300, // 课程列表高度
|
|
|
+ courseItemHeight: 36, // 每个课程项的高度
|
|
|
+ courseStartIndex: 0,
|
|
|
+ courseEndIndex: 0,
|
|
|
+ courseScrollTop: 0,
|
|
|
+ courseVisibleItemCount: 0,
|
|
|
+ courseFlattenedNodes: [], // 扁平化的课程数据
|
|
|
+ courseNodeMap: new Map(), // 课程节点映射
|
|
|
+ courseUpdateTimer: null,
|
|
|
+ courseScrollRAF: null,
|
|
|
+ courseFilterDebounced: null,
|
|
|
+
|
|
|
+ //AI模型
|
|
|
+ modeOptions: [],
|
|
|
+ //渠道类型
|
|
|
+ channelOptions: [],
|
|
|
+ changeTagsOpen: {
|
|
|
+ title : "",
|
|
|
+ open :false,
|
|
|
+ roleId : null,
|
|
|
+ },
|
|
|
+ changeTagsOpenAdd:{
|
|
|
+ title : "",
|
|
|
+ open :false,
|
|
|
+ roleId : null,
|
|
|
+ },
|
|
|
+ //标签弹窗选择
|
|
|
+ tagChange:{
|
|
|
+ open:false,
|
|
|
+ title:"",
|
|
|
+ roleId:null,
|
|
|
+ id:null,
|
|
|
+ },
|
|
|
+ //新增
|
|
|
+ tagChangeAdd:{
|
|
|
+ open:false,
|
|
|
+ title:"",
|
|
|
+ roleId:null,
|
|
|
+ id:null,
|
|
|
+ },
|
|
|
+ //所有的标签组-标签
|
|
|
+ tagGroupList:[],
|
|
|
+
|
|
|
+ //所有的标签
|
|
|
+ tagList:[],
|
|
|
+ contactInfo:[],
|
|
|
+ //已经选择的标签
|
|
|
+ tagListFormIndex:[],
|
|
|
+
|
|
|
+ //新的标签
|
|
|
+ tagListFormIndexAdd:[],
|
|
|
+ // uploadUrl:process.env.VUE_APP_BASE_API+"/chat/upload/uploadFile",
|
|
|
+ uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
|
|
|
+ // 选中数组
|
|
|
+ ids: [],
|
|
|
+ externalInfoOptions : [],
|
|
|
+ // 非单个禁用
|
|
|
+ single: true,
|
|
|
+ // 非多个禁用
|
|
|
+ multiple: true,
|
|
|
+ // 显示搜索条件
|
|
|
+ showSearch: true,
|
|
|
+ // 总条数
|
|
|
+ total: 0,
|
|
|
+ // 应用表格数据
|
|
|
+ fastGptRoleList: [],
|
|
|
+ // 弹出层标题
|
|
|
+ title: "",
|
|
|
+ // 是否显示弹出层
|
|
|
+ open: false,
|
|
|
+ // 查询参数
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ roleName: null,
|
|
|
+ companyId: null,
|
|
|
+ roleType: null,
|
|
|
+ mode: null,
|
|
|
+ kfId: null,
|
|
|
+ kfUrl: null,
|
|
|
+ avatar: null,
|
|
|
+ kfMediaId: null,
|
|
|
+ channelType: null,
|
|
|
+ logistics: null,
|
|
|
+ forbidStatus: null,
|
|
|
+ sendCourseStatus: null,
|
|
|
+ courseId: null,
|
|
|
+ },
|
|
|
+ // ... 其他数据
|
|
|
+ courseListLoaded: false,
|
|
|
+ // 表单参数
|
|
|
+ form: {
|
|
|
+ },
|
|
|
+ //某一个标签组
|
|
|
+ tagsForm:{},
|
|
|
+ //新增
|
|
|
+ tagsFormAdd:{},
|
|
|
+ //当前role的所有标签组
|
|
|
+ tagsFormList:[],
|
|
|
+ // 表单校验
|
|
|
+ rules: {
|
|
|
+ roleName: [
|
|
|
+ { required: true, message: "角色名称不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ roleType: [
|
|
|
+ { required: true, message: "角色类型不能为空", trigger: "change" }
|
|
|
+ ],
|
|
|
+ logistics: [
|
|
|
+ { required: true, message: "物流提醒不能为空", trigger: "change" }
|
|
|
+ ],
|
|
|
+ forbidStatus: [
|
|
|
+ { required: true, message: "禁止夜间回复不能为空", trigger: "change" }
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ tagsFormRules:{
|
|
|
+ tagIds:[
|
|
|
+ { required: true, message: "标签不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ reminderWords:[
|
|
|
+ { required: true, message: "提示词不能为空", trigger: "blur" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ tagsFormAddRules:{
|
|
|
+ tagIds:[
|
|
|
+ { required: true, message: "标签不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ reminderWords:[
|
|
|
+ { required: true, message: "提示词不能为空", trigger: "blur" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ tagListFormIndex: {
|
|
|
+ handler(newList) {
|
|
|
+ if (!Array.isArray(newList)) return; // 仅在 newList 为数组时继续
|
|
|
+
|
|
|
+ // 确保 tagsForm.tagIds 是数组并清空它
|
|
|
+ this.tagsForm.tagIds = [];
|
|
|
+
|
|
|
+ // 遍历 newList,添加 tagId
|
|
|
+ newList.forEach(tags => {
|
|
|
+ if (Array.isArray(tags)) {
|
|
|
+ // 如果 tags 是数组,遍历并添加
|
|
|
+ tags.forEach(item => {
|
|
|
+ if (item && item.tagId !== undefined) {
|
|
|
+ this.tagsForm.tagIds.push(item.tagId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (tags && tags.tagId !== undefined) {
|
|
|
+ // 如果 tags 是单个对象,直接添加
|
|
|
+ this.tagsForm.tagIds.push(tags.tagId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deep: true
|
|
|
+ },
|
|
|
+
|
|
|
+ tagListFormIndexAdd: {
|
|
|
+ handler(newList) {
|
|
|
+
|
|
|
+ if (!Array.isArray(newList)) return; // 仅在 newList 为数组时继续
|
|
|
+
|
|
|
+ // 确保 tagsForm.tagIds 是数组并清空它
|
|
|
+ this.tagsFormAdd.tagIds = [];
|
|
|
+
|
|
|
+ // 遍历 newList,添加 tagId
|
|
|
+ newList.forEach(tags => {
|
|
|
+ if (Array.isArray(tags)) {
|
|
|
+ // 如果 tags 是数组,遍历并添加
|
|
|
+ tags.forEach(item => {
|
|
|
+ if (item && item.tagId !== undefined) {
|
|
|
+ this.tagsFormAdd.tagIds.push(item.tagId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (tags && tags.tagId !== undefined) {
|
|
|
+ // 如果 tags 是单个对象,直接添加
|
|
|
+ this.tagsFormAdd.tagIds.push(tags.tagId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ courseTotalHeight() {
|
|
|
+ return this.courseVisibleNodes.length * this.courseItemHeight;
|
|
|
+ },
|
|
|
+ courseOffsetY() {
|
|
|
+ return this.courseStartIndex * this.courseItemHeight;
|
|
|
+ },
|
|
|
+ courseVisibleNodes() {
|
|
|
+ let nodes = this.courseFlattenedNodes;
|
|
|
+ if (this.courseFilterText.trim()) {
|
|
|
+ nodes = this.applyCourseFilter(nodes);
|
|
|
+ }
|
|
|
+ return nodes;
|
|
|
+ },
|
|
|
+ courseVisibleItems() {
|
|
|
+ return this.courseVisibleNodes.slice(this.courseStartIndex, this.courseEndIndex);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ // 清理定时器
|
|
|
+ if (this.courseUpdateTimer) clearTimeout(this.courseUpdateTimer);
|
|
|
+ if (this.courseScrollRAF) cancelAnimationFrame(this.courseScrollRAF);
|
|
|
+ },
|
|
|
+ async created() {
|
|
|
+ this.handleUpdate();
|
|
|
+ await this.loadCourseList();
|
|
|
+ this.courseListLoaded = true
|
|
|
+ // 初始化课程选择相关数据
|
|
|
+ this.initCourseData();
|
|
|
+ //客服类型
|
|
|
+ // this.getDicts("chat_role_type").then((response) => {
|
|
|
+ // this.typeOptions = response.data;
|
|
|
+ // });
|
|
|
+ //AI模型
|
|
|
+ this.getDicts("chat_role_mode").then((response) => {
|
|
|
+ this.modeOptions = response.data;
|
|
|
+ });
|
|
|
+ this.getDicts("sys_fastgpt_role_external_info").then((response) => {
|
|
|
+ this.externalInfoOptions = response.data;
|
|
|
+ });
|
|
|
+ //渠道类型
|
|
|
+ this.getDicts("sys_fastgpt_channel_type").then((response) => {
|
|
|
+ this.channelOptions = response.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ getAllRoleType().then(response => {
|
|
|
+ this.typeOptions = response.data;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ // 确保 DOM 已渲染完成
|
|
|
+ this.initScrollListener();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 初始化课程选择相关数据
|
|
|
+ initCourseData() {
|
|
|
+ this.courseVisibleItemCount = Math.ceil(this.courseListHeight / this.courseItemHeight) + 5;
|
|
|
+
|
|
|
+ // 防抖函数
|
|
|
+ this.handleCourseFilterDebounced = this.debounce(this.filterCourseTextChange, 300);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 防抖函数
|
|
|
+ debounce(func, wait) {
|
|
|
+ let timeout;
|
|
|
+ return function executedFunction(...args) {
|
|
|
+ const later = () => {
|
|
|
+ clearTimeout(timeout);
|
|
|
+ func(...args);
|
|
|
+ };
|
|
|
+ clearTimeout(timeout);
|
|
|
+ timeout = setTimeout(later, wait);
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理课程数据
|
|
|
+ processCourseData(data) {
|
|
|
+ if (!Array.isArray(data)) {
|
|
|
+ this.courseFlattenedNodes = [];
|
|
|
+ this.courseNodeMap.clear();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const flattened = [];
|
|
|
+ const nodeMap = new Map();
|
|
|
+
|
|
|
+ data.forEach((item, index) => {
|
|
|
+ const courseItem = {
|
|
|
+ videoId: item.videoId && typeof item.videoId === 'string' ? item.videoId : String(item.videoId || Math.random()),
|
|
|
+ title: item.title && typeof item.title === 'string' ? item.title : String(item.title || item.name || item.videoId || '未命名课程'),
|
|
|
+ originalData: item,
|
|
|
+ disabled: false
|
|
|
+ };
|
|
|
+
|
|
|
+ flattened.push(courseItem);
|
|
|
+ nodeMap.set(courseItem.videoId, courseItem);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.courseFlattenedNodes = flattened;
|
|
|
+ this.courseNodeMap = nodeMap;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 应用课程过滤
|
|
|
+ applyCourseFilter(nodesToFilter) {
|
|
|
+ const searchText = this.courseFilterText.toLowerCase().trim();
|
|
|
+ if (!searchText) return nodesToFilter;
|
|
|
+
|
|
|
+ return nodesToFilter.filter(node =>
|
|
|
+ node.title.toLowerCase().includes(searchText)
|
|
|
+ );
|
|
|
+ },
|
|
|
+
|
|
|
+ // 计算可见范围
|
|
|
+ calculateCourseVisibleRange() {
|
|
|
+ const containerHeight = this.courseListHeight;
|
|
|
+ const totalItems = this.courseVisibleNodes.length;
|
|
|
+
|
|
|
+ const newStartIndex = Math.floor(this.courseScrollTop / this.courseItemHeight);
|
|
|
+ const visibleCountInViewport = Math.ceil(containerHeight / this.courseItemHeight);
|
|
|
+
|
|
|
+ const buffer = 5;
|
|
|
+ this.courseStartIndex = Math.max(0, newStartIndex - buffer);
|
|
|
+ this.courseEndIndex = Math.min(totalItems, newStartIndex + visibleCountInViewport + buffer);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 滚动处理
|
|
|
+ handleCourseScroll(e) {
|
|
|
+ const newScrollTop = e.target.scrollTop;
|
|
|
+ if (newScrollTop !== this.courseScrollTop) {
|
|
|
+ this.courseScrollTop = newScrollTop;
|
|
|
+ if (!this.courseScrollRAF) {
|
|
|
+ this.courseScrollRAF = requestAnimationFrame(() => {
|
|
|
+ this.calculateCourseVisibleRange();
|
|
|
+ this.courseScrollRAF = null;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 重置滚动
|
|
|
+ resetCourseScroll() {
|
|
|
+ this.courseScrollTop = 0;
|
|
|
+ if (this.$refs.courseVirtualList) {
|
|
|
+ this.$refs.courseVirtualList.scrollTop = 0;
|
|
|
+ }
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.calculateCourseVisibleRange();
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 课程过滤文本变化
|
|
|
+ filterCourseTextChange() {
|
|
|
+ this.resetCourseScroll();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 课程项点击
|
|
|
+ handleCourseItemClick(course) {
|
|
|
+ if (course.disabled) return;
|
|
|
+ this.form.courseId = course.videoId;
|
|
|
+ this.coursePopoverVisible = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 课程弹出框显示
|
|
|
+ onCoursePopoverShow() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.resetCourseScroll();
|
|
|
+ if (this.courseFilterable && this.$refs.courseVirtualList) {
|
|
|
+ const inputEl = this.$refs.courseVirtualList.parentElement.querySelector('.course-filter-input input');
|
|
|
+ if (inputEl) inputEl.focus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 初始化滚动监听器
|
|
|
+ initScrollListener() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const container = this.$refs.courseSelectContainer;
|
|
|
+ if (container) {
|
|
|
+ // 移除之前的事件监听器,避免重复绑定
|
|
|
+ container.removeEventListener('scroll', this.handleScroll);
|
|
|
+
|
|
|
+ // 添加新的滚动事件监听器
|
|
|
+ container.addEventListener('scroll', this.handleScroll);
|
|
|
+
|
|
|
+ // 添加初始调试信息
|
|
|
+ console.log('滚动监听器已初始化');
|
|
|
+ console.log('容器总高度:', container.scrollHeight);
|
|
|
+ console.log('可见高度:', container.clientHeight);
|
|
|
+ console.log('课程总数:', this.allCourseOptions.length);
|
|
|
+ console.log('当前显示:', this.displayCourseOptions.length);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getCourseTitle(videoId) {
|
|
|
+ if (!videoId) return '请选择课程';
|
|
|
+
|
|
|
+ console.log(videoId);
|
|
|
+ // 优先从处理后的课程数据中查找
|
|
|
+ const course = this.courseNodeMap.get(String(videoId));
|
|
|
+ if (course) {
|
|
|
+ return course.title;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果在虚拟滚动数据中找不到,尝试从原始数据中查找
|
|
|
+ const originalCourse = this.allCourseOptions.find(item => item.videoId === videoId);
|
|
|
+ return originalCourse ? originalCourse.title : '未找到对应课程';
|
|
|
+ },
|
|
|
+ // 滚动处理函数
|
|
|
+ // 滚动处理函数 - 改进检测逻辑
|
|
|
+ // 滚动处理函数 - 改进检测逻辑
|
|
|
+ handleScroll(event) {
|
|
|
+ const container = event.target;
|
|
|
+ const { scrollTop, scrollHeight, clientHeight } = container;
|
|
|
+
|
|
|
+ // 更精确的滚动到底部检测
|
|
|
+ const threshold = 5; // 阈值调整为5px
|
|
|
+ if (scrollTop + clientHeight >= scrollHeight - threshold &&
|
|
|
+ !this.loadingMore &&
|
|
|
+ this.hasMore) {
|
|
|
+ this.loadMoreCourses();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 修复滚动加载方法,添加更详细的日志
|
|
|
+ // 修复后的滚动加载方法
|
|
|
+ async loadMoreCourses() {
|
|
|
+ if (this.loadingMore || !this.hasMore) {
|
|
|
+ console.log('加载条件不满足:', { loadingMore: this.loadingMore, hasMore: this.hasMore });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('开始加载更多课程');
|
|
|
+ this.loadingMore = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 短暂延迟以避免频繁请求
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
+
|
|
|
+ // 使用全部课程列表
|
|
|
+ const sourceList = this.allCourseOptions;
|
|
|
+
|
|
|
+ // 修复分页逻辑:从 (currentPage - 1) * pageSize 开始
|
|
|
+ const start = (this.currentPage - 1) * this.pageSize;
|
|
|
+ const end = start + this.pageSize;
|
|
|
+ const moreCourses = sourceList.slice(start, end);
|
|
|
+
|
|
|
+ console.log('加载的课程范围:', { start, end, count: moreCourses.length });
|
|
|
+
|
|
|
+ if (moreCourses.length > 0) {
|
|
|
+ // 添加新课程到显示列表(注意:使用 concat 或扩展运算符避免重复添加)
|
|
|
+ this.displayCourseOptions = [...this.displayCourseOptions, ...moreCourses];
|
|
|
+ this.currentPage++; // 递增页码
|
|
|
+ // 检查是否还有更多课程
|
|
|
+ this.hasMore = end < sourceList.length;
|
|
|
+ console.log('更新后的课程列表长度:', this.displayCourseOptions.length, '还有更多:', this.hasMore);
|
|
|
+ } else {
|
|
|
+ // 没有更多课程时停止加载
|
|
|
+ this.hasMore = false;
|
|
|
+ console.log('没有更多课程可加载');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载更多课程失败:', error);
|
|
|
+ this.hasMore = false;
|
|
|
+ } finally {
|
|
|
+ this.loadingMore = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadCourseList() {
|
|
|
+ try {
|
|
|
+ const companyId = this.$route.query.companyId;
|
|
|
+ if (!companyId) {
|
|
|
+ console.warn('缺少 companyId,无法加载课程列表');
|
|
|
+ this.courseOptions = [];
|
|
|
+ this.displayCourseOptions = [];
|
|
|
+ this.allCourseOptions = [];
|
|
|
+ this.hasMore = false;
|
|
|
+ this.courseFlattenedNodes = [];
|
|
|
+ this.courseNodeMap.clear();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const response = await getAllCourseList(companyId);
|
|
|
+ if (Array.isArray(response.data)) {
|
|
|
+ this.courseOptions = response.data
|
|
|
+ .filter(item => item !== null && item !== undefined)
|
|
|
+ .map(item => ({
|
|
|
+ ...item,
|
|
|
+ videoId: item.videoId && typeof item.videoId === 'string' ? item.videoId : String(item.videoId || Math.random()),
|
|
|
+ title: item.title && typeof item.title === 'string' ? item.title : String(item.title || item.name || item.videoId || '未命名课程')
|
|
|
+ }));
|
|
|
+
|
|
|
+ this.allCourseOptions = [...this.courseOptions];
|
|
|
+ // 重置分页参数 - 从第一页开始
|
|
|
+ this.currentPage = 1;
|
|
|
+ // 默认展示前100条
|
|
|
+ this.displayCourseOptions = this.courseOptions.slice(0, this.pageSize);
|
|
|
+ this.hasMore = this.courseOptions.length > this.pageSize;
|
|
|
+
|
|
|
+ // 处理课程数据为虚拟滚动格式
|
|
|
+ this.processCourseData(this.courseOptions);
|
|
|
+ } else {
|
|
|
+ console.warn('getAllCourseList 返回的数据不是数组格式:', response.data);
|
|
|
+ this.courseOptions = [];
|
|
|
+ this.displayCourseOptions = [];
|
|
|
+ this.allCourseOptions = [];
|
|
|
+ this.hasMore = false;
|
|
|
+ this.courseFlattenedNodes = [];
|
|
|
+ this.courseNodeMap.clear();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('课程列表加载失败:', error);
|
|
|
+ this.courseOptions = [];
|
|
|
+ this.displayCourseOptions = [];
|
|
|
+ this.allCourseOptions = [];
|
|
|
+ this.hasMore = false;
|
|
|
+ this.courseFlattenedNodes = [];
|
|
|
+ this.courseNodeMap.clear();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /** 查询应用列表 */
|
|
|
+ getList() {
|
|
|
+ this.loading = true;
|
|
|
+ listFastGptRole(this.queryParams).then(response => {
|
|
|
+ this.fastGptRoleList = response.rows;
|
|
|
+ this.total = response.total;
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 取消按钮
|
|
|
+ cancel() {
|
|
|
+
|
|
|
+ this.reset();
|
|
|
+ window.location.replace('/fastGpt/fastGptRole')
|
|
|
+ },
|
|
|
+ cancelTags(){
|
|
|
+ this.changeTagsOpen.open=false;
|
|
|
+ },
|
|
|
+ cancelAddTags(){
|
|
|
+ this.changeTagsOpenAdd.open=false;
|
|
|
+ },
|
|
|
+ handleAvatarSuccess(res, file) {
|
|
|
+ if(res.code==200){
|
|
|
+ if(res.data.errcode!=0){
|
|
|
+ this.msgError(res.data.errmsg);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ //获取图片
|
|
|
+ this.form.kfMediaId=res.data.media_id;
|
|
|
+ this.form.avatar = res.ossUrl;
|
|
|
+ this.$forceUpdate()
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeAvatarUpload(file) {
|
|
|
+ const isLt1M = file.size / 1024 / 1024 < 1;
|
|
|
+ if (!isLt1M) {
|
|
|
+ this.$message.error('上传图片大小不能超过 1MB!');
|
|
|
+ }
|
|
|
+ return isLt1M;
|
|
|
+ },
|
|
|
+ // 表单重置
|
|
|
+ reset() {
|
|
|
+ this.form = {
|
|
|
+ roleId: null,
|
|
|
+ roleName: null,
|
|
|
+ companyId: null,
|
|
|
+ createTime: null,
|
|
|
+ updateTime: null,
|
|
|
+ roleType: null,
|
|
|
+ modeConfigJson:{APPKey:null,Key:null},
|
|
|
+ mode: 2,
|
|
|
+ kfId: null,
|
|
|
+ kfUrl: null,
|
|
|
+ avatar: null,
|
|
|
+ kfMediaId: null,
|
|
|
+ reminderWords: null,
|
|
|
+ isTags:null,
|
|
|
+ };
|
|
|
+ this.resetForm("form");
|
|
|
+ },
|
|
|
+
|
|
|
+ tagRest(){
|
|
|
+ this.tagListFormIndex=[];
|
|
|
+ this.tagsForm={
|
|
|
+ tagIds:null,
|
|
|
+ reminderWords:null,
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ tagAddRest(){
|
|
|
+ this.tagListFormIndexAdd=[];
|
|
|
+ this.tagsFormAdd={
|
|
|
+ tagIds:null,
|
|
|
+ reminderWords:null,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ /** 搜索按钮操作 */
|
|
|
+ handleQuery() {
|
|
|
+ this.queryParams.pageNum = 1;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ /** 重置按钮操作 */
|
|
|
+ resetQuery() {
|
|
|
+ this.resetForm("queryForm");
|
|
|
+ this.handleQuery();
|
|
|
+ },
|
|
|
+ // 多选框选中数据
|
|
|
+ handleSelectionChange(selection) {
|
|
|
+ this.ids = selection.map(item => item.roleId)
|
|
|
+ this.single = selection.length!==1
|
|
|
+ this.multiple = !selection.length
|
|
|
+ },
|
|
|
+
|
|
|
+ /** 修改按钮操作 */
|
|
|
+ handleUpdate() {
|
|
|
+ var id=this.$route.params.command
|
|
|
+ this.reset();
|
|
|
+ getFastGptRole(id).then(response => {
|
|
|
+ this.form = response.role;
|
|
|
+ this.form.roleType = JSON.stringify(response.role.roleType);
|
|
|
+ if(this.form.modeConfigJson!=null&&this.form.modeConfigJson!=""){
|
|
|
+ this.form.modeConfigJson=JSON.parse(this.form.modeConfigJson)
|
|
|
+ }else{
|
|
|
+ this.form.modeConfigJson={APPKey:null}
|
|
|
+ }
|
|
|
+ if(this.form.contactInfo!=null){
|
|
|
+ this.contactInfo = (this.form.contactInfo).split(",");
|
|
|
+ }
|
|
|
+ //含标签吗
|
|
|
+ getListByRoleId(id).then(res => {
|
|
|
+ this.tagsFormList=res.rows;
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ allListTagGroup({corpId:this.form.corpId}).then(response => {
|
|
|
+ this.tagGroupList = response.rows;
|
|
|
+ });
|
|
|
+
|
|
|
+ //所有的标签
|
|
|
+ listTag({corpId:this.form.corpId}).then(response => {
|
|
|
+ this.tagList = response.rows;
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ this.title = "修改应用";
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ getTagNames(tagIds) {
|
|
|
+ // 确保 tagIds 是数组,如果是字符串则分割
|
|
|
+ const idsArray = Array.isArray(tagIds) ? tagIds : tagIds.split(",");
|
|
|
+ return idsArray.map(tagId => {
|
|
|
+ const tag = this.tagList.find(list => list.tagId === tagId);
|
|
|
+ return tag ? tag.name : tagId; // 返回标签名称或原 tagId
|
|
|
+ }).join(', '); // 使用逗号和空格连接标签名称
|
|
|
+ },
|
|
|
+
|
|
|
+ //标签回复人设弹窗
|
|
|
+ handleAddTags(value,bindCorpId) {
|
|
|
+ if (bindCorpId==null){
|
|
|
+ this.$message({
|
|
|
+ message: '请先给AI客服-绑定企业 再添加标签【企微管理->员工管理->企微员工】',
|
|
|
+ type: 'warning'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.changeTagsOpenAdd.title="创建标签回复人设";
|
|
|
+ this.changeTagsOpenAdd.open=true;
|
|
|
+ this.changeTagsOpenAdd.roleId=value;
|
|
|
+ },
|
|
|
+
|
|
|
+ //选择标签弹窗
|
|
|
+ handleChangeTags(roleId){
|
|
|
+
|
|
|
+ this.tagChange.open=true;
|
|
|
+ this.tagChange.title='选择标签';
|
|
|
+ this.tagChange.roleId=roleId;
|
|
|
+
|
|
|
+ // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
|
|
|
+ const selectedTagIds = new Set(this.tagListFormIndex.map(tagItem => tagItem.tagId));
|
|
|
+ for (let i = 0; i < this.tagGroupList.length; i++) {
|
|
|
+ for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
|
|
|
+ this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ handleChangeTagsAdd(roleId){
|
|
|
+ this.tagChangeAdd.open=true;
|
|
|
+ this.tagChangeAdd.title='选择标签';
|
|
|
+ this.tagChangeAdd.roleId=roleId;
|
|
|
+ },
|
|
|
+ //标签的选择
|
|
|
+ tagSelection(row){
|
|
|
+ row.isSelected= !row.isSelected;
|
|
|
+ this.$forceUpdate();
|
|
|
+ },
|
|
|
+ //删除一些已经选择了的标签
|
|
|
+ handleCloseTag(list){
|
|
|
+
|
|
|
+ // 假设 list 对象具有一个 id 属性
|
|
|
+ const ls = this.tagListFormIndex.findIndex(t => t.tagId === list.tagId);
|
|
|
+ if (ls !== -1) {
|
|
|
+ this.tagListFormIndex.splice(ls, 1);
|
|
|
+ this.tagListFormIndex = [...this.tagListFormIndex];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ //删除一下已经存在的
|
|
|
+ handleCloseRoleTag(row){
|
|
|
+ delFastGptRoleTag(row.id).then(res => {
|
|
|
+ getListByRoleId(row.roleId).then(res => {
|
|
|
+ this.tagsFormList=res.rows;
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ //点击单个
|
|
|
+ handleEditRoleTag(value, index) {
|
|
|
+
|
|
|
+ this.changeTagsOpen.open = true;
|
|
|
+ this.changeTagsOpen.title = "编辑标签回复人设";
|
|
|
+ this.changeTagsOpen.roleId = value.roleId;
|
|
|
+ this.tagsForm = value;
|
|
|
+
|
|
|
+ // 过滤 tagList,获取匹配的标签
|
|
|
+ const tagIdsArray = Array.isArray(value.tagIds) ? value.tagIds : value.tagIds.split(",");
|
|
|
+ this.tagListFormIndex = this.tagList.filter(tag => tagIdsArray.includes(tag.tagId));
|
|
|
+ },
|
|
|
+ //选择标签
|
|
|
+ editTagSubmitForm(){
|
|
|
+
|
|
|
+ for (let i = 0; i < this.tagGroupList.length; i++) {
|
|
|
+ for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
|
|
|
+ if (this.tagGroupList[i].tag[x].isSelected === true) {
|
|
|
+
|
|
|
+ if (!this.tagListFormIndex) {
|
|
|
+ this.tagListFormIndex = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
|
|
|
+ let tagExists = this.tagListFormIndex.some(
|
|
|
+ tag => tag.id === this.tagGroupList[i].tag[x].id
|
|
|
+ );
|
|
|
+
|
|
|
+ // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
|
|
|
+ if (!tagExists) {
|
|
|
+ this.tagListFormIndex.push(this.tagGroupList[i].tag[x]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!this.tagListFormIndex || this.tagListFormIndex.length === 0) {
|
|
|
+ return this.$message('请选择标签');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.tagChange.open = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ //新增的标签
|
|
|
+ addTagSubmitForm(){
|
|
|
+ for (let i = 0; i < this.tagGroupList.length; i++) {
|
|
|
+ for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
|
|
|
+ if (this.tagGroupList[i].tag[x].isSelected === true) {
|
|
|
+
|
|
|
+ if (!this.tagListFormIndexAdd) {
|
|
|
+ this.tagListFormIndexAdd = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
|
|
|
+ let tagExists = this.tagListFormIndexAdd.some(
|
|
|
+ tag => tag.id === this.tagGroupList[i].tag[x].id
|
|
|
+ );
|
|
|
+
|
|
|
+ // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
|
|
|
+ if (!tagExists) {
|
|
|
+ this.tagListFormIndexAdd.push(this.tagGroupList[i].tag[x]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!this.tagListFormIndexAdd || this.tagListFormIndexAdd.length === 0) {
|
|
|
+ return this.$message('请选择标签');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.tagChangeAdd.open = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ //取消选择标签
|
|
|
+ editTagCancel(){
|
|
|
+ this.tagChange.open = false;
|
|
|
+ // this.tagRest();
|
|
|
+ },
|
|
|
+ addTagCancel(){
|
|
|
+ this.tagChangeAdd.open = false;
|
|
|
+ this.tagAddRest();
|
|
|
+ },
|
|
|
+ /** 提交按钮 */
|
|
|
+ submitForm() {
|
|
|
+ if(this.contactInfo!=null){
|
|
|
+ this.form.contactInfo= (this.contactInfo).toString()
|
|
|
+ }
|
|
|
+ this.$refs["form"].validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ this.form.modeConfigJson=JSON.stringify(this.form.modeConfigJson)
|
|
|
+ if (this.form.roleId != null) {
|
|
|
+ updateFastGptRole(this.form).then(response => {
|
|
|
+ this.msgSuccess("修改成功");
|
|
|
+ window.location.replace('/fastGpt/fastGptRole')
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ submitTagsForm(roleId){
|
|
|
+ this.$refs["tagsForm"].validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+
|
|
|
+ this.tagsForm.roleId=roleId
|
|
|
+ this.tagsForm.tagIds=this.tagsForm.tagIds.join(",")
|
|
|
+ if (this.tagsForm.id!= null) {
|
|
|
+ updateFastGptRoleTag(this.tagsForm).then(response => {
|
|
|
+ this.msgSuccess("修改成功");
|
|
|
+ this.changeTagsOpen = false;
|
|
|
+ this.getList();
|
|
|
+ });
|
|
|
+ }else {
|
|
|
+ addFastGptRoleTag(this.tagsForm).then(response => {
|
|
|
+ this.msgSuccess("新增成功");
|
|
|
+ this.changeTagsOpen = false;
|
|
|
+ this.getList();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ submitAddTagsForm(roleId){
|
|
|
+ this.$refs["tagsFormAdd"].validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ this.tagsFormAdd.roleId=roleId
|
|
|
+ this.tagsFormAdd.tagIds=this.tagsFormAdd.tagIds.join(",")
|
|
|
+ addFastGptRoleTag(this.tagsFormAdd).then(response => {
|
|
|
+ this.msgSuccess("新增成功");
|
|
|
+ this.changeTagsOpenAdd = false;
|
|
|
+ this.open=false;
|
|
|
+ this.handleUpdate();
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 删除按钮操作 */
|
|
|
+ handleDelete(row) {
|
|
|
+ const roleIds = row.roleId || this.ids;
|
|
|
+ this.$confirm('是否确认删除应用编号为"' + roleIds + '"的数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function() {
|
|
|
+ return delFastGptRole(roleIds);
|
|
|
+ }).then(() => {
|
|
|
+ this.getList();
|
|
|
+ this.msgSuccess("删除成功");
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ /** 导出按钮操作 */
|
|
|
+ handleExport() {
|
|
|
+ const queryParams = this.queryParams;
|
|
|
+ this.$confirm('是否确认导出所有应用数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(() => {
|
|
|
+ this.exportLoading = true;
|
|
|
+ return exportFastGptRole(queryParams);
|
|
|
+ }).then(response => {
|
|
|
+ this.download(response.msg);
|
|
|
+ this.exportLoading = false;
|
|
|
+ }).catch(() => {});
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+/* CSS 样式 */
|
|
|
+.tag-container {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap; /* 超出宽度时自动换行 */
|
|
|
+ gap: 8px; /* 设置标签之间的间距 */
|
|
|
+}
|
|
|
+.name-background {
|
|
|
+ display: inline-block;
|
|
|
+ background-color: #abece6; /* 背景颜色 */
|
|
|
+ padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
|
|
|
+ border-radius: 4px; /* 可选:设置圆角 */
|
|
|
+}
|
|
|
+.tag-box {
|
|
|
+ padding: 8px 12px;
|
|
|
+ border: 1px solid #989797;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ display: inline-block;
|
|
|
+}
|
|
|
+
|
|
|
+.tag-selected {
|
|
|
+ background-color: #00bc98;
|
|
|
+ color: #fff;
|
|
|
+ border-color: #00bc98;
|
|
|
+}
|
|
|
+
|
|
|
+.el-tag + .el-tag {
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.button-new-tag {
|
|
|
+ margin-left: 10px;
|
|
|
+ height: 32px;
|
|
|
+ line-height: 30px;
|
|
|
+ padding-top: 0;
|
|
|
+ padding-bottom: 0;
|
|
|
+}
|
|
|
+.input-new-tag {
|
|
|
+ width: 90px;
|
|
|
+ margin-left: 10px;
|
|
|
+ vertical-align: bottom;
|
|
|
+}
|
|
|
+.text-container {
|
|
|
+ max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
|
|
|
+ overflow-y: auto; /* 内容超出时显示滚动条 */
|
|
|
+ line-height: 1.5em; /* 行高设置,确保每行高度一致 */
|
|
|
+}
|
|
|
+</style>
|