addSop.vue 40 KB

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