addSop.vue 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. <template>
  2. <div class="app-container">
  3. <div style="margin: 30px;"> 添加sop任务</div>
  4. <div style="margin-top: 10px;margin-left: 50px;margin-right: 100px;margin-bottom: 60px;">
  5. <el-form ref="form" :model="form" :rules="rules" label-width="140px">
  6. <el-form-item label="规则名称" prop="name">
  7. <el-input v-model="form.name" placeholder="请输入规则名称"/>
  8. </el-form-item>
  9. <el-form-item label="类别" prop="type">
  10. <el-radio-group v-model="form.type" @change="clearUser">
  11. <!-- <el-radio-->
  12. <!-- :label="1"-->
  13. <!-- >个微-->
  14. <!-- </el-radio>-->
  15. <el-radio
  16. :label="2"
  17. >企微
  18. </el-radio>
  19. </el-radio-group>
  20. <Tip title="针对于企业微信平台" />
  21. </el-form-item>
  22. <el-form-item label="筛选方式" prop="filterMode">
  23. <el-radio-group v-model="form.filterMode">
  24. <el-radio
  25. :label="1"
  26. >标签
  27. </el-radio>
  28. <el-radio
  29. :label="2"
  30. >群聊
  31. </el-radio>
  32. </el-radio-group>
  33. <Tip :title="'标签:根据企微客户的标签筛选客户进入SOP\r\n群聊:选择企微用户所属的群聊,并且只能选择课程模板,课程模板里面第一条规则是发送到群聊,其他规则催课会发送到群里面的个人'" />
  34. </el-form-item>
  35. <el-form-item label="小转天数" prop="minConversionDay" v-if="form.filterMode == 1">
  36. <!-- <el-input class="el-input" type="" v-model="form.minConversionDay" placeholder="请输入" />-->
  37. <el-input-number v-model="form.minConversionDay" :min="1" :max="100"></el-input-number>
  38. <Tip title="第一次提醒销售,去联系客户,在【催课看板】处显示,哪些需要联系的客户" />
  39. </el-form-item>
  40. <el-form-item label="大转天数" prop="maxConversionDay" v-if="form.filterMode == 1">
  41. <!-- <el-input class="el-input" v-model="form.maxConversionDay" placeholder="请输入" />-->
  42. <el-input-number v-model="form.maxConversionDay" :min="1" :max="100"></el-input-number>
  43. <Tip title="第二次提醒销售,去联系客户,在【催课看板】处显示,哪些需要联系的客户" />
  44. </el-form-item>
  45. <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%" v-if="form.filterMode == 2">
  46. <div>
  47. <el-button
  48. size="medium"
  49. icon="el-icon-circle-plus-outline"
  50. plain
  51. @click="handlelistUser(form.type,form.sendType, true)">请选择使用员工
  52. </el-button>
  53. </div>
  54. <div>
  55. <el-tag
  56. style="margin-left: 5px"
  57. size="medium"
  58. :key="id"
  59. v-for="id in userSelectList"
  60. closable
  61. :disable-transitions="false"
  62. @close="handleClosegroupUser(id)">
  63. <span v-for="list in companyQwUserList" :key="list.qwUserId"
  64. v-if="list.id==id">{{ list.qwUserName }}</span>
  65. </el-tag>
  66. </div>
  67. <Tip title="企业微信员工账号" />
  68. </el-form-item>
  69. <el-form-item label="群聊" prop="chatIds" v-if="form.filterMode == 2">
  70. <el-select multiple filterable clearable v-model="form.chatIds">
  71. <el-option v-for="item in qwGroupList" :key="item.chatId" :label="item.name" :value="item.chatId"/>
  72. </el-select>
  73. <Tip title="选择的企业微信员工下面的群聊" />
  74. </el-form-item>
  75. <el-form-item label="客户评级" prop="isRating" style="margin-top: 2%">
  76. <el-switch
  77. v-model="form.isRating"
  78. active-color="#13ce66"
  79. inactive-color="#ff4949"
  80. :active-value="1"
  81. :inactive-value="2">
  82. </el-switch>
  83. <span v-if="form.isRating == '1'" style="margin-left: 10px;color: #13ce66">已开启</span>
  84. <span v-if="form.isRating == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
  85. <Tip title="根据客户的【看课记录】进行评级,新进客户前4天不评级,第5天开始 根据客户近7天的看课记录进行评级 ABCD级" />
  86. </el-form-item>
  87. <div v-if="form.type==2 && form.filterMode == 1">
  88. <el-form-item label="推送方式 ">
  89. <el-radio-group v-model="form.sendType" @input="handleSendTypeChange">
  90. <el-radio
  91. v-for="dict in sysQwSopType"
  92. :key="dict.dictValue"
  93. :label="parseInt(dict.dictValue)"
  94. >{{ dict.dictLabel }}
  95. </el-radio>
  96. </el-radio-group>
  97. <Tip title="选择模板类型" />
  98. </el-form-item>
  99. <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%">
  100. <div>
  101. <el-button
  102. size="medium"
  103. icon="el-icon-circle-plus-outline"
  104. plain
  105. @click="handlelistUser(form.type,form.sendType, false)">请选择使用员工
  106. </el-button>
  107. </div>
  108. <div>
  109. <el-tag
  110. style="margin-left: 5px"
  111. size="medium"
  112. :key="id"
  113. v-for="id in userSelectList"
  114. closable
  115. :disable-transitions="false"
  116. @close="handleClosegroupUser(id)">
  117. <span v-for="list in companyQwUserList" :key="list.qwUserId"
  118. v-if="list.id==id">{{ list.qwUserName }}</span>
  119. </el-tag>
  120. </div>
  121. <Tip title="选择的企业微信员工下面的群聊" />
  122. </el-form-item>
  123. <el-form-item label="标签规则" prop="filterType">
  124. <el-radio-group v-model="form.filterType">
  125. <el-radio
  126. :label="1"
  127. >含全部标签
  128. </el-radio>
  129. <el-radio
  130. :label="2"
  131. >含任意标签
  132. </el-radio>
  133. </el-radio-group>
  134. <Tip :title="'含全部标签:客户要完全一对一匹配上选择标签,ps:多一个少一个都不行 \r\n含任意标签:客户只要有一个标签匹配上即可'" />
  135. </el-form-item>
  136. <el-form-item label="选择的标签" prop="tags">
  137. <!-- <el-select v-model="tags" remote multiple placeholder="请选择" filterable style="width: 100%;">-->
  138. <!-- <el-option-->
  139. <!-- v-for="dict in tagList"-->
  140. <!-- :label="dict.name"-->
  141. <!-- :value="dict.tagId">-->
  142. <!-- </el-option>-->
  143. <!-- </el-select>-->
  144. <div @click="hangleChangeTags()"
  145. style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 390px">
  146. <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
  147. <el-tag type="success"
  148. closable
  149. :disable-transitions="false"
  150. v-for="list in this.tagsIdsChangeSelectList"
  151. :key="list.tagId"
  152. @close="handleCloseTags(list)"
  153. style="margin: 3px;"
  154. >{{ list.name }}
  155. </el-tag>
  156. </div>
  157. </div>
  158. <Tip title="选择进入SOP任务的标签" />
  159. </el-form-item>
  160. <el-form-item label="排除的标签" prop="excludeTags">
  161. <!-- <el-select v-model="excludeTags" remote multiple placeholder="请选择" filterable style="width: 100%;">-->
  162. <!-- <el-option-->
  163. <!-- v-for="dict in tagList"-->
  164. <!-- :label="dict.name"-->
  165. <!-- :value="dict.tagId">-->
  166. <!-- </el-option>-->
  167. <!-- </el-select>-->
  168. <div @click="hangleChangeOutTags()"
  169. style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 390px">
  170. <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
  171. <el-tag type="success"
  172. closable
  173. :disable-transitions="false"
  174. v-for="list in this.outTagsIdsChangeSelectList"
  175. :key="list.tagId"
  176. @close="handleCloseOutTags(list)"
  177. style="margin: 3px;"
  178. >{{ list.name }}
  179. </el-tag>
  180. </div>
  181. </div><Tip title="选择不想进入SOP的标签" />
  182. </el-form-item>
  183. </div>
  184. <div v-if="form.type==1">
  185. <el-form-item label="推送方式 ">
  186. <el-tag type="success" v-model="form.sendType=2">AI插件</el-tag>
  187. </el-form-item>
  188. <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%">
  189. <div>
  190. <el-button
  191. size="medium"
  192. icon="el-icon-circle-plus-outline"
  193. plain
  194. @click="handleCompanyUser(form.type,form.sendType)">请选择使用员工
  195. </el-button>
  196. </div>
  197. <div>
  198. <el-tag
  199. style="margin-left: 5px"
  200. size="medium"
  201. :key="userId"
  202. v-for="userId in userSelectList"
  203. closable
  204. :disable-transitions="false"
  205. @close="handleClosegroupUser(userId)">
  206. <span v-for="list in companyUserLists " :key="list.userId"
  207. v-if="list.userId==userId">{{ list.nickName }}</span>
  208. </el-tag>
  209. </div>
  210. </el-form-item>
  211. <el-form-item label="标签规则" prop="filterType">
  212. <el-radio-group v-model="form.filterType">
  213. <el-radio
  214. :label="1"
  215. >含全部分组
  216. </el-radio>
  217. <el-radio
  218. :label="2"
  219. >含任意分组
  220. </el-radio>
  221. </el-radio-group>
  222. </el-form-item>
  223. <el-form-item label="选择的分组" prop="tags">
  224. <el-select v-model="tags" remote multiple placeholder="请选择" filterable style="width: 100%;">
  225. <el-option
  226. v-for="dict in wxUserGroupList"
  227. :label="dict.groupName"
  228. :value="dict.groupId">
  229. </el-option>
  230. </el-select>
  231. </el-form-item>
  232. </div>
  233. <el-form-item label="是否固定营期" prop="isFixed" v-if="form.type != 3">
  234. <el-radio-group v-model="form.isFixed">
  235. <el-radio
  236. :label="1"
  237. >是
  238. </el-radio>
  239. <el-radio
  240. :label="0"
  241. >否
  242. </el-radio>
  243. </el-radio-group>
  244. <Tip title="如果为固定营期,不管什么时候进入SOP的客户,营期时间都为SOP任务开始时间" />
  245. </el-form-item>
  246. <el-form-item label="开始时间" prop="startTime">
  247. <el-date-picker clearable size="small"
  248. v-model="form.startTime"
  249. type="date"
  250. value-format="yyyy-MM-dd"
  251. placeholder="选择开始时间">
  252. </el-date-picker>
  253. <Tip title="SOP开始发送时间" />
  254. </el-form-item>
  255. <el-form-item label="任务过期时间" prop="expiryTime">
  256. <el-row>
  257. <el-input-number v-model="form.expiryTime" :min="1" :max="100"></el-input-number>
  258. (小时)
  259. </el-row>
  260. <Tip title="任务生成的代发送消息,如果超过此设置的时间还未发送,自动作废" />
  261. </el-form-item>
  262. <el-form-item v-if="(form.sendType==2 || form.sendType==4 || form.sendType==11) && form.type != 3 && form.isFixed == 0" label="自动添加SOP"
  263. prop="autoSopTime.autoSopType">
  264. <el-radio-group v-model="form.autoSopTime.autoSopType">
  265. <el-radio
  266. :label="1"
  267. >当天开始
  268. </el-radio>
  269. <el-radio
  270. :label="2"
  271. >次日开始
  272. </el-radio>
  273. </el-radio-group>
  274. <Tip :title="'这个选项仅作用于【新客户】进线时或【给客户打标签时】,是进入当日的营期 还是 次日的营期'" />
  275. </el-form-item>
  276. <div style="display: flex; align-items: center; flex-wrap: nowrap;">
  277. <div v-if="form.autoSopTime.autoSopType==1 && form.isFixed == 0" style="display: flex; align-items: center">
  278. <el-form-item
  279. label="起始时间"
  280. prop="autoStartTime"
  281. label-width="100px"
  282. style="margin: 2% 0;align-items: center;">
  283. <el-time-select
  284. style="width: 120px;"
  285. placeholder="起始时间"
  286. v-model="form.autoSopTime.autoStartTime"
  287. :picker-options="{
  288. start: '00:00',
  289. step: '00:15',
  290. end: '24:00'
  291. }">
  292. </el-time-select>
  293. </el-form-item>
  294. <el-form-item
  295. label="结束时间"
  296. prop="autoEndTime"
  297. label-width="100px"
  298. style="margin: 2% 0; align-items: center; ">
  299. <el-time-select
  300. style="width: 120px;"
  301. placeholder="结束时间"
  302. v-model="form.autoSopTime.autoEndTime"
  303. :picker-options="{
  304. start: '00:00',
  305. step: '00:15',
  306. end: '24:00',
  307. minTime: form.autoSopTime.autoEndTime
  308. }">
  309. </el-time-select>
  310. </el-form-item>
  311. <Tip :title="'起始时间-结束时间之内的进线客户,进入【当日营期】,时间之外的,进入【次日营期】'" />
  312. </div>
  313. </div>
  314. <!-- <el-form-item v-if="form.autoSopTime.autoSopType==1" label="过期消息是否发送" prop="autoSopSend"-->
  315. <!-- label-width="130px">-->
  316. <!-- <el-radio-group v-model="form.autoSopTime.autoSopSend">-->
  317. <!-- <el-radio-->
  318. <!-- :label="1"-->
  319. <!-- >是-->
  320. <!-- </el-radio>-->
  321. <!-- <el-radio-->
  322. <!-- :label="2"-->
  323. <!-- >否-->
  324. <!-- </el-radio>-->
  325. <!-- </el-radio-group>-->
  326. <!-- </el-form-item>-->
  327. <el-form-item label="是否只发送注册用户" prop="isRegister" v-if="form.type != 3">
  328. <el-radio-group v-model="form.isRegister">
  329. <el-radio
  330. :label="1"
  331. >是
  332. </el-radio>
  333. <el-radio
  334. :label="0"
  335. >否
  336. </el-radio>
  337. </el-radio-group>
  338. <Tip title="是否只发送在平台注册了会员的客户" />
  339. </el-form-item>
  340. <el-form-item label="模板" prop="tempId">
  341. <div @click="selectListSopTemp(form.sendType)"
  342. style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;">
  343. <el-tag v-if="form.tempId" type="success" style="margin: 3px;">
  344. {{ form.tempName }}
  345. </el-tag>
  346. <span v-else style="margin: 3px; color: #999;">请点我选择模板</span>
  347. </div>
  348. <Tip title="选择想要发送的模板规则" />
  349. </el-form-item>
  350. <el-form-item label="开启评论/弹幕" prop="openCommentStatus">
  351. <el-radio-group v-model="form.openCommentStatus">
  352. <el-radio :label="1" >开启评论</el-radio>
  353. <el-radio :label="2" >开启弹幕</el-radio>
  354. <el-radio :label="3" >关闭</el-radio>
  355. </el-radio-group>
  356. </el-form-item>
  357. </el-form>
  358. <div slot="footer" class="dialog-footer" style="display: flex;justify-content: flex-end;">
  359. <el-button type="primary" @click="submitForm">确 定</el-button>
  360. <el-button @click="cancel">取 消</el-button>
  361. </div>
  362. <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="700px" append-to-body>
  363. <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
  364. </el-dialog>
  365. <el-dialog :title="companyUser.title" :visible.sync="companyUser.open" width="700px" append-to-body>
  366. <company-user-list ref="companyUserList" @selectCompanyUserList="selectCompanyUserList"></company-user-list>
  367. </el-dialog>
  368. <el-dialog title="选择模板" :visible.sync="tempOpen" append-to-body>
  369. <sop-temp ref="SopTempComments" @sopTemp="sopTemp"></sop-temp>
  370. </el-dialog>
  371. <!-- 选择/排除标签 -->
  372. <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" width="800px" append-to-body>
  373. <div>搜索标签:
  374. <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small"
  375. style="width: 200px;margin-right: 10px"/>
  376. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags">搜索</el-button>
  377. <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
  378. </div>
  379. <div v-for="item in tagGroupList" :key="item.id">
  380. <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
  381. <span class="name-background">{{ item.name }}</span>
  382. </div>
  383. <!-- 添加外层滚动容器 -->
  384. <div class="scroll-wrapper">
  385. <div class="tag-container">
  386. <a
  387. v-for="tagItem in item.tag"
  388. class="tag-box"
  389. @click="tagSelection(tagItem)"
  390. :class="{ 'tag-selected': tagItem.isSelected }"
  391. >
  392. {{ tagItem.name }}
  393. </a>
  394. </div>
  395. </div>
  396. <!-- <div class="tag-container">-->
  397. <!-- <a-->
  398. <!-- v-for="tagItem in item.tag"-->
  399. <!-- class="tag-box"-->
  400. <!-- @click="tagSelection(tagItem)"-->
  401. <!-- :class="{ 'tag-selected': tagItem.isSelected }"-->
  402. <!-- >-->
  403. <!-- {{ tagItem.name }}-->
  404. <!-- </a>-->
  405. <!-- </div>-->
  406. </div>
  407. <pagination
  408. v-show="total>0"
  409. :total="total"
  410. :page.sync="queryTagParams.pageNum"
  411. :limit.sync="queryTagParams.pageSize"
  412. @pagination="cancelSearchTags"
  413. />
  414. <div slot="footer" class="dialog-footer">
  415. <el-button type="primary" @click="tagSubmitForm(changeTagDialog.type)">确 定</el-button>
  416. <el-button @click="tagCancel(changeTagDialog.type)">取消</el-button>
  417. </div>
  418. </el-dialog>
  419. </div>
  420. </div>
  421. </template>
  422. <script>
  423. import { addSop, courseList, updateSop } from '@/api/qw/sop'
  424. import { getQwAllUserList, listUser } from '@/api/company/companyUser'
  425. import qwUserList from '@/views/qw/user/qwUserList.vue'
  426. import companyUserList from '@/views/company/companyUser/companyUserList.vue'
  427. import ImageUpload from '@/views/qw/sop/ImageUpload'
  428. import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
  429. import sopLogsDetails from '@/views/qw/sopLogs/sopLogsList.vue'
  430. import { listTag } from '@/api/qw/tag'
  431. import { sopListWxUserGroup } from '@/api/wxUser/wxUserGroup'
  432. import { listAll as chatListAll } from '@/api/qw/groupChat'
  433. import SopTemp from '@/views/qw/sopTemp/sopTemp.vue'
  434. import { allListTagGroup } from '@/api/qw/tagGroup'
  435. import {searchTags} from "../../../api/qw/tag";
  436. import Tip from '@/components/Tip'
  437. export default {
  438. name: "addSop",
  439. components: {SopTemp, CustomerGroupDetails, qwUserList, companyUserList, ImageUpload, sopLogsDetails, Tip},
  440. data() {
  441. return {
  442. //模板查询
  443. myQwCompanyList: [],
  444. // 遮罩层
  445. loading: true,
  446. // 导出遮罩层
  447. exportLoading: false,
  448. //模板遮罩
  449. tempOpen: false,
  450. // 选中数组
  451. ids: [],
  452. courseList: [],
  453. qwGroupList: [],
  454. // videoList:[],
  455. tags: null,
  456. excludeTags: null,
  457. // 非单个禁用
  458. single: true,
  459. setting: [],
  460. //标签组
  461. tagGroupList: [],
  462. tagList: [],
  463. //标签
  464. changeTagDialog: {
  465. title: "",
  466. open: false,
  467. type: null,
  468. },
  469. //选择的标签
  470. tagsIdsChangeSelectList: null,
  471. //排除的标签
  472. outTagsIdsChangeSelectList: null,
  473. //添加的标签
  474. addTagsIdsChangeSelectList: null,
  475. //标签弹窗选择
  476. tagChange: {
  477. open: false,
  478. index: null,
  479. },
  480. queryTagParams: {
  481. pageNum: 1,
  482. pageSize: 5,
  483. total: 0,
  484. name: null,
  485. corpId: null,
  486. },
  487. // 非多个禁用
  488. multiple: true,
  489. // 显示搜索条件
  490. showSearch: true,
  491. // 总条数
  492. total: 0,
  493. // 企微sop表格数据
  494. sopList: [],
  495. // 弹出层标题
  496. title: "",
  497. // 是否显示弹出层
  498. open: false,
  499. //企业微信员工列表
  500. companyQwUserList: [],
  501. //销售员工列表
  502. companyUserLists: [],
  503. // 状态字典
  504. statusOptions: [],
  505. //企微SOP发送类型
  506. sysQwSopType: [],
  507. projectOptions: [],
  508. sopLogsDialog: {
  509. title: '',
  510. open: false,
  511. sopLogsForm: [],
  512. },
  513. // 表单参数
  514. form: {
  515. status: 1,
  516. filterMode: 1,
  517. sendType: 2,
  518. isFixed: 0,
  519. isRegister: 0,
  520. type: 2,
  521. filterType: 2,
  522. expiryTime: 4,
  523. isAutoSop: 1,
  524. autoSopTime: {autoSopType: 2, autoStartTime: '00:00', autoEndTime: '24:00', autoSopSend: 2},
  525. },
  526. userSelectList: [],
  527. qwUserIds: [],
  528. //企业微信员工
  529. listUser: {
  530. title: "",
  531. open: false
  532. },
  533. //销售员工
  534. companyUser: {
  535. title: "",
  536. open: false
  537. },
  538. //个微客户的分组
  539. wxUserGroupList: [],
  540. // 表单校验
  541. rules: {
  542. name: [{required: true, message: "名称不能为空", trigger: "submit"}],
  543. type: [{required: true, message: "不能为空", trigger: "submit"}],
  544. sendType: [{required: true, message: "不能为空", trigger: "submit"}],
  545. startTime: [{required: true, message: "开始时间不能为空", trigger: "submit"}],
  546. tempId: [{required: true, message: "模板不能为空", trigger: "submit"}],
  547. openCommentStatus:[{ required: true, message: '开启评论/弹幕不能为空', trigger: 'change' }]
  548. }
  549. };
  550. },
  551. created() {
  552. this.form.corpId = this.$route.params && this.$route.params.corpId;
  553. this.queryTagParams.corpId = this.$route.params && this.$route.params.corpId;
  554. this.getDicts("sys_company_status").then(response => {
  555. this.statusOptions = response.data;
  556. });
  557. this.getDicts("sys_qw_sop_type").then(response => {
  558. this.sysQwSopType = response.data;
  559. });
  560. this.getDicts("sys_course_project").then(response => {
  561. this.projectOptions = response.data;
  562. });
  563. listUser().then(res => {
  564. this.companyUserLists = res.rows;
  565. }
  566. );
  567. this.refreshData(this.form.corpId);
  568. courseList().then(response => {
  569. this.courseList = response.list;
  570. });
  571. //个微客户的分组
  572. sopListWxUserGroup().then(response => {
  573. this.wxUserGroupList = response.rows;
  574. });
  575. },
  576. watch: {
  577. userSelectList(newList) {
  578. this.form.qwUserIds = newList.map(item => item.id);
  579. }
  580. },
  581. methods: {
  582. //刷新部分数据
  583. refreshData(row) {
  584. getQwAllUserList(row).then(response => {
  585. this.companyQwUserList = response.data;
  586. });
  587. this.cancelSearchTags();
  588. },
  589. handleSearchTags() {
  590. if (!this.queryTagParams.name){
  591. return this.$message.error("请输入要搜索的标签")
  592. }
  593. searchTags(this.queryTagParams).then(response => {
  594. this.tagGroupList = response.rows;
  595. this.total = response.total;
  596. });
  597. },
  598. cancelSearchTags() {
  599. allListTagGroup(this.queryTagParams).then(response => {
  600. this.tagGroupList = response.rows;
  601. this.total = response.total;
  602. });
  603. listTag(this.queryTagParams).then(response => {
  604. this.tagList = response.rows;
  605. });
  606. },
  607. //标签的选择
  608. tagSelection(row) {
  609. row.isSelected = !row.isSelected;
  610. this.$forceUpdate();
  611. },
  612. //确定选择标签
  613. tagSubmitForm(type) {
  614. if (type == 1) {
  615. for (let i = 0; i < this.tagGroupList.length; i++) {
  616. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  617. if (this.tagGroupList[i].tag[x].isSelected === true) {
  618. if (!this.tagsIdsChangeSelectList) {
  619. this.tagsIdsChangeSelectList = [];
  620. }
  621. // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
  622. let tagExists = this.tagsIdsChangeSelectList.some(
  623. tag => tag.id === this.tagGroupList[i].tag[x].id
  624. );
  625. // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
  626. if (!tagExists) {
  627. this.tagsIdsChangeSelectList.push(this.tagGroupList[i].tag[x]);
  628. }
  629. }
  630. }
  631. }
  632. if (!this.tagsIdsChangeSelectList || this.tagsIdsChangeSelectList.length === 0) {
  633. return this.$message('请选择标签');
  634. }
  635. } else if (type == 2) {
  636. for (let i = 0; i < this.tagGroupList.length; i++) {
  637. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  638. if (this.tagGroupList[i].tag[x].isSelected === true) {
  639. if (!this.outTagsIdsChangeSelectList) {
  640. this.outTagsIdsChangeSelectList = [];
  641. }
  642. // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
  643. let tagExists = this.outTagsIdsChangeSelectList.some(
  644. tag => tag.id === this.tagGroupList[i].tag[x].id
  645. );
  646. // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
  647. if (!tagExists) {
  648. this.outTagsIdsChangeSelectList.push(this.tagGroupList[i].tag[x]);
  649. }
  650. }
  651. }
  652. }
  653. if (!this.outTagsIdsChangeSelectList || this.outTagsIdsChangeSelectList.length === 0) {
  654. return this.$message('请选择标签');
  655. }
  656. }
  657. this.changeTagDialog.open = false;
  658. },
  659. //取消选择标签
  660. tagCancel() {
  661. this.changeTagDialog.open = false;
  662. },
  663. //选择标签
  664. hangleChangeTags() {
  665. this.changeTagDialog.title = "选择标签"
  666. this.changeTagDialog.open = true;
  667. this.changeTagDialog.type = 1;
  668. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  669. const selectedTagIds = new Set(
  670. (this.tagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  671. );
  672. for (let i = 0; i < this.tagGroupList.length; i++) {
  673. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  674. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  675. }
  676. }
  677. },
  678. //选择排除标签
  679. hangleChangeOutTags() {
  680. this.changeTagDialog.title = "选择排除的标签"
  681. this.changeTagDialog.open = true;
  682. this.changeTagDialog.type = 2;
  683. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  684. const selectedTagIds = new Set(
  685. (this.outTagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  686. );
  687. for (let i = 0; i < this.tagGroupList.length; i++) {
  688. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  689. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  690. }
  691. }
  692. },
  693. //选择排除标签
  694. hangleChangeAddTags() {
  695. this.changeTagDialog.title = "选择排除的标签"
  696. this.changeTagDialog.open = true;
  697. this.changeTagDialog.type = 2;
  698. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  699. const selectedTagIds = new Set(
  700. (this.outTagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  701. );
  702. for (let i = 0; i < this.tagGroupList.length; i++) {
  703. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  704. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  705. }
  706. }
  707. },
  708. //删除一些选择的标签
  709. handleCloseTags(list) {
  710. const ls = this.tagsIdsChangeSelectList.findIndex(t => t.tagId === list.tagId);
  711. if (ls !== -1) {
  712. this.tagsIdsChangeSelectList.splice(ls, 1);
  713. this.tagsIdsChangeSelectList = [...this.tagsIdsChangeSelectList];
  714. }
  715. },
  716. //删除一些排除的标签
  717. handleCloseOutTags(list) {
  718. const ls = this.outTagsIdsChangeSelectList.findIndex(t => t.tagId === list.tagId);
  719. if (ls !== -1) {
  720. this.outTagsIdsChangeSelectList.splice(ls, 1);
  721. this.outTagsIdsChangeSelectList = [...this.outTagsIdsChangeSelectList];
  722. }
  723. },
  724. //查询模板
  725. selectListSopTemp(type) {
  726. if(this.form.filterMode == 2){
  727. type = 11;
  728. }
  729. this.tempOpen = true;
  730. setTimeout(() => {
  731. this.$refs.SopTempComments.getList(type, undefined, this.form.type == 3);
  732. }, 200);
  733. },
  734. sopTemp(val) {
  735. this.form.tempId = val.id
  736. this.form.tempName = val.name
  737. this.tempOpen = false;
  738. },
  739. //选择企微员工时
  740. handlelistUser(type, sendType, selectOne) {
  741. setTimeout(() => {
  742. this.$refs.QwUserList.getDetails(this.form.corpId, type, sendType, selectOne);
  743. }, 1);
  744. this.listUser.title = "选择企微员工"
  745. this.listUser.open = true;
  746. },
  747. //切换类别时 ,清除选择的成员
  748. clearUser() {
  749. this.userSelectList = [];
  750. this.tags = null;
  751. },
  752. //选择销售员工时
  753. handleCompanyUser(type, sendType) {
  754. this.companyUser.title = "选择销售"
  755. this.companyUser.open = true;
  756. },
  757. //企业微信员工
  758. selectUserList(list) {
  759. this.listUser.open = false;
  760. list.forEach(obj => {
  761. if (!this.userSelectList.some(item => item == obj.id)) {
  762. this.userSelectList.push(obj.id);
  763. this.qwUserIds.push(obj.qwUserId);
  764. }
  765. });
  766. this.loadChatList()
  767. },
  768. //销售员工
  769. selectCompanyUserList(list) {
  770. this.companyUser.open = false;
  771. list.forEach(obj => {
  772. if (!this.userSelectList.some(item => item == obj.userId)) {
  773. this.userSelectList.push(obj.userId);
  774. }
  775. });
  776. },
  777. //选择变动时的变动
  778. handleSendTypeChange(val) {
  779. this.userSelectList = [];
  780. this.form.tempId = null;
  781. if (val == 1) {
  782. // 遍历 this.setting 数组并清空每个对象的 content 属性
  783. this.setting.forEach(item => {
  784. if (item.content.length > 9) {
  785. item.content = item.content.slice(0, 9); // 保留前 9 个元素
  786. }
  787. });
  788. }
  789. },
  790. handleClosegroupUser(list) {
  791. const index = this.userSelectList.findIndex(t => t === list);
  792. if (index !== -1) {
  793. this.userSelectList.splice(index, 1);
  794. this.qwUserIds.splice(index, 1);
  795. this.loadChatList()
  796. }
  797. },
  798. // 取消按钮
  799. cancel() {
  800. this.$store.dispatch("tagsView/delView", this.$route);
  801. this.$router.replace('/qw/conversion/sop')
  802. this.reset();
  803. },
  804. // 表单重置
  805. reset() {
  806. this.form = {
  807. id: null,
  808. name: null,
  809. status: 1,
  810. filterMode: 1,
  811. isFixed: 0,
  812. sendType: 2,
  813. type: 2,
  814. filterType: 2,
  815. expiryTime: 4,
  816. qwUserIds: null,
  817. corpId: null,
  818. setting: null,
  819. createBy: null,
  820. createTime: null,
  821. isRating: null,
  822. autoSopTime: {autoSopType: 2, autoStartTime: '00:00', autoEndTime: '24:00', autoSopSend: 2},
  823. openCommentStatus: 0,
  824. };
  825. this.resetForm("form");
  826. this.tags = null;
  827. this.excludeTags = null;
  828. },
  829. /** 重置按钮操作 */
  830. resetQuery() {
  831. this.resetForm("queryForm");
  832. this.handleQuery();
  833. },
  834. // 多选框选中数据
  835. handleSelectionChange(selection) {
  836. this.ids = selection.map(item => item.id)
  837. this.single = selection.length !== 1
  838. this.multiple = !selection.length
  839. },
  840. /** 新增按钮操作 */
  841. handleAdd() {
  842. this.reset();
  843. this.open = true;
  844. this.setting = []
  845. this.userSelectList = []
  846. this.title = "添加企微sop";
  847. },
  848. formatDateTo24HourString(date) {
  849. let year = date.getFullYear();
  850. let month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份需要加 1 并补零
  851. let day = ('0' + date.getDate()).slice(-2); // 日需要补零
  852. let hours = ('0' + date.getHours()).slice(-2); // 小时需要补零
  853. let minutes = ('0' + date.getMinutes()).slice(-2); // 分钟需要补零
  854. let seconds = ('0' + date.getSeconds()).slice(-2); // 秒需要补零
  855. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  856. },
  857. loadChatList() {
  858. chatListAll(this.qwUserIds.join(), this.form.corpId).then(e => {
  859. this.qwGroupList = e.data;
  860. })
  861. },
  862. /** 提交按钮 */
  863. submitForm() {
  864. this.$refs["form"].validate(valid => {
  865. if (valid) {
  866. if (this.form.type == 2 && this.form.filterMode == 2) {
  867. this.form.sendType = 11;
  868. if (this.form.chatIds.length <= 0) {
  869. return this.$message.error("请选择群聊")
  870. }
  871. this.form.chatId = this.form.chatIds.join();
  872. } else {
  873. if (this.userSelectList.length <= 0) {
  874. return this.$message.error("请选择员工")
  875. }
  876. if (this.tagsIdsChangeSelectList != null && this.tagsIdsChangeSelectList.length > 0) {
  877. // 确保 this.form.tags 是数组
  878. if (!this.form.tags) {
  879. this.form.tags = []; // 如果未定义,初始化
  880. } else {
  881. this.form.tags = []; // 清空已有数据
  882. }
  883. // 遍历并添加 tagId
  884. this.tagsIdsChangeSelectList.forEach(tag => {
  885. if (tag.tagId) { // 确保 tagId 存在
  886. this.form.tags.push(tag.tagId);
  887. }
  888. });
  889. this.form.tags = this.form.tags.join(",");
  890. } else {
  891. return this.$message.error("选择的标签不能为空!!请选择筛选的标签")
  892. }
  893. if (this.outTagsIdsChangeSelectList != null && this.outTagsIdsChangeSelectList.length > 0) {
  894. // 确保 this.form.tags 是数组
  895. if (!this.form.excludeTags) {
  896. this.form.excludeTags = []; // 如果未定义,初始化
  897. } else {
  898. this.form.excludeTags = []; // 清空已有数据
  899. }
  900. // 遍历并添加 tagId
  901. this.outTagsIdsChangeSelectList.forEach(tag => {
  902. if (tag.tagId) { // 确保 tagId 存在
  903. this.form.excludeTags.push(tag.tagId);
  904. }
  905. });
  906. this.form.excludeTags = this.form.excludeTags.join(",");
  907. }
  908. }
  909. this.form.qwUserIds = this.userSelectList.join(",");
  910. this.form.setting = JSON.stringify(this.setting)
  911. this.form.autoSopTime.createTime = this.formatDateTo24HourString(new Date());
  912. this.form.autoSopTime = JSON.stringify(this.form.autoSopTime)
  913. if (this.form.id != null) {
  914. updateSop(this.form).then(response => {
  915. this.msgSuccess("修改成功");
  916. this.$store.dispatch("tagsView/delView", this.$route);
  917. // this.$router.replace('/qw/conversion/sop')
  918. window.location.replace('/qw/conversion/sop')
  919. this.reset();
  920. });
  921. } else {
  922. addSop(this.form).then(response => {
  923. this.msgSuccess("新增成功");
  924. this.$store.dispatch("tagsView/delView", this.$route);
  925. // this.$router.replace('/qw/conversion/sop')
  926. window.location.replace('/qw/conversion/sop')
  927. this.reset();
  928. });
  929. }
  930. }
  931. });
  932. },
  933. }
  934. };
  935. </script>
  936. <style scoped>
  937. .custom-input /deep/ .el-input__inner {
  938. height: 20px;
  939. padding: 0 4px;
  940. text-align: center;
  941. display: block;
  942. }
  943. .custom-input /deep/ .el-input__icon {
  944. line-height: 20px;
  945. }
  946. .user-box {
  947. width: 50px; /* 盒子宽度 */
  948. height: 30px; /* 盒子高度 */
  949. padding: 5px 10px; /* 内边距 */
  950. border: 1px solid #d5d1d1; /* 边框 */
  951. margin: 3px; /* 外边距 */
  952. background-color: #f9f9f9; /* 背景颜色 */
  953. color: #333; /* 文本颜色 */
  954. font-size: 14px; /* 字体大小 */
  955. text-align: center; /* 文本居中 */
  956. }
  957. .elFormItemClass {
  958. margin: 20px 0px
  959. }
  960. .message-stayle {
  961. display: flex;
  962. justify-content: normal;
  963. align-items: center;
  964. margin-top: 10px;
  965. }
  966. .message-stayle .el-link {
  967. white-space: normal; /* 允许换行 */
  968. word-break: break-all; /* 单词中间断行 */
  969. overflow-wrap: break-word; /* 允许在单词内换行 */
  970. }
  971. .message-stayle span {
  972. word-break: break-all;
  973. }
  974. .container {
  975. position: relative; /* 使 phone div 的 absolute 定位基于这个容器 */
  976. width: 100%;
  977. height: 100%;
  978. }
  979. .phone {
  980. position: absolute; /* 定位到容器内 */
  981. top: 5%;
  982. left: 50%;
  983. transform: translateX(-50%);
  984. width: 100%;
  985. max-width: 375px;
  986. height: 100%;
  987. max-height: 90%;
  988. border: 8px solid #ccc;
  989. border-radius: 36px;
  990. box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  991. background-color: #fff;
  992. overflow: hidden;
  993. }
  994. .phone::before {
  995. content: '';
  996. position: absolute;
  997. top: 0;
  998. left: 50%;
  999. width: 60px;
  1000. height: 5px;
  1001. background-color: #ccc;
  1002. border-radius: 10px;
  1003. transform: translateX(-50%);
  1004. }
  1005. .chat-interface {
  1006. display: flex;
  1007. flex-direction: column;
  1008. height: 100%;
  1009. background-color: #fff;
  1010. }
  1011. .header {
  1012. display: flex;
  1013. justify-content: space-between;
  1014. align-items: center;
  1015. height: 50px;
  1016. padding: 0 15px;
  1017. background-color: #fff;
  1018. border-bottom: 1px solid #e0e0e0;
  1019. }
  1020. .header .back,
  1021. .header .menu {
  1022. height: 25px;
  1023. width: 25px;
  1024. }
  1025. .header .title {
  1026. font-size: 16px;
  1027. margin: auto;
  1028. }
  1029. .message-area {
  1030. flex: 1;
  1031. background-color: rgb(240, 242, 245);
  1032. padding: 10px;
  1033. overflow-y: auto;
  1034. }
  1035. .footer {
  1036. display: flex;
  1037. align-items: center;
  1038. padding: 10px;
  1039. background-color: #fff;
  1040. border-top: 1px solid #e0e0e0;
  1041. }
  1042. .footer .voice-button,
  1043. .footer .emoji-button,
  1044. .footer .add-button {
  1045. width: 25px;
  1046. height: 25px;
  1047. border: none;
  1048. cursor: pointer;
  1049. flex-shrink: 0; /* 不允许缩小 */
  1050. }
  1051. .footer .emoji-button,
  1052. .footer .add-button {
  1053. margin: 0px 5px;
  1054. }
  1055. .footer .input-box {
  1056. flex: 1;
  1057. border: 1px solid #e0e0e0;
  1058. margin-left: 5px;
  1059. }
  1060. .text-container {
  1061. max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
  1062. overflow-y: auto; /* 内容超出时显示滚动条 */
  1063. line-height: 1.5em; /* 行高设置,确保每行高度一致 */
  1064. }
  1065. .el-form-item {
  1066. margin-bottom: 30px;
  1067. }
  1068. .custom-span {
  1069. display: block; /* 确保元素是块级元素 */
  1070. height: 110px; /* 设置固定高度 */
  1071. overflow-y: auto; /* 超出高度时显示滚动条 */
  1072. word-wrap: break-word; /* 自动换行 */
  1073. word-break: break-all; /* 在必要时进行换行 */
  1074. }
  1075. .custom-span-description {
  1076. display: block; /* 确保元素是块级元素 */
  1077. height: 110px; /* 设置固定高度 */
  1078. overflow-y: auto; /* 超出高度时显示滚动条 */
  1079. word-wrap: break-word; /* 自动换行 */
  1080. word-break: break-all; /* 在必要时进行换行 */
  1081. }
  1082. .custom-span-title {
  1083. display: block; /* 确保元素是块级元素 */
  1084. height: 45px; /* 设置固定高度 */
  1085. overflow-y: auto; /* 超出高度时显示滚动条 */
  1086. word-wrap: break-word; /* 自动换行 */
  1087. word-break: break-all; /* 在必要时进行换行 */
  1088. }
  1089. /* CSS 样式 */
  1090. .tag-container {
  1091. display: flex;
  1092. flex-wrap: wrap; /* 超出宽度时自动换行 */
  1093. gap: 8px; /* 设置标签之间的间距 */
  1094. }
  1095. .name-background {
  1096. display: inline-block;
  1097. background-color: #abece6; /* 背景颜色 */
  1098. padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
  1099. border-radius: 4px; /* 可选:设置圆角 */
  1100. }
  1101. .tag-box {
  1102. padding: 8px 12px;
  1103. border: 1px solid #989797;
  1104. border-radius: 4px;
  1105. cursor: pointer;
  1106. display: inline-block;
  1107. }
  1108. .tag-selected {
  1109. background-color: #00bc98;
  1110. color: #fff;
  1111. border-color: #00bc98;
  1112. }
  1113. .el-tag + .el-tag {
  1114. margin-left: 10px;
  1115. }
  1116. .button-new-tag {
  1117. margin-left: 10px;
  1118. height: 32px;
  1119. line-height: 30px;
  1120. padding-top: 0;
  1121. padding-bottom: 0;
  1122. }
  1123. .input-new-tag {
  1124. width: 90px;
  1125. margin-left: 10px;
  1126. vertical-align: bottom;
  1127. }
  1128. .text-container {
  1129. max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
  1130. overflow-y: auto; /* 内容超出时显示滚动条 */
  1131. line-height: 1.5em; /* 行高设置,确保每行高度一致 */
  1132. }
  1133. /* 新增的滚动容器样式(不影响原有样式) */
  1134. .scroll-wrapper {
  1135. max-height: 130px; /* 大约三行的高度 */
  1136. overflow-y: auto; /* 垂直滚动 */
  1137. padding-right: 5px; /* 为滚动条留出空间 */
  1138. }
  1139. /* 美化滚动条(可选) */
  1140. .scroll-wrapper::-webkit-scrollbar {
  1141. width: 6px;
  1142. }
  1143. .scroll-wrapper::-webkit-scrollbar-thumb {
  1144. background: rgba(0, 0, 0, 0.2);
  1145. border-radius: 3px;
  1146. }
  1147. </style>