|
@@ -0,0 +1,1702 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 1 && formType==1 "> sop规则【修改企微接口】模板</div>
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 1 && formType==2 "> sop规则【复制企微接口】模板</div>
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 1 && formType==3 "> sop规则【查看企微接口】模板</div>
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 2 && formType==1 "> sop规则【修改群发助手】模板</div>
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 2 && formType==2 "> sop规则【复制群发助手】模板</div>
|
|
|
+ <div style="margin: 30px;" v-if="this.form.sendType == 2 && formType==3 "> sop规则【查看群发助手】模板</div>
|
|
|
+ <div style="margin: 30px;">模板编号:【{{ this.form.id }}】</div>
|
|
|
+
|
|
|
+ <div style="margin-top: 10px;margin-left: 50px;margin-right: 100px;margin-bottom: 60px;">
|
|
|
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
|
|
+ <el-form-item label="名称" prop="name">
|
|
|
+ {{ form.name }}
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="状态">
|
|
|
+ <el-tag v-for="dict in statusOptions" v-if="dict.dictValue == form.status">{{ dict.dictLabel }}</el-tag>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="间隔天数" prop="gap">
|
|
|
+ {{ form.gap }}天
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="规则" prop="setting">
|
|
|
+ <el-link type="primary" class="el-icon-plus" :underline="false" @click='addSetting()'
|
|
|
+ v-if="form.sendType != 4 && formType != 3">添加天数
|
|
|
+ </el-link>
|
|
|
+ <el-link type="primary" class="el-icon-sort" :underline="false" @click='openUpdateDaySorts()'
|
|
|
+ style="margin-left: 20px"
|
|
|
+ v-if="form.sendType != 4 && formType != 3">修改天数排序
|
|
|
+ </el-link>
|
|
|
+ <el-link type="primary" class="el-icon-sort" :underline="false" @click='openUpdateSorts()'
|
|
|
+ style="margin-left: 20px"
|
|
|
+ v-if="form.sendType != 4 && formType != 3">修改规则排序
|
|
|
+ </el-link>
|
|
|
+ <el-link type="primary" class="el-icon-plus" :underline="false" @click='addSetting()'
|
|
|
+ v-if="form.sendType == 4 && (formType != 3 && setting.length < 1)">添加天数
|
|
|
+ </el-link>
|
|
|
+ <el-tabs v-model="tabIndex" type="card" @tab-remove="delSetting" v-if="setting && setting.length > 0"
|
|
|
+ :before-leave="leave" @tab-click="tabClick">
|
|
|
+ <el-tab-pane v-for="(item, index) in setting" :closable="formType != 3" :key="index" :name="index + ''">
|
|
|
+ <el-badge slot="label" :is-dot="!item.id" class="item" style="display: inline-block">
|
|
|
+ <span>{{ '第' + item.dayNum + '天' }}</span>
|
|
|
+ </el-badge>
|
|
|
+ <el-row v-loading="loading">
|
|
|
+ <el-col :span="22">
|
|
|
+ <div
|
|
|
+ style="background-color: #fbfbfb;padding: 15px; border: 1px solid #e6e6e6; margin-bottom: 20px;">
|
|
|
+ <el-form :model="item" label-width="80px">
|
|
|
+ <el-form-item v-if="form.sendType != 4" label="内容名称" style="height: 50px;">
|
|
|
+ <el-input :disabled="formType == 3" v-model="item.name"
|
|
|
+ placeholder="内容名称,仅内部可见"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="课程" v-if="form.sendType == 5 && item.content && item.content.length > 0" required>
|
|
|
+ <el-select :disabled="formType == 3 || form.sendType == 5" v-model="item.content[0].courseId"
|
|
|
+ placeholder="请选择课程" style=" margin-right: 10px;" size="mini" remote
|
|
|
+ filterable
|
|
|
+ @change="courseChangeUpdate(item.content[0], index, 0)">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in courseList"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="parseInt(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-select :disabled="formType == 3 || form.sendType == 5" v-model="item.content[0].videoId"
|
|
|
+ placeholder="请选择小节" size="mini" style=" margin-right: 10px;" remote
|
|
|
+ filterable
|
|
|
+ @change="videoIdChange(item.content[0],index,0)">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in videoList[0]"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="parseInt(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-select :disabled="formType == 3" v-model="item.content[0].courseType"
|
|
|
+ placeholder="请选择消息类型" size="mini"
|
|
|
+ style=" margin-right: 10px;" v-if="item.content[0].type != 4 ">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in sysFsSopWatchStatus"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="Number(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="规则">
|
|
|
+ <div v-for="(content, contentIndex) in item.content" :key="contentIndex"
|
|
|
+ style="background-color: #fdfdfd;padding: 15px; border: 1px solid #e6e6e6; margin-bottom: 20px;">
|
|
|
+ <el-row>
|
|
|
+ <el-col el-col :span="22">
|
|
|
+ <el-form :model="content" label-width="70px">
|
|
|
+ <div v-if="item.dayNum==1">
|
|
|
+ <el-form-item label="时间" v-if="form.sendType != 4">
|
|
|
+ <el-time-picker
|
|
|
+ :disabled="formType == 3"
|
|
|
+ class="custom-input"
|
|
|
+ v-model="content.time"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ :picker-options="{ selectableRange: '01:01:00 - 23:59:59' }"
|
|
|
+ placeholder="时间"
|
|
|
+ style="width: 100px;height: 20px;">
|
|
|
+ </el-time-picker>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <el-form-item label="时间" v-if="form.sendType != 4">
|
|
|
+ <el-time-picker
|
|
|
+ :disabled="formType == 3"
|
|
|
+ class="custom-input"
|
|
|
+ v-model="content.time"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ placeholder="时间"
|
|
|
+ style="width: 100px;height: 20px;">
|
|
|
+ </el-time-picker>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <el-form-item label="官方群发" v-if="contentIndex==0 && content.type==2">
|
|
|
+ <el-switch
|
|
|
+ v-model="content.isOfficial"
|
|
|
+ active-color="#13ce66"
|
|
|
+ inactive-color="#DCDFE6"
|
|
|
+ active-value="1"
|
|
|
+ inactive-value="0">
|
|
|
+ </el-switch>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="消息类别" v-if="form.sendType != 4 && form.sendType != 5">
|
|
|
+ <el-radio-group v-model="content.type"
|
|
|
+ :disabled="formType == 3 || content.isOfficial === '1'"
|
|
|
+ @change="updateHtml(() => content.contentType = '1')">
|
|
|
+ <el-radio :label="1">普通</el-radio>
|
|
|
+ <el-radio :label="2">课程</el-radio>
|
|
|
+ <el-radio :label="3">订单</el-radio>
|
|
|
+ <el-radio :label="4">AI触达</el-radio>
|
|
|
+ <el-radio :label="5">打标签</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="课程" v-if="content.type == 2 && form.sendType != 5" required>
|
|
|
+ <el-select :disabled="formType == 3 || form.sendType == 5" v-model="content.courseId"
|
|
|
+ placeholder="请选择课程" style=" margin-right: 10px;" size="mini" remote
|
|
|
+ filterable
|
|
|
+ @change="courseChangeUpdate(content,index,contentIndex)">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in courseList"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="parseInt(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-select :disabled="formType == 3 || form.sendType == 5" v-model="content.videoId"
|
|
|
+ placeholder="请选择小节" size="mini" style=" margin-right: 10px;" remote
|
|
|
+ filterable
|
|
|
+ @change="videoIdChange(content,index,contentIndex)">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in videoList[contentIndex]"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="parseInt(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-select :disabled="formType == 3" v-model="content.courseType"
|
|
|
+ placeholder="请选择消息类型" size="mini"
|
|
|
+ style=" margin-right: 10px;" v-if="content.type != 4 ">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in sysFsSopWatchStatus"
|
|
|
+ :key="dict.dictValue"
|
|
|
+ :label="dict.dictLabel"
|
|
|
+ :value="Number(dict.dictValue)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="Ai触达" v-if="content.type == 4 ">
|
|
|
+ <el-select :disabled="formType == 3" v-model="content.aiTouch"
|
|
|
+ placeholder="请选择Ai触达类型" size="mini"
|
|
|
+ style=" margin-right: 10px;" v-if="content.type == 4 ">
|
|
|
+ <el-option label="非首次交流" value="非首次交流"></el-option>
|
|
|
+ <el-option label="首次交流1" value="首次交流1"></el-option>
|
|
|
+ <el-option label="首次交流2" value="首次交流2"></el-option>
|
|
|
+ <el-option label="交流状态1" value="交流状态1"></el-option>
|
|
|
+ <el-option label="交流状态2" value="交流状态2"></el-option>
|
|
|
+ <el-option label="交流状态3" value="交流状态3"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="添加标签" prop="addTag" v-if="content.type == 5 "
|
|
|
+ v-model="content.addTag">
|
|
|
+
|
|
|
+ <el-tag
|
|
|
+ :key="tag"
|
|
|
+ v-for="tag in content.addTag"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ @close="handleClose(contentIndex,tag,content)">
|
|
|
+ {{ tag }}
|
|
|
+ </el-tag>
|
|
|
+ <el-input
|
|
|
+ style="width:110px"
|
|
|
+ class="input-new-tag"
|
|
|
+ v-if="addTag[contentIndex].inputVisible"
|
|
|
+ v-model="addTag[contentIndex].inputValue"
|
|
|
+ ref="saveTagInput"
|
|
|
+ size="small"
|
|
|
+ @keyup.enter.native="handleInputConfirm(contentIndex,content)"
|
|
|
+ @blur="handleInputConfirm(contentIndex,content)"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <el-button v-else class="button-new-tag" size="small" style="width: 110px"
|
|
|
+ @click="showInput(contentIndex)">新增标签
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="移除标签" prop="remarkMobiles" v-if="content.type == 5 ">
|
|
|
+
|
|
|
+ <el-tag
|
|
|
+ :key="tag"
|
|
|
+ v-for="tag in content.delTag"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ @close="handleCloseDel(contentIndex,tag,content)">
|
|
|
+ {{ tag }}
|
|
|
+ </el-tag>
|
|
|
+ <el-input
|
|
|
+ style="width:110px"
|
|
|
+ class="input-new-tag"
|
|
|
+ v-if="addTag[contentIndex].delTagVisible"
|
|
|
+ v-model="addTag[contentIndex].delTagValue"
|
|
|
+ ref="saveTagInputDel"
|
|
|
+ size="small"
|
|
|
+ @keyup.enter.native="handleInputConfirmDel(contentIndex,content)"
|
|
|
+ @blur="handleInputConfirmDel(contentIndex,content)"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <el-button v-else class="button-new-tag" size="small" style="width: 110px"
|
|
|
+ @click="showInputDel(contentIndex)">新增标签
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <div v-for="(setList, setIndex) in content.setting" :key="setIndex"
|
|
|
+ style="background-color: #fdfdfd; border: 1px solid #e6e6e6; margin-bottom: 20px;"
|
|
|
+ v-if="content.type != 4 && content.type != 5">
|
|
|
+ <el-row style="padding-bottom: 20px">
|
|
|
+ <el-col :span="22">
|
|
|
+ <el-form v-if="form.sendType != 4" :model="setList" label-width="70px">
|
|
|
+ <el-form-item label="内容类别" style="margin: 2%">
|
|
|
+ <div v-if="form.sendType == 1 ">
|
|
|
+ <el-radio-group v-model="setList.contentType" :disabled="formType == 3">
|
|
|
+ <!-- <el-radio :label="item.dictValue" v-for="item in sysQwSopContentType">{{item.dictLabel}}</el-radio>-->
|
|
|
+ <el-radio
|
|
|
+ v-for="item in sysQwSopContentType"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictValue"
|
|
|
+ :disabled="item.dictValue === '1' && content.setting.some(s => s.contentType == '1') ">
|
|
|
+ {{ item.dictLabel }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="form.sendType == 2 || form.sendType == 5">
|
|
|
+ <el-radio-group v-model="setList.contentType"
|
|
|
+ :disabled="formType == 3"
|
|
|
+ @change="handleContentTypeChange(content,index,contentIndex,setIndex)">
|
|
|
+ <el-radio
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictValue"
|
|
|
+ :disabled="(content.type!=2 && item.dictValue === '9') || (content.isOfficial==1 && ['5','6','7','8','9'].includes(item.dictValue))"
|
|
|
+ v-for="item in sysQwSopAiContentType">{{ item.dictLabel }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <el-input :disabled="formType == 3" v-if="setList.contentType == 1 "
|
|
|
+ v-model="setList.value"
|
|
|
+ type="textarea" :rows="3" placeholder="内容"
|
|
|
+ style="width: 90%;margin-top: 10px;"
|
|
|
+ @keydown.native="handleKeydown($event, index, contentIndex, setIndex)"
|
|
|
+ :ref="`textarea-${index}-${contentIndex}-${setIndex}`"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 修改按钮部分 -->
|
|
|
+ <el-link
|
|
|
+ v-if="setList.contentType == 1"
|
|
|
+ type="primary"
|
|
|
+ @click="toggleSalesCall(index, contentIndex, setIndex)"
|
|
|
+ style="margin-top: 10px;"
|
|
|
+ >
|
|
|
+ {{ setList.isSalesCallAdded ? '移除#销售称呼#' : '添加#销售称呼#' }}
|
|
|
+ </el-link>
|
|
|
+
|
|
|
+ <ImageUpload :disabled="formType == 3" v-if="setList.contentType == 2 "
|
|
|
+ v-model="setList.imgUrl"
|
|
|
+ type="image" :num="1" :width="150" :height="150"/>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="setList.contentType == 3 || (setList.contentType == 9 && content.type==2 )">
|
|
|
+ <el-card class="box-card">
|
|
|
+ <el-form-item label="链接标题:" label-width="100px" required>
|
|
|
+ <el-input :disabled="formType == 3" v-model="setList.linkTitle"
|
|
|
+ placeholder="请输入链接标题"
|
|
|
+ style="width: 90%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="链接描述:" label-width="100px" required>
|
|
|
+ <el-input :disabled="formType == 3" type="textarea" :rows="3"
|
|
|
+ v-model="setList.linkDescribe"
|
|
|
+ placeholder="请输入链接描述"
|
|
|
+ style="width: 90%;margin-top: 1%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="链接封面:" label-width="100px" required>
|
|
|
+ <ImageUpload :disabled="formType == 3" v-model="setList.linkImageUrl"
|
|
|
+ type="image" :num="1"
|
|
|
+ :file-size="2" :width="150" :height="150"
|
|
|
+ style="margin-top: 1%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <div v-if="content.type != 2 " style="margin-top: 1%">
|
|
|
+ <el-form-item label="链接地址:" label-width="100px" required>
|
|
|
+ <el-input :disabled="formType == 3" v-model="setList.linkUrl"
|
|
|
+ placeholder="请输入链接地址"
|
|
|
+ style="width: 90%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div v-if="content.type == 2 ">
|
|
|
+ <el-form-item label="链接地址:" label-width="100px">
|
|
|
+ <el-tag type="warning" v-model="setList.isBindUrl = 1 ">选择的课程小节
|
|
|
+ 即为卡片链接地址
|
|
|
+ </el-tag>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="setList.contentType == 4">
|
|
|
+ <el-card class="box-card">
|
|
|
+ <el-form-item label="标题" prop="miniprogramTitle">
|
|
|
+ <el-input v-model="setList.miniprogramTitle"
|
|
|
+ placeholder="请输入小程序消息标题,最长为64字节" :rows="2"
|
|
|
+ maxlength="64" type="textarea"
|
|
|
+ @input="checkByteLength(content,setList.contentType,content.isOfficial)"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="封面" prop="miniprogramPicUrl">
|
|
|
+ <ImageUpload v-if="content.isOfficial !== '1'"
|
|
|
+ v-model="setList.miniprogramPicUrl" type="image" :num="10"
|
|
|
+ :width="150" :height="150"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="appid" prop="miniprogramAppid" v-show="false">
|
|
|
+ <el-input v-model="setList.miniprogramAppid='wx73f85f8d62769119' "
|
|
|
+ disabled/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="page路径" prop="miniprogramPage" v-show="false"
|
|
|
+ label-width="100px" style="margin-left: -30px">
|
|
|
+ <el-input v-model="setList.miniprogramPage"
|
|
|
+ placeholder="小程序消息打开后的路径" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <div v-if="setList.contentType == 5 ">
|
|
|
+
|
|
|
+ <el-form-item label="上传文件:" prop="fileUrl" label-width="100px">
|
|
|
+ <el-upload
|
|
|
+ :disabled="formType == 3"
|
|
|
+ v-model="setList.fileUrl"
|
|
|
+ class="avatar-uploader"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-success="(res, file) => handleAvatarSuccessFile(res, file, setList)"
|
|
|
+ :before-upload="beforeAvatarUploadFile">
|
|
|
+ <i class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
+ </el-upload>
|
|
|
+ <el-link v-if="setList.fileUrl" type="primary"
|
|
|
+ :href="downloadUrl(setList.fileUrl)" download>
|
|
|
+ {{ setList.fileUrl }}
|
|
|
+ </el-link>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="setList.contentType == 6 ">
|
|
|
+ <el-form-item label="上传视频:" prop="videoUrl" label-width="100px">
|
|
|
+ <el-upload
|
|
|
+ :disabled="formType == 3"
|
|
|
+ v-model="setList.videoUrl"
|
|
|
+ class="avatar-uploader"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-success="(res, file) => handleAvatarSuccessVideo(res, file, setList)"
|
|
|
+ :before-upload="beforeAvatarUploadVideo">
|
|
|
+ <i class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
+ </el-upload>
|
|
|
+ <video v-if="setList.videoUrl"
|
|
|
+ :src="setList.videoUrl"
|
|
|
+ controls style="width: 200px;height: 100px">
|
|
|
+ </video>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div v-if="setList.contentType == 7 ">
|
|
|
+ <el-input
|
|
|
+ :disabled="formType == 3"
|
|
|
+ v-model="setList.value"
|
|
|
+ type="textarea" :rows="3" maxlength="66" show-word-limit
|
|
|
+ placeholder="输入要转为语音的内容"
|
|
|
+ style="width: 90%;margin-top: 10px;"
|
|
|
+ @input="handleInputVideoText(setList.value,setList)"/>
|
|
|
+
|
|
|
+
|
|
|
+ </div>
|
|
|
+ <div v-if="setList.contentType == 8 ">
|
|
|
+ <el-button :disabled="formType == 3" type="primary"
|
|
|
+ style="margin-bottom: 1%"
|
|
|
+ @click="hanldeSelectVideoNum(content,index,contentIndex,setIndex)">
|
|
|
+ 选择视频号
|
|
|
+ </el-button>
|
|
|
+ <el-card class="box-card" v-if="setList.coverUrl">
|
|
|
+ <el-form-item label="封面标题:" label-width="100px">
|
|
|
+ <el-input :disabled="formType == 3" v-model="setList.nickname"
|
|
|
+ style="width: 90%;margin-bottom: 1%" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="头像:" label-width="100px">
|
|
|
+ <el-image
|
|
|
+ v-if="setList.avatar != null"
|
|
|
+ :src="setList.avatar"
|
|
|
+ :preview-src-list="[setList.avatar]"
|
|
|
+ :style="{ width: '50px', height: '50px' }"
|
|
|
+ ></el-image>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="封面:" label-width="100px">
|
|
|
+ <el-image
|
|
|
+ v-if="setList.coverUrl != null"
|
|
|
+ :src="setList.coverUrl"
|
|
|
+ :preview-src-list="[setList.coverUrl]"
|
|
|
+ :style="{ width: '200px', height: '200px' }"
|
|
|
+ ></el-image>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="简介:" label-width="100px">
|
|
|
+ <el-input :disabled="formType == 3" type="textarea" :rows="3"
|
|
|
+ v-model="setList.desc"
|
|
|
+ style="width: 90%;margin-top: 1%;" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="视频地址:" label-width="100px"
|
|
|
+ style="margin-top: 1%">
|
|
|
+ <el-input :disabled="formType == 3" v-model="setList.url"
|
|
|
+ style="width: 90%;" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ <div v-if="setList.contentType == 10 ">
|
|
|
+ <el-card class="box-card">
|
|
|
+ <el-form-item label="链接标题:" label-width="100px" required>
|
|
|
+ <el-input :disabled="formType == 3" v-model="setList.linkTitle"
|
|
|
+ placeholder="请输入链接标题"
|
|
|
+ style="width: 90%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="链接描述:" label-width="100px" required>
|
|
|
+ <el-input :disabled="formType == 3" type="textarea" :rows="3"
|
|
|
+ v-model="setList.linkDescribe"
|
|
|
+ placeholder="请输入链接描述"
|
|
|
+ style="width: 90%;margin-top: 1%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="链接封面:" label-width="100px" required>
|
|
|
+ <ImageUpload :disabled="formType == 3" v-model="setList.linkImageUrl"
|
|
|
+ type="image" :num="1"
|
|
|
+ :file-size="2" :width="150" :height="150"
|
|
|
+ style="margin-top: 1%;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="链接地址:" label-width="100px">
|
|
|
+ <el-tag type="warning"> 链接地址自动生成
|
|
|
+ </el-tag>
|
|
|
+ </el-form-item>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="添加短链"
|
|
|
+ v-if="content.type == 2 && setList.contentType == 1 ">
|
|
|
+ <el-tooltip content="请先根据课程选定课程小节之后再添加" effect="dark"
|
|
|
+ :disabled="!!content.videoId">
|
|
|
+ <el-switch
|
|
|
+ @change="updateHtml"
|
|
|
+ v-model="setList.isBindUrl"
|
|
|
+ :disabled="!content.videoId && formType == 3"
|
|
|
+ active-color="#13ce66"
|
|
|
+ inactive-color="#DCDFE6"
|
|
|
+ active-value="1"
|
|
|
+ inactive-value="2">
|
|
|
+ </el-switch>
|
|
|
+ </el-tooltip>
|
|
|
+
|
|
|
+ <span v-if="setList.isBindUrl == '1'"
|
|
|
+ style="margin-left: 10px; color: #13ce66">添加URL</span>
|
|
|
+ <span v-if="setList.isBindUrl == '2'"
|
|
|
+ style="margin-left: 10px; color: #b1b4ba">不加URL</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="课节过期时间"
|
|
|
+ v-if="content.type == 2 && setList.isBindUrl == '1' && setList.contentType != 2 && setList.contentType != 5 && setList.contentType != 6 && setList.contentType != 8 && setList.contentType != 9 && setList.contentType != 10 ">
|
|
|
+ <el-row>
|
|
|
+ <el-input type="number" v-model="setList.expiresDays"
|
|
|
+ style="width: 200px">
|
|
|
+ <template slot="append">天</template>
|
|
|
+ </el-input>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <span class="tip">填写0或不填时,默认为系统配置的默认时间</span>
|
|
|
+ </el-row>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ </el-form>
|
|
|
+ <el-form v-if="form.sendType == 4" :model="setList" label-width="70px">
|
|
|
+ <el-form-item label="添加客服" prop="intervalTime" style="margin: 2%">
|
|
|
+ <el-input-number
|
|
|
+ v-model="setList.intervalTime"
|
|
|
+ :min="1"
|
|
|
+ :max="1440"
|
|
|
+ style="width:100px;margin-top: 10px;"
|
|
|
+ >
|
|
|
+ </el-input-number>
|
|
|
+ <span class="tip">单位:分钟,最大1440分钟(24小时)</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容" style="margin: 2%">
|
|
|
+ <el-input
|
|
|
+ v-model="setList.value"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="内容"
|
|
|
+ style="width: 90%;margin-top: 10px;"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="交流状态" style="margin: 2%">
|
|
|
+ <el-select v-model="setList.talkType" placeholder="更改交流状态" size="mini"
|
|
|
+ style=" margin-right: 10px;" clearable>
|
|
|
+ <el-option label="非首次交流" value="非首次交流"></el-option>
|
|
|
+ <el-option label="首次交流1" value="首次交流1"></el-option>
|
|
|
+ <el-option label="首次交流2" value="首次交流2"></el-option>
|
|
|
+ <el-option label="交流状态1" value="交流状态1"></el-option>
|
|
|
+ <el-option label="交流状态2" value="交流状态2"></el-option>
|
|
|
+ <el-option label="交流状态3" value="交流状态3"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1" :offset="1">
|
|
|
+ <i class="el-icon-delete" @click="delSetList(index,contentIndex,setIndex)"
|
|
|
+ style="margin-top: 20px;"
|
|
|
+ v-if="content.setting.length>1 && (formType != 3)"></i>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <el-link type="primary" class="el-icon-plus" :underline="false"
|
|
|
+ @click='addSetList(contentIndex,item.content)'
|
|
|
+ v-if="content.type != 4 && formType != 3">添加内容
|
|
|
+ </el-link>
|
|
|
+ </el-form>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1" :offset="1">
|
|
|
+ <i class="el-icon-delete" @click="delContent(index,contentIndex)"
|
|
|
+ style="margin-top: 20px;"
|
|
|
+ v-if="item.content.length>1 && formType != 3"></i>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <el-link type="primary" class="el-icon-plus" :underline="false" @click='addContent(index)'
|
|
|
+ v-if="formType != 3 && form.sendType != 4">添加规则
|
|
|
+ </el-link>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ <div style="float: right;" v-if="formType != 3">
|
|
|
+ <el-button type="primary" @click="save" v-if="!item.voice || item.voice == 0">
|
|
|
+ 保存({{ '第' + (1 + (form.gap * index)) + '天' }})
|
|
|
+ </el-button>
|
|
|
+ <el-button type="primary" disabled v-if="item.voice == 1">语言生成中</el-button>
|
|
|
+ <el-button type="primary" @click="leave(tabIndex)" v-if="item.voice == 1">刷新状态</el-button>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-dialog :title="videoNumOptions.title" :visible.sync="videoNumOptions.open" style="width: 1500px;height: 100%"
|
|
|
+ append-to-body>
|
|
|
+ <userVideo ref="QwUserVideo" @videoResult="qwUserVideoResult"></userVideo>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog title="修改天数排序" :visible.sync="openSort" style="width: 1500px" append-to-body>
|
|
|
+ <draggable v-model="dayList" @end="onDragEndDay" style="padding: 20px">
|
|
|
+ <el-button v-for="(item, index) in dayList" :class="item.newDay != item.dayNum ? 'red':''">第{{
|
|
|
+ item.newDay
|
|
|
+ }}天(第{{ item.dayNum }}天)
|
|
|
+ </el-button>
|
|
|
+ </draggable>
|
|
|
+
|
|
|
+ <div style="float: right;">
|
|
|
+ <el-button type="primary" @click="saveSorts">保存</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog title="修改规则排序" :visible.sync="openSort2" style="width: 1500px" append-to-body>
|
|
|
+ <draggable v-model="ruleList" @end="onDragEnd" style="padding: 20px">
|
|
|
+ <el-button v-for="(item, index) in ruleList">{{ item.time }}</el-button>
|
|
|
+ </draggable>
|
|
|
+
|
|
|
+ <div style="float: right;">
|
|
|
+ <el-button @click="autoSortsRules">自动排序</el-button>
|
|
|
+ <el-button type="primary" @click="saveSortsRules">保存</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.el-button {
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.red:hover {
|
|
|
+ color: #dbdbdb !important;
|
|
|
+}
|
|
|
+
|
|
|
+.red {
|
|
|
+ background-color: #F56C6C !important;
|
|
|
+ color: #fff !important;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-input /deep/ .el-input__inner {
|
|
|
+ height: 20px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-input /deep/ .el-input__icon {
|
|
|
+ line-height: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-icon-delete {
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+/deep/ .el-badge__content.is-fixed {
|
|
|
+ top: 10px !important;
|
|
|
+ right: 0 !important;
|
|
|
+ width: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.tip {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.sortable-ghost {
|
|
|
+ background: rgb(26, 164, 255) !important;
|
|
|
+ color: #FFF !important;
|
|
|
+}
|
|
|
+</style>
|
|
|
+<script>
|
|
|
+import draggable from 'vuedraggable';
|
|
|
+import {
|
|
|
+ listSopTemp,
|
|
|
+ getSopTemp,
|
|
|
+ delSopTemp,
|
|
|
+ addSopTemp,
|
|
|
+ sortDay,
|
|
|
+ dayListFun,
|
|
|
+ updateSopTemp,
|
|
|
+ exportSopTemp,
|
|
|
+ addOrUpdateSetting,
|
|
|
+ selectRulesInfo,
|
|
|
+ delRules
|
|
|
+} from "@/api/qw/sopTemp";
|
|
|
+import {courseList, videoList} from "@/api/qw/sop";
|
|
|
+import ImageUpload from "@/views/qw/sop/ImageUpload";
|
|
|
+import userVideo from "@/views/qw/userVideo/userVideo.vue";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "updateSopTemp",
|
|
|
+ components: {ImageUpload, userVideo, draggable},
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ addTag: [{
|
|
|
+ addTag: [],
|
|
|
+ inputVisible: false,
|
|
|
+ inputValue: '',
|
|
|
+ delTag: [],
|
|
|
+ delTagVisible: false,
|
|
|
+ delTagValue: ''
|
|
|
+ }],
|
|
|
+ uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS2",
|
|
|
+ uploadUrlByVoice: process.env.VUE_APP_BASE_API + "/common/uploadOSSByHOOKVoice",
|
|
|
+ //上传语音的遮罩层
|
|
|
+ voiceLoading: false,
|
|
|
+ openSort: false,
|
|
|
+ openSort2: false,
|
|
|
+ // 遮罩层
|
|
|
+ loading: false,
|
|
|
+ loading2: false,
|
|
|
+ loading3: false,
|
|
|
+ // 导出遮罩层
|
|
|
+ exportLoading: false,
|
|
|
+ // 选中数组
|
|
|
+ dayList: [],
|
|
|
+ ruleList: [],
|
|
|
+ ids: [],
|
|
|
+ sysFsSopWatchStatus: [],
|
|
|
+ //消息内容类型 企微版
|
|
|
+ sysQwSopContentType: [],
|
|
|
+ //插件版
|
|
|
+ sysQwSopAiContentType: [],
|
|
|
+
|
|
|
+ //类别
|
|
|
+ sysQwSopSettingType: [],
|
|
|
+
|
|
|
+ courseList: [],
|
|
|
+ videoList: [],
|
|
|
+ // 非单个禁用
|
|
|
+ single: true,
|
|
|
+ // 非多个禁用
|
|
|
+ multiple: true,
|
|
|
+ defaultContentType: 1,
|
|
|
+ // 显示搜索条件
|
|
|
+ showSearch: true,
|
|
|
+ // 总条数
|
|
|
+ id: "",
|
|
|
+ total: 0,
|
|
|
+ tabIndex: null,
|
|
|
+ // sop模板表格数据
|
|
|
+ setting: [],
|
|
|
+ data: [],
|
|
|
+ // 弹出层标题
|
|
|
+ title: "",
|
|
|
+ // 是否显示弹出层
|
|
|
+ open: false,
|
|
|
+ // 状态字典
|
|
|
+ statusOptions: [],
|
|
|
+ videoNumOptions: {
|
|
|
+ title: '选择视频号',
|
|
|
+ open: false,
|
|
|
+ content: null,
|
|
|
+ contentIndex: null,
|
|
|
+ setIndex: null,
|
|
|
+ },
|
|
|
+ //1 修改 2 复制 3 查看
|
|
|
+ formType: null,
|
|
|
+ // 查询参数
|
|
|
+ form: {
|
|
|
+ name: null,
|
|
|
+ setting: null,
|
|
|
+ status: "1",
|
|
|
+ sort: 1,
|
|
|
+ companyId: null,
|
|
|
+ gap: 1,
|
|
|
+ },
|
|
|
+ // 表单校验
|
|
|
+ rules: {
|
|
|
+ name: [
|
|
|
+ {required: true, message: '名称不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ status: [
|
|
|
+ {required: true, message: '状态不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ sort: [
|
|
|
+ {required: true, message: '排序不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ gap: [
|
|
|
+ {required: true, message: '间隔天数不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getDicts("sys_qwSopAi_contentType").then(response => {
|
|
|
+ this.sysQwSopAiContentType = response.data;
|
|
|
+ });
|
|
|
+ this.getDicts("sys_fs_sop_watch_status").then(response => {
|
|
|
+ this.sysFsSopWatchStatus = response.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.getDicts("sys_qwSop_contentType").then(response => {
|
|
|
+ this.sysQwSopContentType = response.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.getDicts("sys_company_status").then(response => {
|
|
|
+ this.statusOptions = response.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.getDicts("sys_qwSop_settingType").then(response => {
|
|
|
+ this.sysQwSopSettingType = response.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ courseList().then(response => {
|
|
|
+ this.courseList = response.list;
|
|
|
+ });
|
|
|
+
|
|
|
+ const id = this.$route.params && this.$route.params.id;
|
|
|
+ this.id = id;
|
|
|
+ this.formType = this.$route.params && this.$route.params.type;
|
|
|
+ this.handleUpdate(id);
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleClose(index, tag, content) {
|
|
|
+ content.addTag.splice(content.addTag.indexOf(tag), 1);
|
|
|
+ },
|
|
|
+ showInput(index) {
|
|
|
+ this.addTag[index].inputVisible = true;
|
|
|
+ },
|
|
|
+ handleInputConfirm(index, content) {
|
|
|
+ let inputValue = this.addTag[index].inputValue;
|
|
|
+ if (inputValue) {
|
|
|
+ if (!content.hasOwnProperty('addTag')) {
|
|
|
+ this.$set(content, 'addTag', []);
|
|
|
+ }
|
|
|
+ content.addTag.push(inputValue);
|
|
|
+ }
|
|
|
+ this.addTag[index].inputVisible = false;
|
|
|
+ this.addTag[index].inputValue = '';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查字节长度
|
|
|
+ checkByteLength(content, type, isOfficial) {
|
|
|
+
|
|
|
+ if (type == 4 && isOfficial == '1')
|
|
|
+ for (let i = 0; i < content.setting.length; i++) {
|
|
|
+ const text = content.setting[i].miniprogramTitle;
|
|
|
+ const byteLength = this.getByteLength(text); // 获取当前字节数
|
|
|
+ // 如果字节数超过64,截断输入内容
|
|
|
+ if (byteLength > 64) {
|
|
|
+ this.$set(content.setting[i], 'miniprogramTitle', this.truncateTextByByteLength(text, 60));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ // 计算字符串的字节数
|
|
|
+ getByteLength(text) {
|
|
|
+ return new Blob([text]).size; // 使用 Blob 计算字节数
|
|
|
+ },
|
|
|
+
|
|
|
+ // 根据字节数截断字符串
|
|
|
+ truncateTextByByteLength(text, maxByteLength) {
|
|
|
+ let byteLength = 0;
|
|
|
+ let result = "";
|
|
|
+
|
|
|
+ for (let i = 0; i < text.length; i++) {
|
|
|
+ const char = text[i];
|
|
|
+ const charByteLength = this.getByteLength(char); // 获取当前字符的字节数
|
|
|
+
|
|
|
+ // 如果加上当前字符的字节数后不超过限制,则添加到结果中
|
|
|
+ if (byteLength + charByteLength <= maxByteLength) {
|
|
|
+ result += char;
|
|
|
+ byteLength += charByteLength;
|
|
|
+ } else {
|
|
|
+ break; // 超过限制时停止
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleCloseDel(index, tag, content) {
|
|
|
+ content.delTag.splice(content.delTag.indexOf(tag), 1);
|
|
|
+ },
|
|
|
+
|
|
|
+ showInputDel(index) {
|
|
|
+ this.addTag[index].delTagVisible = true;
|
|
|
+ },
|
|
|
+ handleInputConfirmDel(index, content) {
|
|
|
+
|
|
|
+ let delTagValue = this.addTag[index].delTagValue;
|
|
|
+
|
|
|
+ if (delTagValue) {
|
|
|
+ if (!content.hasOwnProperty('delTag')) {
|
|
|
+ this.$set(content, 'delTag', []);
|
|
|
+ }
|
|
|
+ content.delTag.push(delTagValue);
|
|
|
+
|
|
|
+ }
|
|
|
+ this.addTag[index].delTagVisible = false;
|
|
|
+ this.addTag[index].delTagValue = '';
|
|
|
+ },
|
|
|
+ saveSorts() {
|
|
|
+ let list = this.dayList.filter(e => e.dayNum != e.newDay).map(e => {
|
|
|
+ return {dayNum: e.newDay, id: e.id}
|
|
|
+ })
|
|
|
+ this.loading3 = true;
|
|
|
+ sortDay(list).then(e => {
|
|
|
+ window.location.reload();
|
|
|
+ })
|
|
|
+ },
|
|
|
+ saveSortsRules() {
|
|
|
+ this.$set(this.setting[this.tabIndex], 'content', this.ruleList);
|
|
|
+ this.openSort2 = false;
|
|
|
+ },
|
|
|
+ autoSortsRules() {
|
|
|
+ this.ruleList = this.ruleList.sort((a, b) => {
|
|
|
+ // 将 time 字段转换为 Date 对象进行比较
|
|
|
+ const timeA = new Date(`1970-01-01T${a.time}Z`);
|
|
|
+ const timeB = new Date(`1970-01-01T${b.time}Z`);
|
|
|
+
|
|
|
+ // 比较时间顺序
|
|
|
+ return timeA - timeB; // 升序排序
|
|
|
+ });
|
|
|
+ },
|
|
|
+ openUpdateDaySorts() {
|
|
|
+ dayListFun(this.id).then(response => {
|
|
|
+ response.data.forEach((item) => item.newDay = item.dayNum);
|
|
|
+ this.dayList = response.data;
|
|
|
+ if (this.dayList == null || this.dayList.length == 0) {
|
|
|
+ this.$message.error("暂无天数")
|
|
|
+ } else {
|
|
|
+ this.openSort = true;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ openUpdateSorts() {
|
|
|
+ this.ruleList = JSON.parse(JSON.stringify(this.setting[this.tabIndex].content));
|
|
|
+ if (this.ruleList == null || this.ruleList.length == 0) {
|
|
|
+ this.$message.error("暂无规则")
|
|
|
+ } else {
|
|
|
+ this.openSort2 = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onDragEndDay() {
|
|
|
+ this.dayList.forEach((item, index) => {
|
|
|
+ item.newDay = (this.form.gap * index) + 1;
|
|
|
+ })
|
|
|
+ this.$forceUpdate()
|
|
|
+ },
|
|
|
+ onDragEnd() {
|
|
|
+ // 更新排序值
|
|
|
+ // this.setting[this.tabIndex].content.forEach((item, index) => {
|
|
|
+ // item.sorts = index;
|
|
|
+ // });
|
|
|
+ },
|
|
|
+ // 切换标签保存数据
|
|
|
+ leave(index, oldIndex) {
|
|
|
+ const newData = this.setting[index]
|
|
|
+ if (newData.dayNum && newData.id) {
|
|
|
+ this.loading = true;
|
|
|
+ selectRulesInfo(newData.id).then(res => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.loading = false;
|
|
|
+ this.videoList = [];
|
|
|
+ this.addTag = [];
|
|
|
+ this.$set(this.setting, index, {
|
|
|
+ ...newData,
|
|
|
+ voice: res.data.voice,
|
|
|
+ content: res.data.list || [{type: this.defaultContentType, contentType: '1', setting: [{contentType: '1', value: ""}]}]
|
|
|
+ });
|
|
|
+
|
|
|
+ for (let j = 0; j < this.setting[index].content.length; j++) {
|
|
|
+
|
|
|
+ if (this.setting[index].content[j].addTag != null) {
|
|
|
+ this.setting[index].content[j].addTag = JSON.parse(this.setting[index].content[j].addTag)
|
|
|
+ }
|
|
|
+ if (this.setting[index].content[j].delTag != null) {
|
|
|
+ this.setting[index].content[j].delTag = JSON.parse(this.setting[index].content[j].delTag)
|
|
|
+ }
|
|
|
+ this.videoList.push([])
|
|
|
+ this.addTag.push({
|
|
|
+ addTag: [],
|
|
|
+ inputVisible: false,
|
|
|
+ inputValue: '',
|
|
|
+ delTag: [],
|
|
|
+ delTagVisible: false,
|
|
|
+ delTagValue: ''
|
|
|
+ })
|
|
|
+ if (this.setting[index].content[j].type == 2) {
|
|
|
+ if (this.setting[index].content[j].hasOwnProperty('courseId')) {
|
|
|
+ this.courseChange(this.setting[index].content[j], index, j);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ save() {
|
|
|
+ let data = this.setting[this.tabIndex];
|
|
|
+ let check = this.checkData(data);
|
|
|
+ if (!check) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (let j = 0; j < data.content.length; j++) {
|
|
|
+ if (data.content[j].type != 4 && data.content[j].type != 5) {
|
|
|
+ for (let k = 0; k < data.content[j].setting.length; k++) {
|
|
|
+ if (data.content[j].setting[k].contentType == 4 && (data.content[j].setting[k].miniprogramTitle != null || data.content[j].setting[k].miniprogramTitle != "")) {
|
|
|
+ data.content[j].setting[k].miniprogramTitle = this.truncateTextByByteLength(data.content[j].setting[k].miniprogramTitle, 60)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let index = 0;
|
|
|
+ const dataList = data.content.map(e => {
|
|
|
+ e.name = data.name;
|
|
|
+ e.tempId = this.id;
|
|
|
+ e.sorts = Number(this.tabIndex);
|
|
|
+ e.dayNum = (this.form.gap * e.sorts) + 1;
|
|
|
+ e.sorts = index++;
|
|
|
+ data.dayNum = e.dayNum;
|
|
|
+ e.contentType = e.type;
|
|
|
+ e.settingList = e.setting;
|
|
|
+ e.settingList.forEach(e => e.content = JSON.stringify(e));
|
|
|
+ if (e.addTag != null) {
|
|
|
+ e.addTag = JSON.stringify(e.addTag);
|
|
|
+ }
|
|
|
+ if (e.delTag != null) {
|
|
|
+ e.delTag = JSON.stringify(e.delTag);
|
|
|
+ }
|
|
|
+ return e;
|
|
|
+ })
|
|
|
+ data.tempId = this.id;
|
|
|
+ data.list = dataList;
|
|
|
+ this.loading = true;
|
|
|
+ addOrUpdateSetting(data).then(e => {
|
|
|
+ let content = this.setting[this.tabIndex].content;
|
|
|
+ for (let j = 0; j < content.length; j++) {
|
|
|
+ if (content[j].addTag != null) {
|
|
|
+ content[j].addTag = JSON.parse(content[j].addTag);
|
|
|
+ }
|
|
|
+ if (content[j].delTag != null) {
|
|
|
+ content[j].delTag = JSON.parse(content[j].delTag);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.loading = false;
|
|
|
+ // 使用Vue.set确保响应式更新
|
|
|
+ this.$set(this.setting, this.tabIndex, {
|
|
|
+ ...this.setting[this.tabIndex],
|
|
|
+ id: e.data.id,
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ checkData(data) {
|
|
|
+ if (this.form.sendType != 4) {
|
|
|
+
|
|
|
+ for (let j = 0; j < data.content.length; j++) {
|
|
|
+ if (data.name == null || data.name == "") {
|
|
|
+ this.$message.error("内容名称不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].time == null || data.content[j].time == "") {
|
|
|
+ this.$message.error("时间不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].type == 2) {
|
|
|
+ if (data.content[j].courseId == null || data.content[j].courseId == "") {
|
|
|
+ this.$message.error("请选择课程")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].videoId == null || data.content[j].videoId == "") {
|
|
|
+ this.$message.error("请选择课节")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].courseType == null || data.content[j].courseType === "") {
|
|
|
+ this.$message.error("请选择消息类型")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.content[j].type != 4 && data.content[j].type != 5) {
|
|
|
+ for (let k = 0; k < data.content[j].setting.length; k++) {
|
|
|
+ if (data.content[j].setting[k].contentType == 1 && (data.content[j].setting[k].value == null || data.content[j].setting[k].value == "")) {
|
|
|
+ this.$message.error("内容不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 2 && (data.content[j].setting[k].imgUrl == null || data.content[j].setting[k].imgUrl == "")) {
|
|
|
+ this.$message.error("图片不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ((data.content[j].setting[k].contentType == 3 || data.content[j].setting[k].contentType == 9 || data.content[j].setting[k].contentType == 10) && (data.content[j].setting[k].linkTitle == null || data.content[j].setting[k].linkTitle == "")) {
|
|
|
+ this.$message.error("链接标题不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ((data.content[j].setting[k].contentType == 3 || data.content[j].setting[k].contentType == 9 || data.content[j].setting[k].contentType == 10) && (data.content[j].setting[k].linkDescribe == null || data.content[j].setting[k].linkDescribe == "")) {
|
|
|
+ this.$message.error("链接描述不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ((data.content[j].setting[k].contentType == 3 || data.content[j].setting[k].contentType == 9 || data.content[j].setting[k].contentType == 10) && (data.content[j].setting[k].linkImageUrl == null || data.content[j].setting[k].linkImageUrl == "")) {
|
|
|
+ this.$message.error("链接图片不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 3 && data.content[j].setting[k].type == 1 && (data.content[j].setting[k].linkUrl == null || data.content[j].setting[k].linkUrl == "")) {
|
|
|
+ this.$message.error("链接地址不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.content[j].setting[k].contentType == 4 && (data.content[j].setting[k].miniprogramTitle == null || data.content[j].setting[k].miniprogramTitle == "")) {
|
|
|
+ this.$message.error("小程序消息标题不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 4 && data.content[j].isOfficial !== '1' && (data.content[j].setting[k].miniprogramPicUrl == null || data.content[j].setting[k].miniprogramPicUrl == "")) {
|
|
|
+ this.$message.error("小程序封面地址不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.content[j].setting[k].contentType == 5 && (data.content[j].setting[k].fileUrl == null || data.content[j].setting[k].fileUrl == "")) {
|
|
|
+ this.$message.error("文件不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 6 && (data.content[j].setting[k].videoUrl == null || data.content[j].setting[k].videoUrl == "")) {
|
|
|
+ this.$message.error("视频不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 7 && (data.content[j].setting[k].value == null || data.content[j].setting[k].value == "")) {
|
|
|
+ this.$message.error("语音文本不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (data.content[j].setting[k].contentType == 8 && (data.content[j].setting[k].url == null || data.content[j].setting[k].url == "")) {
|
|
|
+ this.$message.error("视频号信息不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (data.content[j].type == 4) {
|
|
|
+ if (data.content[j].aiTouch == null || data.content[j].aiTouch == '') {
|
|
|
+ this.$message.error("AI触达不能为空")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (let day of this.setting) {
|
|
|
+ for (let content of day.content) {
|
|
|
+ for (let set of content.setting) {
|
|
|
+ if (!set.intervalTime) {
|
|
|
+ this.$message.error("客服数量不能为空");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!set.value) {
|
|
|
+ this.$message.error("内容不能为空");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+ tabClick(obj) {
|
|
|
+
|
|
|
+ },
|
|
|
+ addSetList(contentIndex, content) {
|
|
|
+
|
|
|
+ if (this.form.sendType == 1) {
|
|
|
+ for (let i = 0; i < content.length; i++) {
|
|
|
+
|
|
|
+ if (content[i].setting.length > 9) {
|
|
|
+ return this.$message.error("因为企微接口限制,企微模板一条消息只能设置最多~9个内容!!")
|
|
|
+ } else {
|
|
|
+
|
|
|
+ // 动态生成新的设置项
|
|
|
+ const newSetting = content[i].setting.some(item => item.contentType === '1')
|
|
|
+ ? {contentType: '2', imgUrl: ''} // 如果存在 contentType = '1',添加 contentType = '2'
|
|
|
+ : {contentType: '1', value: ''}; // 如果不存在 contentType = '1',添加 contentType = '1'
|
|
|
+
|
|
|
+ // 将新设置项添加到 content[i].setting 数组中
|
|
|
+ content[i].setting.push(newSetting);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ const newSetting = {
|
|
|
+ contentType: '1',
|
|
|
+ value: '',
|
|
|
+ };
|
|
|
+ if (this.form.sendType == 4) {
|
|
|
+ newSetting.intervalTime = 5;
|
|
|
+ }
|
|
|
+ // 将新设置项添加到 content.setting 数组中
|
|
|
+ content[contentIndex].setting.push(newSetting);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+ delSetList(index, contentIndex, setIndex) {
|
|
|
+ this.setting[index].content[contentIndex].setting.splice(setIndex, 1)
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ addContent(index) {
|
|
|
+ if (this.setting[index].content.length > 0 && this.form.sendType == 1) {
|
|
|
+ return this.$message.error("因为企微接口限制,企微模板一天只能设置一条消息~")
|
|
|
+ } else {
|
|
|
+ this.setting[index].content.push({type: this.defaultContentType, contentType: 1, setting: [{contentType: '1', value: "",}]})
|
|
|
+ this.videoList.push([])
|
|
|
+ this.addTag.push({
|
|
|
+ addTag: [],
|
|
|
+ inputVisible: false,
|
|
|
+ inputValue: '',
|
|
|
+ delTag: [],
|
|
|
+ delTagVisible: false,
|
|
|
+ delTagValue: ''
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ delContent(index, contentIndex) {
|
|
|
+ this.setting[index].content.splice(contentIndex, 1)
|
|
|
+ this.videoList.splice(contentIndex, 1)
|
|
|
+ this.addTag.splice(contentIndex, 1)
|
|
|
+ },
|
|
|
+ addSetting() {
|
|
|
+ let content = [{type: this.defaultContentType, contentType: '1', setting: [{contentType: '1', value: "",}]}];
|
|
|
+ if (this.form.sendType == 4) {
|
|
|
+ content[0].setting[0].intervalTime = 5;
|
|
|
+ }
|
|
|
+ this.setting.push({
|
|
|
+ name: null,
|
|
|
+ dayNum: (this.form.gap * this.setting.length) + 1,
|
|
|
+ content
|
|
|
+ })
|
|
|
+
|
|
|
+ },
|
|
|
+ delSetting(index) {
|
|
|
+ const newData = this.setting[index]
|
|
|
+ if (newData.id && newData.dayNum) {
|
|
|
+ this.$confirm('此操作将永久删除, 是否继续?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ delRules(newData.id, newData.name, newData.dayNum).then(res => {
|
|
|
+ this.del(index);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.del(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ del(index) {
|
|
|
+ if (index == 0) {
|
|
|
+ this.tabIndex = "0";
|
|
|
+ } else {
|
|
|
+ this.tabIndex = (index - 1) + "";
|
|
|
+ }
|
|
|
+ this.setting.splice(index, 1)
|
|
|
+
|
|
|
+ },
|
|
|
+ handleClosegroupUser(list) {
|
|
|
+ const index = this.userSelectList.findIndex(t => t === list);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.userSelectList.splice(index, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ //选择视频号
|
|
|
+ hanldeSelectVideoNum(content, index, contentIndex, setIndex) {
|
|
|
+ this.videoNumOptions.content = content;
|
|
|
+ this.videoNumOptions.contentIndex = contentIndex;
|
|
|
+ this.videoNumOptions.setIndex = setIndex;
|
|
|
+ this.videoNumOptions.open = true;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ qwUserVideoResult(val) {
|
|
|
+
|
|
|
+ // 根据选中的内容,将返回的数据更新到相应的表单项
|
|
|
+ const content = this.videoNumOptions.content;
|
|
|
+ const setList = content.setting[this.videoNumOptions.setIndex];
|
|
|
+
|
|
|
+ setList.nickname = val.nickname;
|
|
|
+ setList.avatar = val.avatar;
|
|
|
+ setList.coverUrl = val.coverUrl;
|
|
|
+ setList.thumbUrl = val.thumbUrl;
|
|
|
+ setList.desc = val.desc;
|
|
|
+ setList.url = val.url;
|
|
|
+ setList.extras = val.extras;
|
|
|
+
|
|
|
+ this.videoNumOptions.open = false;
|
|
|
+
|
|
|
+ },
|
|
|
+ //首次刷新
|
|
|
+ courseChange(content, index, countIndex) {
|
|
|
+
|
|
|
+ this.courseUpdate(content, index, countIndex);
|
|
|
+ },
|
|
|
+
|
|
|
+ //修改
|
|
|
+ courseChangeUpdate(content, index, countIndex) {
|
|
|
+
|
|
|
+ this.$set(content, 'videoId', null);
|
|
|
+ // 查找选中的课程对应的 label
|
|
|
+ const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === content.courseId);
|
|
|
+ for (let i = 0; i < content.setting.length; i++) {
|
|
|
+
|
|
|
+
|
|
|
+ this.$set(content.setting[i], 'linkTitle', null);
|
|
|
+ this.$set(content.setting[i], 'linkDescribe', null);
|
|
|
+ this.$set(content.setting[i], 'linkImageUrl', null);
|
|
|
+
|
|
|
+
|
|
|
+ //如果是链接的才上
|
|
|
+ if (selectedCourse && content.type == 2 && content.courseId != null) {
|
|
|
+ //响应式直接给链接的标题/封面上值
|
|
|
+
|
|
|
+ if (content.setting[i].contentType == 3 || content.setting[i].contentType == 9) {
|
|
|
+ this.$set(content.setting[i], 'linkTitle', selectedCourse.dictLabel);
|
|
|
+ this.$set(content.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
|
|
|
+ }
|
|
|
+ if (content.setting[i].contentType == 4) {
|
|
|
+ this.$set(content.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ this.courseUpdate(content, index, countIndex);
|
|
|
+ },
|
|
|
+ handleInputVideoText(value, content) {
|
|
|
+ // 允许的字符:中文、英文(大小写)、数字和指定标点符号(,。!?)
|
|
|
+ const regex = /^[\u4e00-\u9fa5,。!?,!?]+$/;
|
|
|
+
|
|
|
+ // 删除不符合条件的字符
|
|
|
+ const filteredValue = value.split('').filter(char => regex.test(char)).join('');
|
|
|
+
|
|
|
+ this.$set(content, 'value', filteredValue);
|
|
|
+
|
|
|
+ },
|
|
|
+ courseUpdate(content, index, countIndex) {
|
|
|
+ videoList(content.courseId).then(response => {
|
|
|
+ // this.$set(this.videoList, countIndex, response.list); // 响应式设置videoList
|
|
|
+ this.videoList.splice(countIndex, 1, response.list);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ toggleSalesCall(itemIndex, contentIndex, setIndex) {
|
|
|
+ // 获取目标对象
|
|
|
+ const setItem = this.setting[itemIndex].content[contentIndex].setting[setIndex];
|
|
|
+ const salesCall = '#销售称呼#';
|
|
|
+ const refKey = `textarea-${itemIndex}-${contentIndex}-${setIndex}`;
|
|
|
+ const textarea = this.$refs[refKey][0]?.$refs?.textarea;
|
|
|
+
|
|
|
+ if (!textarea) return;
|
|
|
+
|
|
|
+ // 获取光标位置
|
|
|
+ const cursorPosition = textarea.selectionStart;
|
|
|
+
|
|
|
+ if (setItem.isSalesCallAdded) {
|
|
|
+ // 移除所有标签
|
|
|
+ setItem.value = setItem.value.replace(new RegExp(salesCall, 'g'), '');
|
|
|
+ } else {
|
|
|
+ // 插入到光标位置
|
|
|
+ setItem.value =
|
|
|
+ setItem.value.slice(0, cursorPosition) +
|
|
|
+ salesCall +
|
|
|
+ setItem.value.slice(cursorPosition);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换状态
|
|
|
+ setItem.isSalesCallAdded = !setItem.isSalesCallAdded;
|
|
|
+
|
|
|
+ // 保持光标位置
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const newCursorPos = cursorPosition + (setItem.isSalesCallAdded ? salesCall.length : 0);
|
|
|
+ textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleKeydown(event, itemIndex, contentIndex, setIndex) {
|
|
|
+
|
|
|
+ const setItem = this.setting[itemIndex].content[contentIndex].setting[setIndex];
|
|
|
+ const refKey = `textarea-${itemIndex}-${contentIndex}-${setIndex}`;
|
|
|
+ const textarea = this.$refs[refKey][0]?.$refs?.textarea;
|
|
|
+
|
|
|
+ if (!textarea) return;
|
|
|
+
|
|
|
+ const tags = ['#销售称呼#', '#客户称呼#'];
|
|
|
+ const key = event.key;
|
|
|
+ const value = setItem.value;
|
|
|
+ const cursorPosition = textarea.selectionStart;
|
|
|
+
|
|
|
+ if (key === 'Backspace' || key === 'Delete') {
|
|
|
+ tags.forEach(tag => {
|
|
|
+ let start, end;
|
|
|
+
|
|
|
+ // Backspace 处理
|
|
|
+ if (key === 'Backspace' && cursorPosition >= tag.length) {
|
|
|
+ start = cursorPosition - tag.length;
|
|
|
+ if (value.slice(start, cursorPosition) === tag) {
|
|
|
+ event.preventDefault();
|
|
|
+ setItem.value = value.slice(0, start) + value.slice(cursorPosition);
|
|
|
+ if (tag === '#销售称呼#') setItem.isSalesCallAdded = false;
|
|
|
+ this.$nextTick(() => textarea.setSelectionRange(start, start));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete 处理
|
|
|
+ if (key === 'Delete') {
|
|
|
+ end = cursorPosition + tag.length;
|
|
|
+ if (value.slice(cursorPosition, end) === tag) {
|
|
|
+ event.preventDefault();
|
|
|
+ setItem.value = value.slice(0, cursorPosition) + value.slice(end);
|
|
|
+ if (tag === '#销售称呼#') setItem.isSalesCallAdded = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleContentTypeChange(content, index, countIndex) {
|
|
|
+ //如果是链接的才上
|
|
|
+ if (content.courseId != null && content.type == 2) {
|
|
|
+ const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === content.courseId);
|
|
|
+ for (let i = 0; i < content.setting.length; i++) {
|
|
|
+ //响应式直接给链接的标题/封面上值
|
|
|
+ if (selectedCourse && content.type == 2 && content.courseId != null) {
|
|
|
+ if (content.setting[i].contentType == 3 || content.setting[i].contentType == 9) {
|
|
|
+ this.$set(content.setting[i], 'linkTitle', selectedCourse.dictLabel);
|
|
|
+ this.$set(content.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
|
|
|
+ }
|
|
|
+ if (content.setting[i].contentType == 4 && (content.isOfficial == '0' || content.isOfficial == null)) {
|
|
|
+ console.log(content.isOfficial);
|
|
|
+ this.$set(content.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (content.videoId != null && content.type == 2) {
|
|
|
+ // 查找选中的课节对应的 label
|
|
|
+ const selectedVideo = this.videoList[countIndex].find(course => parseInt(course.dictValue) === content.videoId);
|
|
|
+
|
|
|
+ for (let i = 0; i < content.setting.length; i++) {
|
|
|
+ //响应式直接给链接的描述上值
|
|
|
+ if (selectedVideo && content.type == 2 && content.videoId != null) {
|
|
|
+
|
|
|
+ if (content.setting[i].contentType == 3 || content.setting[i].contentType == 9) {
|
|
|
+ this.$set(content.setting[i], 'linkDescribe', selectedVideo.dictLabel);
|
|
|
+ }
|
|
|
+ if (content.setting[i].contentType == 4) {
|
|
|
+ this.$set(content.setting[i], 'miniprogramTitle', this.truncateTextByByteLength(selectedVideo.dictLabel, 60));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ videoIdChange(content, index, countIndex) {
|
|
|
+
|
|
|
+ //选择了课程小节则 默认绑上
|
|
|
+ let selectedVideo;
|
|
|
+ // 查找选中的课程对应的 label
|
|
|
+ if (content.videoId != null) {
|
|
|
+ selectedVideo = this.videoList[countIndex].find(course => parseInt(course.dictValue) === content.videoId);
|
|
|
+ }
|
|
|
+ for (let i = 0; i < content.setting.length; i++) {
|
|
|
+ //课程消息-文本内容
|
|
|
+ if (content.setting[i].contentType == 1 && content.type == 2) {
|
|
|
+ this.$set(content.setting[i], 'isBindUrl', '1');
|
|
|
+ }
|
|
|
+ //如果是链接的才上
|
|
|
+ if (selectedVideo && content.type == 2 && content.videoId != null) {
|
|
|
+
|
|
|
+ if (content.setting[i].contentType == 3 || content.setting[i].contentType == 9) {
|
|
|
+ this.$set(content.setting[i], 'linkDescribe', selectedVideo.dictLabel);
|
|
|
+ }
|
|
|
+ if (content.setting[i].contentType == 4) {
|
|
|
+ this.$set(content.setting[i], 'miniprogramTitle', this.truncateTextByByteLength(selectedVideo.dictLabel, 60));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ //上传文件
|
|
|
+ handleAvatarSuccessFile(res, file, content) {
|
|
|
+ if (res.code === 200) {
|
|
|
+ // 使用 $set 确保响应式更新
|
|
|
+ this.$set(content, 'fileUrl', res.url);
|
|
|
+ } else {
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ beforeAvatarUploadFile(file) {
|
|
|
+ const isLt1M = file.size / 1024 / 1024 < 10;
|
|
|
+ if (!isLt1M) {
|
|
|
+ this.$message.error('上传大小不能超过 10MB!');
|
|
|
+ }
|
|
|
+
|
|
|
+ return isLt1M;
|
|
|
+ },
|
|
|
+
|
|
|
+ //下载文件
|
|
|
+ downloadUrl(materialUrl) {
|
|
|
+ // 直接返回文件 URL
|
|
|
+ return materialUrl;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleAvatarSuccessVideo(res, file, content) {
|
|
|
+ if (res.code == 200) {
|
|
|
+ // 使用 $set 确保响应式更新
|
|
|
+ this.$set(content, 'videoUrl', res.url);
|
|
|
+ } else {
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ beforeAvatarUploadVideo(file) {
|
|
|
+ const isLt30M = file.size / 1024 / 1024 < 10;
|
|
|
+ const isMP4 = file.type === 'video/mp4';
|
|
|
+
|
|
|
+ if (!isMP4) {
|
|
|
+ this.$message.error('仅支持上传 MP4 格式的视频文件!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isLt30M) {
|
|
|
+ this.$message.error('上传大小不能超过 10MB!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleAvatarSuccessVoice(res, file, content) {
|
|
|
+ if (res.code == 200) {
|
|
|
+ // 创建 Audio 对象加载音频
|
|
|
+ const audio = new Audio(res.mp3Url);
|
|
|
+ audio.addEventListener('loadedmetadata', () => {
|
|
|
+ // 获取音频时长
|
|
|
+ this.$set(content, 'voiceDuration', Math.ceil(audio.duration));
|
|
|
+ });
|
|
|
+ // 使用 $set 确保响应式更新
|
|
|
+ this.$set(content, 'voiceUrl', res.silkUrl);
|
|
|
+ this.$set(content, 'mp3Url', res.mp3Url);
|
|
|
+ } else {
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+ this.voiceLoading = false;
|
|
|
+
|
|
|
+ },
|
|
|
+ beforeAvatarUploadVoice(file) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const isLt10M = file.size / 1024 / 1024 < 10; // 假设语音文件大小限制为10MB
|
|
|
+ const isVoiceType = ['audio/mp3', 'audio/mpeg', 'audio/wav', 'audio/x-wav'].includes(file.type);
|
|
|
+
|
|
|
+ if (!isVoiceType) {
|
|
|
+ this.$message.error('仅支持上传 MP3, WAV, X-WAV 格式的语音文件!');
|
|
|
+ return reject(false); // 不允许继续上传
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isLt10M) {
|
|
|
+ this.$message.error('上传大小不能超过 10MB!');
|
|
|
+ return reject(false); // 不允许继续上传
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用 FileReader 读取文件
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (event) => {
|
|
|
+ const audio = new Audio(event.target.result);
|
|
|
+ audio.addEventListener('loadedmetadata', () => {
|
|
|
+ // 获取时长并保存
|
|
|
+ if (Math.ceil(audio.duration) > 30) {
|
|
|
+ this.$message.error('音频时长不能超过30秒!');
|
|
|
+ this.voiceLoading = false;
|
|
|
+ return reject(false); // 不允许继续上传
|
|
|
+ }
|
|
|
+ resolve(true); // 允许上传
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ reader.onerror = () => {
|
|
|
+ this.$message.error('无法读取音频文件!请上传正确的音频文件');
|
|
|
+ reject(false); // 不允许继续上传
|
|
|
+ };
|
|
|
+
|
|
|
+ this.voiceLoading = true;
|
|
|
+ reader.readAsDataURL(file); // 开始读取文件
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ /** 查询sop模板列表 */
|
|
|
+ getList() {
|
|
|
+ this.loading = true;
|
|
|
+ listSopTemp(this.queryParams).then(response => {
|
|
|
+ this.sopTempList = response.rows;
|
|
|
+ this.total = response.total;
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ // 取消按钮
|
|
|
+ cancel() {
|
|
|
+ this.$store.dispatch("tagsView/delView", this.$route);
|
|
|
+ this.$router.replace('/qw/conversion/sopTemp')
|
|
|
+ // this.reset();
|
|
|
+
|
|
|
+ },
|
|
|
+ // 表单重置
|
|
|
+ reset() {
|
|
|
+ this.form = {
|
|
|
+ id: null,
|
|
|
+ name: null,
|
|
|
+ setting: null,
|
|
|
+ status: "0",
|
|
|
+ sort: null,
|
|
|
+ createTime: null,
|
|
|
+ createBy: null,
|
|
|
+ companyId: null
|
|
|
+ };
|
|
|
+ this.resetForm("form");
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /** 修改按钮操作 */
|
|
|
+ handleUpdate(id) {
|
|
|
+ getSopTemp(id).then(response => {
|
|
|
+ this.videoList = []
|
|
|
+ this.form = response.data;
|
|
|
+ this.setting = this.form.list || [];
|
|
|
+
|
|
|
+ if (Array.isArray(this.setting)) {
|
|
|
+ this.setting.forEach(item => {
|
|
|
+ if (item && Array.isArray(item.content)) {
|
|
|
+ item.content.forEach(content => {
|
|
|
+ if (content && Array.isArray(content.setting)) {
|
|
|
+ content.setting.forEach(setList => {
|
|
|
+ if (setList && !Object.hasOwn(setList, 'isSalesCallAdded')) {
|
|
|
+ this.$set(setList, 'isSalesCallAdded', false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.form.list.forEach(e => e.newDay = e.dayNum)
|
|
|
+ this.dayList = JSON.parse(JSON.stringify(this.form.list));
|
|
|
+ this.videoList.push([]);
|
|
|
+ this.addTag.push({
|
|
|
+ addTag: [],
|
|
|
+ inputVisible: false,
|
|
|
+ inputValue: '',
|
|
|
+ delTag: [],
|
|
|
+ delTagVisible: false,
|
|
|
+ delTagValue: ''
|
|
|
+ })
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ /** 提交按钮 */
|
|
|
+ submitForm() {
|
|
|
+ },
|
|
|
+ /** 删除按钮操作 */
|
|
|
+ handleDelete(row) {
|
|
|
+ const ids = row.id || this.ids;
|
|
|
+ this.$confirm('是否确认删除sop模板编号为"' + ids + '"的数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function () {
|
|
|
+ return delSopTemp(ids);
|
|
|
+ }).then(() => {
|
|
|
+ this.getList();
|
|
|
+ this.msgSuccess("删除成功");
|
|
|
+ }).catch(() => {
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ /** 导出按钮操作 */
|
|
|
+ handleExport() {
|
|
|
+ const queryParams = this.queryParams;
|
|
|
+ this.$confirm('是否确认导出所有sop模板数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(() => {
|
|
|
+ this.exportLoading = true;
|
|
|
+ return exportSopTemp(queryParams);
|
|
|
+ }).then(response => {
|
|
|
+ this.download(response.msg);
|
|
|
+ this.exportLoading = false;
|
|
|
+ }).catch(() => {
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ updateHtml(val) {
|
|
|
+ val || val();
|
|
|
+
|
|
|
+ },
|
|
|
+ // updateChange(val) {
|
|
|
+ // console.log(val)
|
|
|
+ // }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|