addSop.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  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. <div class="tag-container">
  384. <a
  385. v-for="tagItem in item.tag"
  386. class="tag-box"
  387. @click="tagSelection(tagItem)"
  388. :class="{ 'tag-selected': tagItem.isSelected }"
  389. >
  390. {{ tagItem.name }}
  391. </a>
  392. </div>
  393. </div>
  394. <pagination
  395. v-show="total>0"
  396. :total="total"
  397. :page.sync="queryTagParams.pageNum"
  398. :limit.sync="queryTagParams.pageSize"
  399. @pagination="cancelSearchTags"
  400. />
  401. <div slot="footer" class="dialog-footer">
  402. <el-button type="primary" @click="tagSubmitForm(changeTagDialog.type)">确 定</el-button>
  403. <el-button @click="tagCancel(changeTagDialog.type)">取消</el-button>
  404. </div>
  405. </el-dialog>
  406. </div>
  407. </div>
  408. </template>
  409. <script>
  410. import { addSop, courseList, updateSop } from '@/api/qw/sop'
  411. import { getQwAllUserList, listUser } from '@/api/company/companyUser'
  412. import qwUserList from '@/views/qw/user/qwUserList.vue'
  413. import companyUserList from '@/views/company/companyUser/companyUserList.vue'
  414. import ImageUpload from '@/views/qw/sop/ImageUpload'
  415. import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
  416. import sopLogsDetails from '@/views/qw/sopLogs/sopLogsList.vue'
  417. import { listTag } from '@/api/qw/tag'
  418. import { sopListWxUserGroup } from '@/api/wxUser/wxUserGroup'
  419. import { listAll as chatListAll } from '@/api/qw/groupChat'
  420. import SopTemp from '@/views/qw/sopTemp/sopTemp.vue'
  421. import { allListTagGroup } from '@/api/qw/tagGroup'
  422. import {searchTags} from "../../../api/qw/tag";
  423. import Tip from '@/components/Tip'
  424. export default {
  425. name: "addSop",
  426. components: {SopTemp, CustomerGroupDetails, qwUserList, companyUserList, ImageUpload, sopLogsDetails, Tip},
  427. data() {
  428. return {
  429. //模板查询
  430. myQwCompanyList: [],
  431. // 遮罩层
  432. loading: true,
  433. // 导出遮罩层
  434. exportLoading: false,
  435. //模板遮罩
  436. tempOpen: false,
  437. // 选中数组
  438. ids: [],
  439. courseList: [],
  440. qwGroupList: [],
  441. // videoList:[],
  442. tags: null,
  443. excludeTags: null,
  444. // 非单个禁用
  445. single: true,
  446. setting: [],
  447. //标签组
  448. tagGroupList: [],
  449. tagList: [],
  450. //标签
  451. changeTagDialog: {
  452. title: "",
  453. open: false,
  454. type: null,
  455. },
  456. //选择的标签
  457. tagsIdsChangeSelectList: null,
  458. //排除的标签
  459. outTagsIdsChangeSelectList: null,
  460. //添加的标签
  461. addTagsIdsChangeSelectList: null,
  462. //标签弹窗选择
  463. tagChange: {
  464. open: false,
  465. index: null,
  466. },
  467. queryTagParams: {
  468. pageNum: 1,
  469. pageSize: 10,
  470. total: 0,
  471. name: null,
  472. corpId: null,
  473. },
  474. // 非多个禁用
  475. multiple: true,
  476. // 显示搜索条件
  477. showSearch: true,
  478. // 总条数
  479. total: 0,
  480. // 企微sop表格数据
  481. sopList: [],
  482. // 弹出层标题
  483. title: "",
  484. // 是否显示弹出层
  485. open: false,
  486. //企业微信员工列表
  487. companyQwUserList: [],
  488. //销售员工列表
  489. companyUserLists: [],
  490. // 状态字典
  491. statusOptions: [],
  492. //企微SOP发送类型
  493. sysQwSopType: [],
  494. projectOptions: [],
  495. sopLogsDialog: {
  496. title: '',
  497. open: false,
  498. sopLogsForm: [],
  499. },
  500. // 表单参数
  501. form: {
  502. status: 1,
  503. filterMode: 1,
  504. sendType: 2,
  505. isFixed: 0,
  506. isRegister: 0,
  507. type: 2,
  508. filterType: 2,
  509. expiryTime: 4,
  510. isAutoSop: 1,
  511. autoSopTime: {autoSopType: 2, autoStartTime: '00:00', autoEndTime: '24:00', autoSopSend: 2},
  512. },
  513. userSelectList: [],
  514. qwUserIds: [],
  515. //企业微信员工
  516. listUser: {
  517. title: "",
  518. open: false
  519. },
  520. //销售员工
  521. companyUser: {
  522. title: "",
  523. open: false
  524. },
  525. //个微客户的分组
  526. wxUserGroupList: [],
  527. // 表单校验
  528. rules: {
  529. name: [{required: true, message: "名称不能为空", trigger: "submit"}],
  530. type: [{required: true, message: "不能为空", trigger: "submit"}],
  531. sendType: [{required: true, message: "不能为空", trigger: "submit"}],
  532. startTime: [{required: true, message: "开始时间不能为空", trigger: "submit"}],
  533. tempId: [{required: true, message: "模板不能为空", trigger: "submit"}],
  534. openCommentStatus:[{ required: true, message: '开启评论/弹幕不能为空', trigger: 'change' }]
  535. }
  536. };
  537. },
  538. created() {
  539. this.form.corpId = this.$route.params && this.$route.params.corpId;
  540. this.queryTagParams.corpId = this.$route.params && this.$route.params.corpId;
  541. this.getDicts("sys_company_status").then(response => {
  542. this.statusOptions = response.data;
  543. });
  544. this.getDicts("sys_qw_sop_type").then(response => {
  545. this.sysQwSopType = response.data;
  546. });
  547. this.getDicts("sys_course_project").then(response => {
  548. this.projectOptions = response.data;
  549. });
  550. listUser().then(res => {
  551. this.companyUserLists = res.rows;
  552. }
  553. );
  554. this.refreshData(this.form.corpId);
  555. courseList().then(response => {
  556. this.courseList = response.list;
  557. });
  558. //个微客户的分组
  559. sopListWxUserGroup().then(response => {
  560. this.wxUserGroupList = response.rows;
  561. });
  562. },
  563. watch: {
  564. userSelectList(newList) {
  565. this.form.qwUserIds = newList.map(item => item.id);
  566. }
  567. },
  568. methods: {
  569. //刷新部分数据
  570. refreshData(row) {
  571. getQwAllUserList(row).then(response => {
  572. this.companyQwUserList = response.data;
  573. });
  574. this.cancelSearchTags();
  575. },
  576. handleSearchTags() {
  577. searchTags(this.queryTagParams).then(response => {
  578. this.tagGroupList = response.rows;
  579. this.total = response.total;
  580. });
  581. },
  582. cancelSearchTags() {
  583. allListTagGroup(this.queryTagParams).then(response => {
  584. this.tagGroupList = response.rows;
  585. this.total = response.total;
  586. });
  587. listTag(this.queryTagParams).then(response => {
  588. this.tagList = response.rows;
  589. });
  590. },
  591. //标签的选择
  592. tagSelection(row) {
  593. row.isSelected = !row.isSelected;
  594. this.$forceUpdate();
  595. },
  596. //确定选择标签
  597. tagSubmitForm(type) {
  598. if (type == 1) {
  599. for (let i = 0; i < this.tagGroupList.length; i++) {
  600. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  601. if (this.tagGroupList[i].tag[x].isSelected === true) {
  602. if (!this.tagsIdsChangeSelectList) {
  603. this.tagsIdsChangeSelectList = [];
  604. }
  605. // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
  606. let tagExists = this.tagsIdsChangeSelectList.some(
  607. tag => tag.id === this.tagGroupList[i].tag[x].id
  608. );
  609. // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
  610. if (!tagExists) {
  611. this.tagsIdsChangeSelectList.push(this.tagGroupList[i].tag[x]);
  612. }
  613. }
  614. }
  615. }
  616. if (!this.tagsIdsChangeSelectList || this.tagsIdsChangeSelectList.length === 0) {
  617. return this.$message('请选择标签');
  618. }
  619. } else if (type == 2) {
  620. for (let i = 0; i < this.tagGroupList.length; i++) {
  621. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  622. if (this.tagGroupList[i].tag[x].isSelected === true) {
  623. if (!this.outTagsIdsChangeSelectList) {
  624. this.outTagsIdsChangeSelectList = [];
  625. }
  626. // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
  627. let tagExists = this.outTagsIdsChangeSelectList.some(
  628. tag => tag.id === this.tagGroupList[i].tag[x].id
  629. );
  630. // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
  631. if (!tagExists) {
  632. this.outTagsIdsChangeSelectList.push(this.tagGroupList[i].tag[x]);
  633. }
  634. }
  635. }
  636. }
  637. if (!this.outTagsIdsChangeSelectList || this.outTagsIdsChangeSelectList.length === 0) {
  638. return this.$message('请选择标签');
  639. }
  640. }
  641. this.changeTagDialog.open = false;
  642. },
  643. //取消选择标签
  644. tagCancel() {
  645. this.changeTagDialog.open = false;
  646. },
  647. //选择标签
  648. hangleChangeTags() {
  649. this.changeTagDialog.title = "选择标签"
  650. this.changeTagDialog.open = true;
  651. this.changeTagDialog.type = 1;
  652. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  653. const selectedTagIds = new Set(
  654. (this.tagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  655. );
  656. for (let i = 0; i < this.tagGroupList.length; i++) {
  657. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  658. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  659. }
  660. }
  661. },
  662. //选择排除标签
  663. hangleChangeOutTags() {
  664. this.changeTagDialog.title = "选择排除的标签"
  665. this.changeTagDialog.open = true;
  666. this.changeTagDialog.type = 2;
  667. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  668. const selectedTagIds = new Set(
  669. (this.outTagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  670. );
  671. for (let i = 0; i < this.tagGroupList.length; i++) {
  672. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  673. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  674. }
  675. }
  676. },
  677. //选择排除标签
  678. hangleChangeAddTags() {
  679. this.changeTagDialog.title = "选择排除的标签"
  680. this.changeTagDialog.open = true;
  681. this.changeTagDialog.type = 2;
  682. // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
  683. const selectedTagIds = new Set(
  684. (this.outTagsIdsChangeSelectList || []).map(tagItem => tagItem?.tagId)
  685. );
  686. for (let i = 0; i < this.tagGroupList.length; i++) {
  687. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  688. this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
  689. }
  690. }
  691. },
  692. //删除一些选择的标签
  693. handleCloseTags(list) {
  694. const ls = this.tagsIdsChangeSelectList.findIndex(t => t.tagId === list.tagId);
  695. if (ls !== -1) {
  696. this.tagsIdsChangeSelectList.splice(ls, 1);
  697. this.tagsIdsChangeSelectList = [...this.tagsIdsChangeSelectList];
  698. }
  699. },
  700. //删除一些排除的标签
  701. handleCloseOutTags(list) {
  702. const ls = this.outTagsIdsChangeSelectList.findIndex(t => t.tagId === list.tagId);
  703. if (ls !== -1) {
  704. this.outTagsIdsChangeSelectList.splice(ls, 1);
  705. this.outTagsIdsChangeSelectList = [...this.outTagsIdsChangeSelectList];
  706. }
  707. },
  708. //查询模板
  709. selectListSopTemp(type) {
  710. if(this.form.filterMode == 2){
  711. type = 11;
  712. }
  713. this.tempOpen = true;
  714. setTimeout(() => {
  715. this.$refs.SopTempComments.getList(type, undefined, this.form.type == 3);
  716. }, 200);
  717. },
  718. sopTemp(val) {
  719. this.form.tempId = val.id
  720. this.form.tempName = val.name
  721. this.tempOpen = false;
  722. },
  723. //选择企微员工时
  724. handlelistUser(type, sendType, selectOne) {
  725. setTimeout(() => {
  726. this.$refs.QwUserList.getDetails(this.form.corpId, type, sendType, selectOne);
  727. }, 1);
  728. this.listUser.title = "选择企微员工"
  729. this.listUser.open = true;
  730. },
  731. //切换类别时 ,清除选择的成员
  732. clearUser() {
  733. this.userSelectList = [];
  734. this.tags = null;
  735. },
  736. //选择销售员工时
  737. handleCompanyUser(type, sendType) {
  738. this.companyUser.title = "选择销售"
  739. this.companyUser.open = true;
  740. },
  741. //企业微信员工
  742. selectUserList(list) {
  743. this.listUser.open = false;
  744. list.forEach(obj => {
  745. if (!this.userSelectList.some(item => item == obj.id)) {
  746. this.userSelectList.push(obj.id);
  747. this.qwUserIds.push(obj.qwUserId);
  748. }
  749. });
  750. this.loadChatList()
  751. },
  752. //销售员工
  753. selectCompanyUserList(list) {
  754. this.companyUser.open = false;
  755. list.forEach(obj => {
  756. if (!this.userSelectList.some(item => item == obj.userId)) {
  757. this.userSelectList.push(obj.userId);
  758. }
  759. });
  760. },
  761. //选择变动时的变动
  762. handleSendTypeChange(val) {
  763. this.userSelectList = [];
  764. this.form.tempId = null;
  765. if (val == 1) {
  766. // 遍历 this.setting 数组并清空每个对象的 content 属性
  767. this.setting.forEach(item => {
  768. if (item.content.length > 9) {
  769. item.content = item.content.slice(0, 9); // 保留前 9 个元素
  770. }
  771. });
  772. }
  773. },
  774. handleClosegroupUser(list) {
  775. const index = this.userSelectList.findIndex(t => t === list);
  776. if (index !== -1) {
  777. this.userSelectList.splice(index, 1);
  778. this.qwUserIds.splice(index, 1);
  779. this.loadChatList()
  780. }
  781. },
  782. // 取消按钮
  783. cancel() {
  784. this.$store.dispatch("tagsView/delView", this.$route);
  785. this.$router.replace('/qw/conversion/sop')
  786. this.reset();
  787. },
  788. // 表单重置
  789. reset() {
  790. this.form = {
  791. id: null,
  792. name: null,
  793. status: 1,
  794. filterMode: 1,
  795. isFixed: 0,
  796. sendType: 2,
  797. type: 2,
  798. filterType: 2,
  799. expiryTime: 4,
  800. qwUserIds: null,
  801. corpId: null,
  802. setting: null,
  803. createBy: null,
  804. createTime: null,
  805. isRating: null,
  806. autoSopTime: {autoSopType: 2, autoStartTime: '00:00', autoEndTime: '24:00', autoSopSend: 2},
  807. openCommentStatus: 0,
  808. };
  809. this.resetForm("form");
  810. this.tags = null;
  811. this.excludeTags = null;
  812. },
  813. /** 重置按钮操作 */
  814. resetQuery() {
  815. this.resetForm("queryForm");
  816. this.handleQuery();
  817. },
  818. // 多选框选中数据
  819. handleSelectionChange(selection) {
  820. this.ids = selection.map(item => item.id)
  821. this.single = selection.length !== 1
  822. this.multiple = !selection.length
  823. },
  824. /** 新增按钮操作 */
  825. handleAdd() {
  826. this.reset();
  827. this.open = true;
  828. this.setting = []
  829. this.userSelectList = []
  830. this.title = "添加企微sop";
  831. },
  832. formatDateTo24HourString(date) {
  833. let year = date.getFullYear();
  834. let month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份需要加 1 并补零
  835. let day = ('0' + date.getDate()).slice(-2); // 日需要补零
  836. let hours = ('0' + date.getHours()).slice(-2); // 小时需要补零
  837. let minutes = ('0' + date.getMinutes()).slice(-2); // 分钟需要补零
  838. let seconds = ('0' + date.getSeconds()).slice(-2); // 秒需要补零
  839. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  840. },
  841. loadChatList() {
  842. chatListAll(this.qwUserIds.join(), this.form.corpId).then(e => {
  843. this.qwGroupList = e.data;
  844. })
  845. },
  846. /** 提交按钮 */
  847. submitForm() {
  848. this.$refs["form"].validate(valid => {
  849. if (valid) {
  850. if (this.form.type == 2 && this.form.filterMode == 2) {
  851. this.form.sendType = 11;
  852. if (this.form.chatIds.length <= 0) {
  853. return this.$message.error("请选择群聊")
  854. }
  855. this.form.chatId = this.form.chatIds.join();
  856. } else {
  857. if (this.userSelectList.length <= 0) {
  858. return this.$message.error("请选择员工")
  859. }
  860. if (this.tagsIdsChangeSelectList != null && this.tagsIdsChangeSelectList.length > 0) {
  861. // 确保 this.form.tags 是数组
  862. if (!this.form.tags) {
  863. this.form.tags = []; // 如果未定义,初始化
  864. } else {
  865. this.form.tags = []; // 清空已有数据
  866. }
  867. // 遍历并添加 tagId
  868. this.tagsIdsChangeSelectList.forEach(tag => {
  869. if (tag.tagId) { // 确保 tagId 存在
  870. this.form.tags.push(tag.tagId);
  871. }
  872. });
  873. this.form.tags = this.form.tags.join(",");
  874. } else {
  875. return this.$message.error("选择的标签不能为空!!请选择筛选的标签")
  876. }
  877. if (this.outTagsIdsChangeSelectList != null && this.outTagsIdsChangeSelectList.length > 0) {
  878. // 确保 this.form.tags 是数组
  879. if (!this.form.excludeTags) {
  880. this.form.excludeTags = []; // 如果未定义,初始化
  881. } else {
  882. this.form.excludeTags = []; // 清空已有数据
  883. }
  884. // 遍历并添加 tagId
  885. this.outTagsIdsChangeSelectList.forEach(tag => {
  886. if (tag.tagId) { // 确保 tagId 存在
  887. this.form.excludeTags.push(tag.tagId);
  888. }
  889. });
  890. this.form.excludeTags = this.form.excludeTags.join(",");
  891. }
  892. }
  893. this.form.qwUserIds = this.userSelectList.join(",");
  894. this.form.setting = JSON.stringify(this.setting)
  895. this.form.autoSopTime.createTime = this.formatDateTo24HourString(new Date());
  896. this.form.autoSopTime = JSON.stringify(this.form.autoSopTime)
  897. if (this.form.id != null) {
  898. updateSop(this.form).then(response => {
  899. this.msgSuccess("修改成功");
  900. this.$store.dispatch("tagsView/delView", this.$route);
  901. // this.$router.replace('/qw/conversion/sop')
  902. window.location.replace('/qw/conversion/sop')
  903. this.reset();
  904. });
  905. } else {
  906. addSop(this.form).then(response => {
  907. this.msgSuccess("新增成功");
  908. this.$store.dispatch("tagsView/delView", this.$route);
  909. // this.$router.replace('/qw/conversion/sop')
  910. window.location.replace('/qw/conversion/sop')
  911. this.reset();
  912. });
  913. }
  914. }
  915. });
  916. },
  917. }
  918. };
  919. </script>
  920. <style scoped>
  921. .custom-input /deep/ .el-input__inner {
  922. height: 20px;
  923. padding: 0 4px;
  924. text-align: center;
  925. display: block;
  926. }
  927. .custom-input /deep/ .el-input__icon {
  928. line-height: 20px;
  929. }
  930. .user-box {
  931. width: 50px; /* 盒子宽度 */
  932. height: 30px; /* 盒子高度 */
  933. padding: 5px 10px; /* 内边距 */
  934. border: 1px solid #d5d1d1; /* 边框 */
  935. margin: 3px; /* 外边距 */
  936. background-color: #f9f9f9; /* 背景颜色 */
  937. color: #333; /* 文本颜色 */
  938. font-size: 14px; /* 字体大小 */
  939. text-align: center; /* 文本居中 */
  940. }
  941. .elFormItemClass {
  942. margin: 20px 0px
  943. }
  944. .message-stayle {
  945. display: flex;
  946. justify-content: normal;
  947. align-items: center;
  948. margin-top: 10px;
  949. }
  950. .message-stayle .el-link {
  951. white-space: normal; /* 允许换行 */
  952. word-break: break-all; /* 单词中间断行 */
  953. overflow-wrap: break-word; /* 允许在单词内换行 */
  954. }
  955. .message-stayle span {
  956. word-break: break-all;
  957. }
  958. .container {
  959. position: relative; /* 使 phone div 的 absolute 定位基于这个容器 */
  960. width: 100%;
  961. height: 100%;
  962. }
  963. .phone {
  964. position: absolute; /* 定位到容器内 */
  965. top: 5%;
  966. left: 50%;
  967. transform: translateX(-50%);
  968. width: 100%;
  969. max-width: 375px;
  970. height: 100%;
  971. max-height: 90%;
  972. border: 8px solid #ccc;
  973. border-radius: 36px;
  974. box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  975. background-color: #fff;
  976. overflow: hidden;
  977. }
  978. .phone::before {
  979. content: '';
  980. position: absolute;
  981. top: 0;
  982. left: 50%;
  983. width: 60px;
  984. height: 5px;
  985. background-color: #ccc;
  986. border-radius: 10px;
  987. transform: translateX(-50%);
  988. }
  989. .chat-interface {
  990. display: flex;
  991. flex-direction: column;
  992. height: 100%;
  993. background-color: #fff;
  994. }
  995. .header {
  996. display: flex;
  997. justify-content: space-between;
  998. align-items: center;
  999. height: 50px;
  1000. padding: 0 15px;
  1001. background-color: #fff;
  1002. border-bottom: 1px solid #e0e0e0;
  1003. }
  1004. .header .back,
  1005. .header .menu {
  1006. height: 25px;
  1007. width: 25px;
  1008. }
  1009. .header .title {
  1010. font-size: 16px;
  1011. margin: auto;
  1012. }
  1013. .message-area {
  1014. flex: 1;
  1015. background-color: rgb(240, 242, 245);
  1016. padding: 10px;
  1017. overflow-y: auto;
  1018. }
  1019. .footer {
  1020. display: flex;
  1021. align-items: center;
  1022. padding: 10px;
  1023. background-color: #fff;
  1024. border-top: 1px solid #e0e0e0;
  1025. }
  1026. .footer .voice-button,
  1027. .footer .emoji-button,
  1028. .footer .add-button {
  1029. width: 25px;
  1030. height: 25px;
  1031. border: none;
  1032. cursor: pointer;
  1033. flex-shrink: 0; /* 不允许缩小 */
  1034. }
  1035. .footer .emoji-button,
  1036. .footer .add-button {
  1037. margin: 0px 5px;
  1038. }
  1039. .footer .input-box {
  1040. flex: 1;
  1041. border: 1px solid #e0e0e0;
  1042. margin-left: 5px;
  1043. }
  1044. .text-container {
  1045. max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
  1046. overflow-y: auto; /* 内容超出时显示滚动条 */
  1047. line-height: 1.5em; /* 行高设置,确保每行高度一致 */
  1048. }
  1049. .el-form-item {
  1050. margin-bottom: 30px;
  1051. }
  1052. .custom-span {
  1053. display: block; /* 确保元素是块级元素 */
  1054. height: 110px; /* 设置固定高度 */
  1055. overflow-y: auto; /* 超出高度时显示滚动条 */
  1056. word-wrap: break-word; /* 自动换行 */
  1057. word-break: break-all; /* 在必要时进行换行 */
  1058. }
  1059. .custom-span-description {
  1060. display: block; /* 确保元素是块级元素 */
  1061. height: 110px; /* 设置固定高度 */
  1062. overflow-y: auto; /* 超出高度时显示滚动条 */
  1063. word-wrap: break-word; /* 自动换行 */
  1064. word-break: break-all; /* 在必要时进行换行 */
  1065. }
  1066. .custom-span-title {
  1067. display: block; /* 确保元素是块级元素 */
  1068. height: 45px; /* 设置固定高度 */
  1069. overflow-y: auto; /* 超出高度时显示滚动条 */
  1070. word-wrap: break-word; /* 自动换行 */
  1071. word-break: break-all; /* 在必要时进行换行 */
  1072. }
  1073. /* CSS 样式 */
  1074. .tag-container {
  1075. display: flex;
  1076. flex-wrap: wrap; /* 超出宽度时自动换行 */
  1077. gap: 8px; /* 设置标签之间的间距 */
  1078. }
  1079. .name-background {
  1080. display: inline-block;
  1081. background-color: #abece6; /* 背景颜色 */
  1082. padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
  1083. border-radius: 4px; /* 可选:设置圆角 */
  1084. }
  1085. .tag-box {
  1086. padding: 8px 12px;
  1087. border: 1px solid #989797;
  1088. border-radius: 4px;
  1089. cursor: pointer;
  1090. display: inline-block;
  1091. }
  1092. .tag-selected {
  1093. background-color: #00bc98;
  1094. color: #fff;
  1095. border-color: #00bc98;
  1096. }
  1097. .el-tag + .el-tag {
  1098. margin-left: 10px;
  1099. }
  1100. .button-new-tag {
  1101. margin-left: 10px;
  1102. height: 32px;
  1103. line-height: 30px;
  1104. padding-top: 0;
  1105. padding-bottom: 0;
  1106. }
  1107. .input-new-tag {
  1108. width: 90px;
  1109. margin-left: 10px;
  1110. vertical-align: bottom;
  1111. }
  1112. .text-container {
  1113. max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
  1114. overflow-y: auto; /* 内容超出时显示滚动条 */
  1115. line-height: 1.5em; /* 行高设置,确保每行高度一致 */
  1116. }
  1117. </style>