index.vue 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686
  1. <template>
  2. <div >
  3. <div style="padding: 10px">
  4. <div style="border-bottom: 1px solid #e6e6e6;background-color: white; display: flex;justify-content: left;padding-top: 20px;">
  5. <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
  6. <el-form-item label="企微公司" prop="corpId">
  7. <el-select v-model="queryParams.corpId" placeholder="企微账号" size="small" @change="updateCorpId()">
  8. <el-option
  9. v-for="dict in myQwCompanyList"
  10. :key="dict.dictValue"
  11. :label="dict.dictLabel"
  12. :value="dict.dictValue"
  13. />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="名称" prop="name">
  17. <el-input
  18. v-model="queryParams.name"
  19. placeholder="请输入名称"
  20. clearable
  21. size="small"
  22. @keyup.enter.native="handleQuery"
  23. />
  24. </el-form-item>
  25. <el-form-item label="类型" prop="type">
  26. <el-select v-model="queryParams.type" placeholder="请选择联系方式类型" clearable size="small">
  27. <el-option
  28. v-for="dict in typeOptions"
  29. :key="dict.dictValue"
  30. :label="dict.dictLabel"
  31. :value="dict.dictValue"
  32. />
  33. </el-select>
  34. </el-form-item>
  35. <el-form-item label="是否免验证" prop="skipVerify">
  36. <el-select v-model="queryParams.skipVerify" placeholder="是否无需验证" clearable size="small">
  37. <el-option
  38. v-for="dict in isOptions"
  39. :key="dict.dictValue"
  40. :label="dict.dictLabel"
  41. :value="dict.dictValue"
  42. />
  43. </el-select>
  44. </el-form-item>
  45. <!-- <el-form-item label="用户" prop="userIds">
  46. <el-select v-model="queryParams.userIds" filterable placeholder="公司员工" >
  47. <el-option style="width: 300px;"
  48. v-for="dict in companyUserList"
  49. :key="dict.userId"
  50. :label="dict.nickName"
  51. :value="dict.userId">
  52. </el-option>
  53. </el-select>
  54. </el-form-item> -->
  55. <!-- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> -->
  56. <el-form-item>
  57. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  58. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  59. </el-form-item>
  60. </el-form>
  61. </div>
  62. <div style="height: 700px;width: auto; display: flex;margin-top: 10px;">
  63. <div style="background-color: white;height: 100%;width: 15%; border: 1px solid #e6e6e6; ">
  64. <div >
  65. <contactWayGroup ref="contactWayGroup" @selectGroupScreen="selectGroupScreen" @getGroupList="getGroupList" ></contactWayGroup>
  66. </div>
  67. </div>
  68. <div style="height: 100%;width: 1%">
  69. </div>
  70. <div style="background-color: white;height: 100%;width: 85%;border: 1px solid #e6e6e6; ">
  71. <el-row :gutter="10" class="mb8" style="margin-top: 10px;margin: 15px;">
  72. <el-col :span="1.5">
  73. <el-button
  74. type="primary"
  75. plain
  76. icon="el-icon-plus"
  77. size="mini"
  78. @click="handleAdd"
  79. v-hasPermi="['qw:contactWay:add']"
  80. >新增</el-button>
  81. </el-col>
  82. <el-col :span="1.5">
  83. <el-button
  84. type="warning"
  85. plain
  86. icon="el-icon-download"
  87. size="mini"
  88. :loading="exportLoading"
  89. @click="handleExport"
  90. v-hasPermi="['qw:contactWay:export']"
  91. >导出</el-button>
  92. </el-col>
  93. <el-col :span="1.5">
  94. <el-button
  95. type="primary"
  96. plain
  97. size="mini"
  98. @click="sync"
  99. v-hasPermi="['qw:contactWay:add']"
  100. >同步</el-button>
  101. </el-col>
  102. </el-row>
  103. <div style=" height: calc(100% - 40px); overflow-y: auto;">
  104. <el-table v-loading="loading" :data="contactWayList" @selection-change="handleSelectionChange" border>
  105. <el-table-column label="id" align="center" prop="id" />
  106. <el-table-column label="名称" align="center" prop="name" />
  107. <el-table-column label="二维码" align="center" prop="qrCode" width="150px" >
  108. <template slot-scope="scope">
  109. <el-popover
  110. placement="right"
  111. title=""
  112. trigger="hover">
  113. <img slot="reference" :src="scope.row.qrCode" width="100px">
  114. <img :src="scope.row.qrCode" style="max-width: 350px;">
  115. </el-popover>
  116. </template>
  117. </el-table-column>
  118. <el-table-column label="类型" align="center" prop="type">
  119. <template slot-scope="scope">
  120. <dict-tag :options="typeOptions" :value="scope.row.type"/>
  121. </template>
  122. </el-table-column>
  123. <el-table-column label="备注" align="center" prop="remark" />
  124. <el-table-column label="是否免验证" align="center" prop="skipVerify">
  125. <template slot-scope="scope">
  126. <dict-tag :options="isOptions" :value="scope.row.skipVerify"/>
  127. </template>
  128. </el-table-column>
  129. <el-table-column label="state参数" align="center" prop="state" />
  130. <el-table-column label="用户" align="center" prop="userIds" width="200px">
  131. <template slot-scope="scope">
  132. <div v-for="i in JSON.parse(scope.row.userIds)" :key="i" style="display: inline;">
  133. <el-tag type="success" v-for="ii in companyUserList" :key="ii.id" style="margin: 3px;" v-if="ii.qwUserId==i">{{ii.qwUserName}}</el-tag>
  134. </div>
  135. </template>
  136. </el-table-column>
  137. <el-table-column label="添加人数" align="center" prop="addNum" />
  138. <el-table-column label="删除人数" align="center" prop="deleteNum" />
  139. <el-table-column label="净人数" align="center" prop="num" />
  140. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="170px">
  141. <template slot-scope="scope">
  142. <el-button
  143. size="mini"
  144. type="text"
  145. icon="el-icon-edit"
  146. @click="handleUpdate(scope.row)"
  147. v-hasPermi="['qw:contactWay:edit']"
  148. >修改</el-button>
  149. <el-button
  150. size="mini"
  151. type="text"
  152. @click="handledetails(scope.row)"
  153. >数据统计
  154. </el-button>
  155. <el-button
  156. size="mini"
  157. type="text"
  158. icon="el-icon-delete"
  159. @click="handleDelete(scope.row)"
  160. v-hasPermi="['qw:contactWay:remove']"
  161. >删除</el-button>
  162. </template>
  163. </el-table-column>
  164. </el-table>
  165. <pagination style="margin: 10px;"
  166. v-show="total>0"
  167. :total="total"
  168. :page.sync="queryParams.pageNum"
  169. :limit.sync="queryParams.pageSize"
  170. @pagination="getList"
  171. />
  172. </div>
  173. </div>
  174. </div>
  175. <!-- 添加或修改企微活码对话框 -->
  176. <el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
  177. <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  178. <el-form-item label="名称" prop="name">
  179. <el-input v-model="form.name" placeholder="请输入名称" />
  180. </el-form-item>
  181. <el-form-item label="客服类型" prop="userType" >
  182. <el-radio-group v-model="form.userType">
  183. <el-radio :key="1":label="1" >全天在线</el-radio>
  184. <el-radio :key="2":label="2" >自动上下线</el-radio>
  185. </el-radio-group>
  186. </el-form-item>
  187. <el-form-item label="" prop="userTimeJson" v-if="form.userType==2">
  188. <div v-for="(item, index) in userTimeJson" >
  189. <el-row>
  190. <el-col :span="22">
  191. <div style="background-color: #fbfbfb;padding: 15px; border: 1px solid #e6e6e6; margin-bottom: 20px;">
  192. <el-form :model="item" label-width="80px">
  193. <el-form-item label="员工选择">
  194. <div>
  195. <el-button
  196. size="medium"
  197. icon="el-icon-circle-plus-outline"
  198. plain
  199. @click="handleListUserForTimeSlot(index)">请选择使用员工
  200. </el-button>
  201. </div>
  202. <div style="margin-top: 10px;">
  203. <el-tag
  204. style="margin-left: 5px; margin-top: 5px;"
  205. size="medium"
  206. :key="user.id"
  207. v-for="user in item.userList || []"
  208. closable
  209. :disable-transitions="false"
  210. @close="handleCloseTimeSlotUser(index, user)">
  211. {{ user.qwUserName }}
  212. </el-tag>
  213. </div>
  214. </el-form-item>
  215. <el-form-item label="工作周期" prop="week" style="height: 50px;" >
  216. <el-select v-model="item.week" remote multiple placeholder="请选择" filterable style="width: 100%;">
  217. <el-option
  218. v-for="dict in weekOptions"
  219. :key="dict.value"
  220. :label="dict.label"
  221. :value="dict.value">
  222. </el-option>
  223. </el-select>
  224. </el-form-item>
  225. <el-form-item label="上线时间" style="height: 50px;">
  226. <el-time-select style="margin-right: 20px; width: 150px;"
  227. placeholder="起始时间"
  228. v-model="item.startTime"
  229. :picker-options="{
  230. start: '00:00',
  231. step: '00:15',
  232. end: '24:00'
  233. }">
  234. </el-time-select>
  235. <el-time-select style="width: 150px;"
  236. placeholder="结束时间"
  237. v-model="item.endTime"
  238. :picker-options="{
  239. start: '00:00',
  240. step: '00:15',
  241. end: '24:00',
  242. minTime: item.startTime
  243. }">
  244. </el-time-select>
  245. </el-form-item>
  246. </el-form>
  247. </div>
  248. </el-col>
  249. <el-col :span="1" :offset="1">
  250. <i class="el-icon-delete-solid" @click="delUserTime(index)" style="margin-top: 165px;" v-if="userTimeJson.length>1"></i>
  251. </el-col>
  252. </el-row>
  253. </div>
  254. <el-link type="primary" class="el-icon-plus" :underline="false" @click='addUserTime()'>添加其他工作周期</el-link>
  255. </el-form-item>
  256. <el-form-item label="" v-if="form.userType==1">
  257. <div>
  258. <el-button
  259. size="medium"
  260. icon="el-icon-circle-plus-outline"
  261. plain
  262. @click="handleListUser(form.type,form.sendType, true)">请选择使用员工
  263. </el-button>
  264. </div>
  265. <div>
  266. <el-tag
  267. style="margin-left: 5px"
  268. size="medium"
  269. :key="user.id"
  270. v-for="user in userSelectList"
  271. closable
  272. :disable-transitions="false"
  273. @close="handleCloseGroupUser(user)">
  274. {{ user.qwUserName }}
  275. </el-tag>
  276. </div>
  277. </el-form-item>
  278. <el-form-item label="员工添加上限"v-if="form.userType==1" prop="isUserLimit">
  279. <el-switch
  280. v-model="form.isUserLimit"
  281. :active-value="1"
  282. :inactive-value="0"
  283. >
  284. </el-switch>
  285. </el-form-item>
  286. <el-form-item label="" v-if="form.isUserLimit==1&&form.userType==1">
  287. <el-table :data="userLimitJson" style="border: 1px solid #e6e6e6;width: 50%;">
  288. <el-table-column label="名称" align="center" prop="userId" >
  289. <template slot-scope="scope">
  290. <div v-for="(companyUser, index) in companyUserList" :key="index">
  291. <span v-if="companyUser.qwUserId==scope.row.userId">{{companyUser.qwUserName}}</span>
  292. </div>
  293. </template>
  294. </el-table-column>
  295. <el-table-column label="数量" align="center" prop="limitCount" >
  296. <template slot-scope="scope">
  297. <div>
  298. <el-input-number v-model="scope.row.limitCount" size="mini" :min="0" ></el-input-number>
  299. </div>
  300. </template>
  301. </el-table-column>
  302. </el-table>
  303. </el-form-item>
  304. <el-form-item label="备用员工" prop="spareUserIds" >
  305. <el-select v-model="spareUserIds" remote multiple placeholder="员工" filterable style="width: 800px;">
  306. <el-option
  307. v-for="dict in companyUserList"
  308. :key="dict.qwUserId"
  309. :label="dict.qwUserName"
  310. :value="dict.qwUserId">
  311. </el-option>
  312. </el-select>
  313. </el-form-item>
  314. <el-form-item label="分组" prop="groupId">
  315. <el-select v-model="form.groupId" placeholder="分组">
  316. <el-option
  317. v-for="dict in groupList"
  318. :label="dict.groupName"
  319. :value="parseInt(dict.id)"
  320. ></el-option>
  321. </el-select>
  322. </el-form-item>
  323. <el-form-item label="信息流" prop="informationId">
  324. <el-select v-model="form.informationId" placeholder="分组">
  325. <el-option
  326. v-for="dict in informationList"
  327. :label="dict.dictLabel"
  328. :value="parseInt(dict.dictValue)"
  329. ></el-option>
  330. </el-select>
  331. </el-form-item>
  332. <el-form-item label="免验证" prop="skipVerify">
  333. <el-switch
  334. v-model="form.skipVerify"
  335. :active-value="1"
  336. :inactive-value="0"
  337. >
  338. </el-switch>
  339. </el-form-item>
  340. <el-form-item label="备注" prop="isRemark">
  341. <el-radio-group v-model="form.isRemark">
  342. <el-switch
  343. v-model="form.isRemark"
  344. :active-value="1"
  345. :inactive-value="0"
  346. >
  347. </el-switch>
  348. </el-radio-group>
  349. </el-form-item>
  350. <el-form-item label="" v-if="form.isRemark==1" prop="remarkStatus">
  351. <el-radio-group v-model="form.remarkStatus" >
  352. <el-radio :label="1">昵称后</el-radio>
  353. <el-radio :label="2">昵称前</el-radio>
  354. </el-radio-group>
  355. </el-form-item>
  356. <el-form-item label="" prop="remark" v-if="form.isRemark==1">
  357. <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
  358. </el-form-item>
  359. <el-form-item label="添加描述" prop="isDescription">
  360. <el-switch
  361. v-model="form.isDescription"
  362. :active-value="1"
  363. :inactive-value="0"
  364. >
  365. </el-switch>
  366. </el-form-item>
  367. <el-form-item label="" prop="description" v-if="form.isDescription==1">
  368. <el-input v-model="form.description" type="textarea" placeholder="请输入描述" />
  369. </el-form-item>
  370. <el-form-item label="开启欢迎语屏蔽" prop="isCloseWelcome">
  371. <el-switch
  372. v-model="form.isCloseWelcome"
  373. :active-value="1"
  374. :inactive-value="0"
  375. >
  376. </el-switch>
  377. </el-form-item>
  378. <el-form-item label="欢迎语屏蔽" prop="closeWelcomeWord" v-if="form.isCloseWelcome==1">
  379. <el-tag
  380. v-for="tag in closeWelcomeWord"
  381. closable
  382. :disable-transitions="false"
  383. @close="handleCloseWord(tag)">
  384. {{tag}}
  385. </el-tag>
  386. <el-input
  387. style="width:110px"
  388. class="input-new-tag"
  389. v-if="inputVisible"
  390. v-model="inputValue"
  391. ref="saveTagInput"
  392. size="small"
  393. @keyup.enter.native="handleInputConfirm"
  394. @blur="handleInputConfirm"
  395. >
  396. </el-input>
  397. <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增屏蔽关键词</el-button>
  398. </el-form-item>
  399. <el-form-item label="添加标签" prop="isTag">
  400. <el-switch
  401. v-model="form.isTag"
  402. :active-value="1"
  403. :inactive-value="0"
  404. >
  405. </el-switch>
  406. </el-form-item>
  407. <el-form-item label="" v-if="form.isTag==1">
  408. <div>
  409. <div>
  410. <el-button size="medium" icon="el-icon-circle-plus-outline" plain @click="handleTags()">请选择标签</el-button>
  411. </div>
  412. <div>
  413. <div v-for="i in tagListForm" :key="i" style="display: inline;">
  414. <el-tag type="success" closable :disable-transitions="false" @close="handleCloseTag(i)" v-for="ii in tagList" :key="ii.id" style="margin: 3px;" v-if="ii.tagId==i">{{ii.name}}</el-tag>
  415. </div>
  416. </div>
  417. </div>
  418. </el-form-item>
  419. <el-form-item label="发送欢迎语" prop="isWelcome">
  420. <el-switch
  421. v-model="form.isWelcome"
  422. :active-value="1"
  423. :inactive-value="0"
  424. >
  425. </el-switch>
  426. </el-form-item>
  427. <el-form-item label="消息文本内容" prop="textContent" v-if="form.isWelcome==1">
  428. <el-input type="textarea" cols="1000" v-model="form.textContent" placeholder="请输入消息文本内容" />
  429. </el-form-item>
  430. <el-form-item label="图片的链接" prop="imagePicUrl" v-if="form.isWelcome==1">
  431. <el-upload
  432. v-model="form.imgUrl"
  433. class="avatar-uploader"
  434. :action="uploadUrl"
  435. :show-file-list="false"
  436. :on-success="handleAvatarSuccess"
  437. :before-upload="beforeAvatarUpload">
  438. <img v-if="form.imagePicUrl" :src="form.imagePicUrl" class="avatar" width="300px">
  439. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  440. </el-upload>
  441. </el-form-item>
  442. <el-form-item label="分时段欢迎语" prop="isSpanWelcome">
  443. <el-switch
  444. v-model="form.isSpanWelcome"
  445. :active-value="1"
  446. :inactive-value="0"
  447. >
  448. </el-switch>
  449. </el-form-item>
  450. <div v-if="form.isSpanWelcome == '1'" v-for="(item, index) in welcomeJson" :key="index" >
  451. <el-form-item :label="`时段 ${index + 1}:`">
  452. <el-row>
  453. <el-col :span="22">
  454. <div style="background-color: #fbfbfb;padding: 10px; border: 1px solid #e6e6e6; margin-bottom: 20px;">
  455. <el-form ref="friendWelcomeItemForm" :rules="itemRules" :model="item">
  456. <div style="display: flex; ">
  457. <el-form-item label="时间:" prop="week" style="flex: 6;">
  458. <el-select v-model="item.week" remote multiple placeholder="请选择" filterable style="width: 580px;">
  459. <el-option
  460. v-for="dict in weekOptions"
  461. :key="dict.value"
  462. :label="dict.label"
  463. :value="dict.value">
  464. </el-option>
  465. </el-select>
  466. </el-form-item>
  467. <el-form-item prop="startTime" style="flex: 1;">
  468. <el-time-picker
  469. v-model="item.startTime"
  470. value-format="HH:mm"
  471. format="HH:mm"
  472. :picker-options="{ selectableRange: '00:00:00 - 23:59:59' }"
  473. placeholder="开始"
  474. style="width: 100px">
  475. </el-time-picker>
  476. </el-form-item>
  477. <el-form-item prop="endTime" style="flex: 1;">
  478. <el-time-picker
  479. v-model="item.endTime"
  480. value-format="HH:mm"
  481. format="HH:mm"
  482. :picker-options="{ selectableRange: '00:00:00 - 23:59:59' }"
  483. placeholder="结束"
  484. style="width: 100px">
  485. </el-time-picker>
  486. </el-form-item>
  487. </div>
  488. <el-form-item style="margin-top: 20px" prop="text">
  489. <el-input v-model="item.text.content" type="textarea" :rows="12" maxlength="1300" show-word-limit placeholder="请输入消息内容"/>
  490. <!-- 附件和链接列表 -->
  491. <el-row>
  492. <el-col>
  493. <div v-for="(attachment, attachIndex) in item.attachments" :key="attachIndex" style="background-color: #f5f7fa;padding: 5px;border: 1px solid #d9d9d9;">
  494. <div slot="header" style=" display: flex;justify-content: space-between;align-items: center; ">
  495. <div style="flex: 1;">
  496. <span v-if="attachment.msgtype === 'image'">【图片】: {{ attachment.image.pic_url }}</span>
  497. <span v-if="attachment.msgtype === 'link'">【链接】: {{ attachment.link.title }}-{{attachment.link.desc}}</span>
  498. </div>
  499. <div style=" display: flex;gap: 10px;">
  500. <el-button
  501. size="mini"
  502. type="text"
  503. icon="el-icon-edit"
  504. style="float: left;"
  505. @click="editFileItem(attachment,attachIndex,index)"
  506. >修改</el-button>
  507. <el-button
  508. size="mini"
  509. type="text"
  510. icon="el-icon-delete"
  511. style="float: right;"
  512. @click="removeFileItem(attachment,attachIndex,index)"
  513. >删除</el-button>
  514. </div>
  515. </div>
  516. </div>
  517. </el-col>
  518. </el-row>
  519. <el-dropdown @command="(command) => handleCommand(command, index)" trigger="click" placement="top-start">
  520. <el-dropdown-menu slot="dropdown" style="width: 100px;">
  521. <el-dropdown-item command="image">
  522. <i class="el-icon-picture" style="margin-right: 10px;"></i>图片
  523. </el-dropdown-item>
  524. <el-dropdown-item command="link">
  525. <i class="el-icon-link" style="margin-right: 10px;"></i>链接
  526. </el-dropdown-item>
  527. </el-dropdown-menu>
  528. <span class="el-dropdown-link">
  529. <el-link icon="el-icon-paperclip" type="text" style="color: rgb(24, 144, 255)">
  530. 添加附件(最多9个)
  531. </el-link>
  532. </span>
  533. </el-dropdown>
  534. </el-form-item>
  535. </el-form>
  536. </div>
  537. </el-col>
  538. <el-col :span="1" :offset="1">
  539. <el-link v-if="welcomeJson.length>1" icon="el-icon-delete-solid" @click="delItemList(index)" type="text" style="margin-top: 400px" ></el-link>
  540. </el-col>
  541. </el-row>
  542. </el-form-item>
  543. </div>
  544. <div v-if="form.isSpanWelcome == '1'" style="margin-left: 10%">
  545. <el-link type="primary" class="el-icon-plus" :underline="false" @click='addItemList()'>添加其他分时段欢迎语</el-link>
  546. </div>
  547. </el-form>
  548. <div slot="footer" class="dialog-footer">
  549. <el-button type="primary" @click="submitForm">确 定</el-button>
  550. <el-button @click="cancel">取 消</el-button>
  551. </div>
  552. </el-dialog>
  553. <el-dialog :title="welcomeItem.title" :visible.sync="welcomeItem.open" style="width: 1300px;height: 100%" append-to-body>
  554. <el-form ref="fileFrom" :model="fileFrom" :rules="fuleRules" label-width="100px">
  555. <div v-if="welcomeItem.type==='image'">
  556. <el-form-item label="图片:" prop="imagePicUrl">
  557. <ImageUpload v-model="fileFrom.imagePicUrl" type="image" :num="10" :width="150" :height="150" disabled/>
  558. </el-form-item>
  559. </div>
  560. <div v-if="welcomeItem.type==='link'">
  561. <el-form-item label="选择课程">
  562. <el-select v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
  563. <el-option
  564. v-for="dict in courseList"
  565. :key="dict.dictValue"
  566. :label="dict.dictLabel"
  567. :value="parseInt(dict.dictValue)"
  568. />
  569. </el-select>
  570. <el-select v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex)" >
  571. <el-option
  572. v-for="dict in videoList"
  573. :key="dict.dictValue"
  574. :label="dict.dictLabel"
  575. :value="parseInt(dict.dictValue)"
  576. />
  577. </el-select>
  578. </el-form-item>
  579. <el-form-item label="图文标题:" prop="linkTitle">
  580. <el-input v-model="fileFrom.linkTitle" :rows="2" maxlength="42" show-word-limit placeholder="请输入图文消息标题,最长为42字" />
  581. </el-form-item>
  582. <el-form-item label="图文封面:" prop="linkPicUrl">
  583. <ImageUpload v-model="fileFrom.linkPicUrl" type="image" :num="10" :width="150" :height="150" />
  584. </el-form-item>
  585. <el-form-item label="图文的描述:" prop="linkDesc">
  586. <el-input v-model="fileFrom.linkDesc" :rows="4" maxlength="170" show-word-limit type="textarea" placeholder="请输入内容,,最长为170字" />
  587. </el-form-item>
  588. <div v-if="fileFrom.videoId==null" style="margin-top: 1%">
  589. <el-form-item label="图文链接:" label-width="100px" >
  590. <el-input v-model="fileFrom.linkUrl" placeholder="请输入链接地址" style="width: 90%;"/>
  591. </el-form-item>
  592. </div>
  593. <div v-if="fileFrom.videoId!=null">
  594. <el-form-item label="图文链接:" label-width="100px" >
  595. <el-tag type="warning">选择的课程小节 即为卡片链接地址</el-tag>
  596. </el-form-item>
  597. </div>
  598. <div v-if="fileFrom.videoId!=null">
  599. <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
  600. <el-row>
  601. <el-input-number v-model="fileFrom.expiresDays" :min="1" :max="9999" ></el-input-number>
  602. (天)
  603. </el-row>
  604. <el-row>
  605. <span class="tip">默认为30天</span>
  606. </el-row>
  607. </el-form-item>
  608. </div>
  609. </div>
  610. </el-form>
  611. <div slot="footer" class="dialog-footer" style="text-align: center">
  612. <el-button type="primary" @click="confirmUpload">确定</el-button>
  613. <el-button type="primary" @click="cancelUpload">取消</el-button>
  614. </div>
  615. </el-dialog>
  616. <el-dialog title="添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
  617. <div>搜索标签:
  618. <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
  619. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
  620. <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
  621. </div>
  622. <div v-for="item in tagGroupList" :key="item.id" >
  623. <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
  624. <span class="name-background">{{ item.name }}</span>
  625. </div>
  626. <!-- 添加外层滚动容器 -->
  627. <div class="scroll-wrapper">
  628. <div class="tag-container">
  629. <a
  630. v-for="tagItem in item.tag"
  631. class="tag-box"
  632. @click="tagSelection(tagItem)"
  633. :class="{ 'tag-selected': tagItem.isSelected }"
  634. >
  635. {{ tagItem.name }}
  636. </a>
  637. </div>
  638. </div>
  639. </div>
  640. <div slot="footer" class="dialog-footer">
  641. <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
  642. <el-button @click="addTagCancel">取 消</el-button>
  643. </div>
  644. </el-dialog>
  645. <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="700px" append-to-body>
  646. <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
  647. </el-dialog>
  648. </div>
  649. <el-drawer
  650. :with-header="false"
  651. size="75%"
  652. :title="show.title" :visible.sync="show.open">
  653. <statisDetails ref="Details" />
  654. </el-drawer>
  655. </div>
  656. </template>
  657. <script>
  658. import { informationList,sync,listContactWay, getContactWay, delContactWay, addContactWay, updateContactWay, exportContactWay } from "@/api/qw/contactWay";
  659. import {getQwAllUserList } from "@/api/company/companyUser";
  660. import contactWayGroup from '@/views/qw/contactWay/group';
  661. import {listTag, getTag, searchTags,} from "@/api/qw/tag";
  662. import { allListTagGroup} from "@/api/qw/tagGroup";
  663. import ImageUpload from '@/views/qw/material/ImageUpload.vue'
  664. import statisDetails from '@/views/qw/contactWay/statisDetails';
  665. import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
  666. import {courseList, videoList} from "@/api/qw/sop";
  667. import qwUserList from "@/views/qw/user/qwUserList.vue";
  668. export default {
  669. name: "ContactWay",
  670. components: {qwUserList, contactWayGroup,ImageUpload,statisDetails},
  671. data() {
  672. return {
  673. // 遮罩层
  674. loading: true,
  675. informationList:[],
  676. // 导出遮罩层
  677. exportLoading: false,
  678. // 选中数组
  679. ids: [],
  680. userTimeJson:[{userIds:null,userList:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}],
  681. currentEditingTimeSlotIndex: -1, // 当前正在编辑的时间段索引
  682. userIds:[],
  683. show:{
  684. title:"医院详情",
  685. open:false,
  686. },
  687. userLimitJson:[],
  688. welcomeJson:[{text:{content:null},attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}],
  689. closeWelcomeWord: [],
  690. inputVisible: false,
  691. inputValue: '',
  692. myQwCompanyList:[],
  693. tagOpen:false,
  694. spareUserIds:[],
  695. welcomeItem:{
  696. open: false,
  697. title: '',
  698. type: '',
  699. index: -1,
  700. itemIndex: -1
  701. },
  702. courseList:[],
  703. videoList:[],
  704. //标签弹窗选择
  705. tagChange:{
  706. open:false,
  707. index:null,
  708. },
  709. // 非单个禁用
  710. single: true,
  711. // 非多个禁用
  712. multiple: true,
  713. // 显示搜索条件
  714. showSearch: true,
  715. // 总条数
  716. total: 0,
  717. groupList:[],
  718. // 企微活码表格数据
  719. contactWayList: [],
  720. // 弹出层标题
  721. title: "",
  722. itemRules: {
  723. week: [
  724. { required: true, message: '请选择发起时间的星期', trigger: 'submit' }
  725. ],
  726. startTime: [
  727. { required: true, message: '请选择开始时间', trigger: 'submit' },
  728. ],
  729. endTime: [
  730. { required: true, message: '请选择结束时间', trigger: 'submit' },
  731. ],
  732. text: [
  733. { required: true, message: '消息内容不能为空噢', trigger: 'submit' }
  734. ],
  735. },
  736. fuleRules:{
  737. imagePicUrl:[ { required: true, message: "图片不能为空", trigger: "submit" }],
  738. linkTitle:[ { required: true, message: "图文标题不能为空", trigger: "submit" }],
  739. linkUrl:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
  740. },
  741. // 是否显示弹出层
  742. open: false,
  743. // 联系方式类型,1-单人, 2-多人字典
  744. typeOptions: [],
  745. weekOptions: [{
  746. value: 1,
  747. label: '星期一'
  748. }, {
  749. value: 2,
  750. label: '星期二'
  751. }, {
  752. value: 3,
  753. label: '星期三'
  754. }, {
  755. value: 4,
  756. label: '星期四'
  757. }, {
  758. value: 5,
  759. label: '星期五'
  760. }
  761. , {
  762. value: 6,
  763. label: '星期六'
  764. }
  765. , {
  766. value: 7,
  767. label: '星期天'
  768. }],
  769. // 外部客户添加时是否无需验证字典
  770. isOptions: [],
  771. // 查询参数
  772. queryParams: {
  773. pageNum: 1,
  774. pageSize: 10,
  775. name: null,
  776. type: null,
  777. skipVerify: null,
  778. state: null,
  779. userIds: null,
  780. addNum: null,
  781. deleteNum: null,
  782. num: null,
  783. qrCode: null,
  784. configId: null,
  785. isDel: 0,
  786. companyId: null,
  787. groupId: null,
  788. },
  789. uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
  790. baseUrl: process.env.VUE_APP_BASE_API,
  791. // 表单参数
  792. form: {
  793. },
  794. fileFrom:{
  795. imagePicUrl:null,
  796. linkTitle:null,
  797. linkPicUrl:null,
  798. linkDesc:null,
  799. linkUrl:null,
  800. videoId:null,
  801. courseId:null,
  802. expiresDays:30,
  803. },
  804. // 是否发送欢迎语字典
  805. companyUserList:[],
  806. // 表单校验
  807. rules: {
  808. name:[{required:true,message:"名称不能为空",trigger:"blur"}],
  809. userIds:[{required:true,message:"用户不能为空",trigger:"blur"}],
  810. skipVerify:[{required:true,message:"是否跳过验证不能为空",trigger:"change"}],
  811. isWelcome:[{required:true,message:"是否发送欢迎语不能为空",trigger:"change"}],
  812. textContent:[{required:true,message:"不能为空",trigger:"change"}],
  813. isUserLimit:[{required:true,message:"不能为空",trigger:"change"}],
  814. isSpanWelcome:[{required:true,message:"不能为空",trigger:"change"}],
  815. isCloseWelcome:[{required:true,message:"不能为空",trigger:"change"}],
  816. isTag:[{required:true,message:"不能为空",trigger:"change"}],
  817. tags:[{required:true,message:"不能为空",trigger:"change"}],
  818. isRemark:[{required:true,message:"不能为空",trigger:"change"}],
  819. remarkStatus:[{required:true,message:"不能为空",trigger:"change"}],
  820. description:[{required:true,message:"不能为空",trigger:"change"}],
  821. isDescription:[{required:true,message:"不能为空",trigger:"change"}],
  822. groupId:[{required:true,message:"不能为空",trigger:"change"}],
  823. userType:[{required:true,message:"不能为空",trigger:"change"}],
  824. },
  825. tagGroupList:[],
  826. tagList:[],
  827. tagListForm:[],
  828. // 选择使用员工相关参数
  829. userSelectList: [],
  830. //企业微信员工
  831. listUser: {
  832. title: "",
  833. open: false
  834. },
  835. };
  836. },
  837. created() {
  838. informationList().then(response => {
  839. this.informationList = response.data;
  840. });
  841. courseList().then(response => {
  842. this.courseList = response.list;
  843. });
  844. this.getDicts("sys_qw_contact_way_type").then(response => {
  845. this.typeOptions = response.data;
  846. });
  847. this.getDicts("sys_company_or").then(response => {
  848. this.isOptions = response.data;
  849. });
  850. getMyQwCompanyList().then(response => {
  851. this.myQwCompanyList = response.data;
  852. if(this.myQwCompanyList!=null){
  853. this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
  854. setTimeout(() => {
  855. this.$refs.contactWayGroup.getDetails(this.queryParams.corpId);
  856. }, 100);
  857. getQwAllUserList(this.queryParams.corpId).then(response => {
  858. this.companyUserList = response.data;
  859. });
  860. listTag({corpId:this.queryParams.corpId}).then(response => {
  861. this.tagList = response.rows;
  862. });
  863. allListTagGroup({corpId:this.queryParams.corpId}).then(response => {
  864. this.tagGroupList = response.rows;
  865. });
  866. this.getList();
  867. }
  868. });
  869. },
  870. methods: {
  871. updateCorpId(){
  872. setTimeout(() => {
  873. this.$refs.contactWayGroup.getDetails(this.queryParams.corpId);
  874. }, 1);
  875. getQwAllUserList(this.queryParams.corpId).then(response => {
  876. this.companyUserList = response.data;
  877. });
  878. listTag({corpId:this.queryParams.corpId}).then(response => {
  879. this.tagList = response.rows;
  880. });
  881. allListTagGroup({corpId:this.queryParams.corpId}).then(response => {
  882. this.tagGroupList = response.rows;
  883. });
  884. this.getList();
  885. },
  886. handleSearchTags(name){
  887. if (!name){
  888. return this.$message.error("请输入要搜索的标签")
  889. }
  890. this.queryTagParams.name=name;
  891. this.queryTagParams.corpId=this.queryParams.corpId;
  892. searchTags(this.queryTagParams).then(response => {
  893. this.tagGroupList = response.rows;
  894. this.tagTotal = response.total;
  895. });
  896. // searchTags({name:name,corpId:this.queryParams.corpId}).then(response => {
  897. // this.tagGroupList = response.rows;
  898. // });
  899. },
  900. cancelSearchTags(){
  901. this.afreshData(this.queryParams.corpId)
  902. },
  903. /**
  904. * 重新获取 部分数据
  905. */
  906. afreshData(value){
  907. //所有的标签组
  908. allListTagGroup({corpId:value}).then(response => {
  909. this.tagGroupList = response.rows;
  910. });
  911. //所有的标签
  912. listTag({corpId:value}).then(response => {
  913. this.tagList = response.rows;
  914. });
  915. },
  916. /** 查询企微活码列表 */
  917. getList() {
  918. this.loading = true;
  919. listContactWay(this.queryParams).then(response => {
  920. this.contactWayList = response.rows;
  921. this.total = response.total;
  922. this.loading = false;
  923. });
  924. },
  925. handledetails(row){
  926. this.show.open=true;
  927. setTimeout(() => {
  928. this.$refs.Details.getDetails(row.id);
  929. }, 1);
  930. },
  931. courseChange(fileFrom,index,itemIndex){
  932. // 清空 videoId 选择
  933. this.$set(fileFrom, 'videoId', null);
  934. // 清空 videoList
  935. this.videoList = [];
  936. if (fileFrom.courseId != null) {
  937. // 查找选中的课程对应的 label 和 dictImgUrl
  938. const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === fileFrom.courseId);
  939. if (selectedCourse) {
  940. // 设置 linkTitle 和 linkImageUrl
  941. this.$set(fileFrom, 'linkTitle', selectedCourse.dictLabel);
  942. this.$set(fileFrom, 'linkPicUrl', selectedCourse.dictImgUrl);
  943. }
  944. // 获取新的 videoList
  945. videoList(fileFrom.courseId).then(response => {
  946. this.videoList = response.list;
  947. });
  948. }
  949. //
  950. // // 更新对应的数据层级
  951. // if (itemIndex === -1) {
  952. // // 更新 form.attachments
  953. // this.$set(this.form.attachments, index, {
  954. // ...this.form.attachments[index],
  955. // courseId: fileFrom.courseId,
  956. // videoId: null, // 因为已清空
  957. // title: fileFrom.linkTitle,
  958. // picurl: fileFrom.linkPicUrl
  959. // });
  960. // } else {
  961. //
  962. // this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
  963. // ...this.form.daypartingItemlist[itemIndex].attachments[index],
  964. // courseId: fileFrom.courseId,
  965. // videoId: null, // 因为已清空
  966. // title: fileFrom.linkTitle,
  967. // picurl: fileFrom.linkPicUrl
  968. // });
  969. // }
  970. },
  971. videoIdChange(fileFrom,index, itemIndex){
  972. //选择了课程小节则 默认绑上
  973. if (fileFrom.videoId != null) {
  974. // 根据 videoId 获取相关信息(假设有相关的 API 调用)
  975. let selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === fileFrom.videoId);
  976. if (selectedVideo) {
  977. this.$set(fileFrom, 'linkDesc', selectedVideo.dictLabel);
  978. this.$set(fileFrom, 'expiresDays', 30);
  979. }
  980. }
  981. // // 更新对应的数据层级
  982. // if (itemIndex === -1) {
  983. // // 更新 form.attachments
  984. // this.$set(this.form.attachments, index, {
  985. // ...this.form.attachments[index],
  986. // videoId: fileFrom.videoId,
  987. // desc: fileFrom.linkDesc,
  988. // });
  989. // } else {
  990. // // 更新 form.daypartingItemlist[itemIndex].attachments
  991. // this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
  992. // ...this.form.daypartingItemlist[itemIndex].attachments[index],
  993. // videoId: fileFrom.videoId,
  994. // desc: fileFrom.linkDesc,
  995. // });
  996. //
  997. // }
  998. },
  999. //附件选择
  1000. handleCommand(command,itemIndex){
  1001. if (this.welcomeJson[itemIndex].attachments.length>=9){
  1002. return this.$message.error('附件数量已达上限,无法添加更多附件');
  1003. }
  1004. this.welcomeItem = {
  1005. open: true,
  1006. title: command === 'image' ? '添加图片' : '添加链接',
  1007. type: command,
  1008. index: itemIndex === -1 ? this.form.attachments.length : this.welcomeJson[itemIndex].attachments.length,
  1009. itemIndex
  1010. };
  1011. },
  1012. //重置附件表单
  1013. resetFileFrom() {
  1014. this.fileFrom = {
  1015. imagePicUrl: null,
  1016. linkTitle: null,
  1017. linkPicUrl: null,
  1018. linkDesc: null,
  1019. linkUrl: null,
  1020. videoId:null,
  1021. courseId:null,
  1022. };
  1023. this.welcomeItem={
  1024. open: false,
  1025. title: '',
  1026. type: '',
  1027. index: -1,
  1028. itemIndex: -1
  1029. } // 重置编辑索引
  1030. },
  1031. //修改附件
  1032. editFileItem(item, index, itemIndex){
  1033. this.welcomeItem = {
  1034. open: true,
  1035. title: item.msgtype === 'image' ? '编辑图片' : '编辑链接',
  1036. type: item.msgtype,
  1037. index,
  1038. itemIndex
  1039. };
  1040. if (item.msgtype === 'image') {
  1041. this.fileFrom.imagePicUrl = item.image.pic_url;
  1042. } else if (item.msgtype === 'link') {
  1043. this.fileFrom.linkTitle = item.link.title;
  1044. this.fileFrom.linkPicUrl = item.link.picurl;
  1045. this.fileFrom.linkDesc = item.link.desc;
  1046. this.fileFrom.linkUrl = item.link.url;
  1047. this.fileFrom.videoId = item.link.videoId;
  1048. this.fileFrom.courseId = item.link.courseId;
  1049. this.fileFrom.expiresDays = item.link.expiresDays;
  1050. }
  1051. videoList(item.link.courseId).then(response => {
  1052. this.videoList = response.list;
  1053. });
  1054. },
  1055. //删除附件
  1056. removeFileItem(data,index, itemIndex) {
  1057. if (itemIndex === -1) {
  1058. this.form.attachments.splice(index, 1);
  1059. } else {
  1060. this.welcomeJson[itemIndex].attachments.splice(index, 1);
  1061. }
  1062. },
  1063. //添加分时段欢迎语
  1064. addItemList(){
  1065. this.welcomeJson.push({text:{content:null},attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null})
  1066. },
  1067. //删除某一个分时段欢迎语
  1068. delItemList(index){
  1069. this.welcomeJson.splice(index,1)
  1070. },
  1071. //提交附件
  1072. confirmUpload() {
  1073. const { type, index, itemIndex } = this.welcomeItem;
  1074. let attachment = {};
  1075. if (type === 'image') {
  1076. attachment = {
  1077. msgtype: 'image',
  1078. image: {
  1079. pic_url: this.fileFrom.imagePicUrl
  1080. }
  1081. };
  1082. } else if (type === 'link') {
  1083. attachment = {
  1084. msgtype: 'link',
  1085. link: {
  1086. title: this.fileFrom.linkTitle,
  1087. picurl: this.fileFrom.linkPicUrl,
  1088. desc: this.fileFrom.linkDesc,
  1089. url: this.fileFrom.linkUrl,
  1090. courseId:this.fileFrom.courseId,
  1091. videoId:this.fileFrom.videoId,
  1092. expiresDays:this.fileFrom.expiresDays,
  1093. }
  1094. };
  1095. }
  1096. if (itemIndex === -1) {
  1097. // 默认欢迎语附件处理
  1098. if (index < this.form.attachments.length) {
  1099. // 存在附件则更新
  1100. this.form.attachments.splice(index, 1, attachment);
  1101. } else {
  1102. // 不存在附件则插入
  1103. this.form.attachments.push(attachment);
  1104. }
  1105. } else {
  1106. // 分时段欢迎语附件处理
  1107. if (index < this.welcomeJson[itemIndex].attachments.length) {
  1108. // 存在附件则更新
  1109. this.welcomeJson[itemIndex].attachments.splice(index, 1, attachment);
  1110. } else {
  1111. // 不存在附件则插入
  1112. this.welcomeJson[itemIndex].attachments.push(attachment);
  1113. }
  1114. }
  1115. this.resetFileFrom();
  1116. },
  1117. //取消附件
  1118. cancelUpload() {
  1119. this.resetFileFrom();
  1120. this.welcomeItem.open = false;
  1121. },
  1122. userChange(){
  1123. for (let i = 0; i < this.userIds.length; i++) {
  1124. if(!this.userLimitJson.find(item => item.userId == this.userIds[i])){
  1125. this.userLimitJson.push({userId:this.userIds[i],limitCount:100})
  1126. console.log(this.userLimitJson)
  1127. }
  1128. }
  1129. for (let i = 0; i < this.userLimitJson.length; i++) {
  1130. if(!this.userIds.find(item => item== this.userLimitJson[i].userId)){
  1131. this.userLimitJson.splice(i,1)
  1132. }
  1133. }
  1134. },
  1135. showInput() {
  1136. this.inputVisible = true;
  1137. this.$nextTick(_ => {
  1138. this.$refs.saveTagInput.$refs.input.focus();
  1139. });
  1140. },
  1141. addUserTime(){
  1142. this.userTimeJson.push({userIds:null,userList:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null})
  1143. },
  1144. delUserTime(index){
  1145. this.userTimeJson.splice(index,1)
  1146. },
  1147. handleInputConfirm() {
  1148. let inputValue = this.inputValue;
  1149. if (inputValue) {
  1150. this.closeWelcomeWord.push(inputValue);
  1151. }
  1152. this.inputVisible = false;
  1153. this.inputValue = '';
  1154. },
  1155. handleCloseTag(row) {
  1156. console.log(row)
  1157. this.tagListForm.splice(this.tagListForm.indexOf(row), 1);
  1158. },
  1159. handleTags(){
  1160. for (let i = 0; i < this.tagGroupList.length; i++) {
  1161. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1162. this.tagGroupList[i].tag[x].isSelected=false;
  1163. }
  1164. }
  1165. this.tagOpen = true;
  1166. },
  1167. addTagSubmitForm(){
  1168. this.tagListForm=[];
  1169. for (let i = 0; i < this.tagGroupList.length; i++) {
  1170. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1171. if(this.tagGroupList[i].tag[x].isSelected==true){
  1172. this.tagListForm.push(this.tagGroupList[i].tag[x].tagId)
  1173. }
  1174. }
  1175. }
  1176. if(this.tagListForm==[]||this.tagListForm==null||this.tagListForm==""){
  1177. return this.$message('请选择标签');
  1178. }
  1179. this.tagOpen = false;
  1180. },
  1181. addTagCancel() {
  1182. this.tagOpen = false;
  1183. this.tagListForm=null;
  1184. },
  1185. tagSelection(row){
  1186. row.isSelected= !row.isSelected;
  1187. this.$forceUpdate();
  1188. },
  1189. selectGroupScreen(row){
  1190. this.queryParams.groupId=row
  1191. this.getList();
  1192. },
  1193. getGroupList(row){
  1194. this.groupList=row;
  1195. },
  1196. // 取消按钮
  1197. cancel() {
  1198. this.open = false;
  1199. this.reset();
  1200. },
  1201. // 表单重置
  1202. reset() {
  1203. this.form = {
  1204. id: null,
  1205. type: null,
  1206. name: null,
  1207. remark: null,
  1208. skipVerify: null,
  1209. state: null,
  1210. userIds: null,
  1211. addNum: null,
  1212. deleteNum: null,
  1213. num: null,
  1214. qrCode: null,
  1215. configId: null,
  1216. isDel: null,
  1217. createTime: null,
  1218. companyId: null,
  1219. isWelcome: 0,
  1220. textContent: null,
  1221. imagePicUrl: null,
  1222. isUserLimit: 0,
  1223. isSpanWelcome: 1,
  1224. isCloseWelcome: 1,
  1225. closeWelcomeWord: null,
  1226. isTag: 0,
  1227. tags: null,
  1228. isRemark: 0,
  1229. remarkStatus: 1,
  1230. description: null,
  1231. isDescription: 0,
  1232. spareUserIds: null,
  1233. groupId: null,
  1234. userLimitJson: null,
  1235. userTimeJson: null,
  1236. userType: 2
  1237. };
  1238. this.userTimeJson=[{userIds:null,userList:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}];
  1239. this.currentEditingTimeSlotIndex = -1;
  1240. this.userLimitJson=[];
  1241. this.userIds=[];
  1242. this.userSelectList=[];
  1243. this.spareUserIds=[];
  1244. this.tagListForm=[];
  1245. this.closeWelcomeWord=[];
  1246. this.welcomeJson=[{text:{content:null},attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}];
  1247. },
  1248. /** 搜索按钮操作 */
  1249. handleQuery() {
  1250. this.queryParams.pageNum = 1;
  1251. this.getList();
  1252. },
  1253. sync(){
  1254. sync(this.queryParams.corpId).then(response => {
  1255. this.msgSuccess("同步");
  1256. this.getList();
  1257. });
  1258. },
  1259. /** 重置按钮操作 */
  1260. resetQuery() {
  1261. this.resetForm("queryForm");
  1262. this.queryParams.groupId=null
  1263. this.handleQuery();
  1264. },
  1265. // 多选框选中数据
  1266. handleSelectionChange(selection) {
  1267. this.ids = selection.map(item => item.id)
  1268. this.single = selection.length!==1
  1269. this.multiple = !selection.length
  1270. },
  1271. /** 新增按钮操作 */
  1272. handleAdd() {
  1273. this.reset();
  1274. this.open = true;
  1275. this.title = "添加企微活码";
  1276. this.form.groupId=this.queryParams.groupId
  1277. },
  1278. handleAvatarSuccess(res, file) {
  1279. if(res.code==200){
  1280. this.form.imagePicUrl=res.url;
  1281. }
  1282. else{
  1283. this.msgError(res.msg);
  1284. }
  1285. },
  1286. beforeAvatarUpload(file) {
  1287. const isLt1M = file.size / 1024 / 1024 < 1;
  1288. if (!isLt1M) {
  1289. this.$message.error('上传图片大小不能超过 1MB!');
  1290. }
  1291. return isLt1M;
  1292. },
  1293. /** 修改按钮操作 */
  1294. handleUpdate(row) {
  1295. this.reset();
  1296. const id = row.id || this.ids
  1297. getContactWay(id).then(response => {
  1298. this.form = response.data;
  1299. this.open = true;
  1300. // 根据 userType 区分处理
  1301. if(this.form.userType === 2) {
  1302. // 自动上下线模式 - 只回显 userTimeJson
  1303. if(this.form.userTimeJson!=null){
  1304. this.userTimeJson=JSON.parse(this.form.userTimeJson)
  1305. // 根据 userIds回显userList
  1306. this.userTimeJson.forEach(timeSlot => {
  1307. if (!timeSlot.userList) {
  1308. timeSlot.userList = [];
  1309. }
  1310. if (timeSlot.userIds && Array.isArray(timeSlot.userIds)) {
  1311. timeSlot.userList = timeSlot.userIds.map(qwUserId => {
  1312. return this.companyUserList.find(u => u.qwUserId === qwUserId);
  1313. }).filter(u => u); // 过滤掉 undefined
  1314. }
  1315. });
  1316. }else{
  1317. this.userTimeJson=[{userIds:null,userList:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}]
  1318. }
  1319. } else if(this.form.userType === 1) {
  1320. // 全天在线模式 - 只回显 userSelectList
  1321. if(this.form.userIds!=null){
  1322. this.userIds=JSON.parse(this.form.userIds)
  1323. this.userSelectList = this.userIds.map(qwUserId => {
  1324. return this.companyUserList.find(u => u.qwUserId === qwUserId);
  1325. }).filter(u => u); // 过滤掉 undefined
  1326. }else{
  1327. this.userIds=[]
  1328. this.userSelectList=[]
  1329. }
  1330. }
  1331. if(this.form.userLimitJson!=null){
  1332. this.userLimitJson=JSON.parse(this.form.userLimitJson)
  1333. }else{ this.userLimitJson=[]}
  1334. if(this.form.spareUserIds!=null){
  1335. this.spareUserIds=JSON.parse(this.form.spareUserIds)
  1336. }else{ this.spareUserIds=[]}
  1337. if(this.form.tags!=null){
  1338. this.tagListForm=JSON.parse(this.form.tags)
  1339. }else{ this.tagListForm=[]}
  1340. if(this.form.closeWelcomeWord!=null){
  1341. this.closeWelcomeWord=JSON.parse(this.form.closeWelcomeWord)
  1342. }else{ this.closeWelcomeWord=[]}
  1343. if(this.form.welcomeJson!=null){
  1344. this.welcomeJson=JSON.parse(this.form.welcomeJson)
  1345. }else{ this.welcomeJson=[{text:{content:null},attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}] }
  1346. this.title = "修改企微活码";
  1347. });
  1348. },
  1349. /** 提交按钮 */
  1350. submitForm() {
  1351. this.$refs["form"].validate(valid => {
  1352. if (valid) {
  1353. this.form.corpId=this.queryParams.corpId
  1354. if(this.form.userType === 1){
  1355. if(Object.keys(this.userIds).length === 0){
  1356. return this.$message({
  1357. message: '请选择客服类型-使用员工',
  1358. type: 'warning'
  1359. });
  1360. }
  1361. }
  1362. if(this.form.userType==2){
  1363. var jsonUserIds=[];
  1364. for (let i = 0; i < this.userTimeJson.length; i++) {
  1365. // 确保 userIds 与 userList 同步
  1366. if(this.userTimeJson[i].userList && this.userTimeJson[i].userList.length > 0){
  1367. this.userTimeJson[i].userIds = this.userTimeJson[i].userList.map(u => u.qwUserId);
  1368. }
  1369. if(this.userTimeJson[i].userIds==null||this.userTimeJson[i].userIds=="" || this.userTimeJson[i].userIds.length==0){
  1370. return this.$message('人员不能为空');
  1371. }
  1372. if(this.userTimeJson[i].week==null||this.userTimeJson[i].week==""){
  1373. return this.$message('日期不能为空');
  1374. }
  1375. if(this.userTimeJson[i].startTime==null||this.userTimeJson[i].startTime==""){
  1376. return this.$message('时间不能为空');
  1377. }
  1378. if(this.userTimeJson[i].endTime==null||this.userTimeJson[i].endTime==""){
  1379. return this.$message('时间不能为空');
  1380. }
  1381. for (let j = 0; j < this.userTimeJson[i].userIds.length; j++) {
  1382. if(!jsonUserIds.find(item=>item==this.userTimeJson[i].userIds[j])){
  1383. jsonUserIds.push(this.userTimeJson[i].userIds[j]);
  1384. }
  1385. }
  1386. }
  1387. this.userIds=jsonUserIds;
  1388. }
  1389. this.form.closeWelcomeWord=JSON.stringify(this.closeWelcomeWord)
  1390. this.form.userIds=JSON.stringify(this.userIds)
  1391. // 提交前移除 userList 字段(因为后端只需要 userIds)
  1392. const userTimeJsonForSubmit = this.userTimeJson.map(item => {
  1393. const {userList, ...rest} = item;
  1394. return rest;
  1395. });
  1396. this.form.userTimeJson=JSON.stringify(userTimeJsonForSubmit)
  1397. this.form.userLimitJson=JSON.stringify(this.userLimitJson)
  1398. this.form.spareUserIds=JSON.stringify(this.spareUserIds)
  1399. this.form.tags=JSON.stringify(this.tagListForm)
  1400. this.form.welcomeJson=JSON.stringify(this.welcomeJson)
  1401. if (this.form.id != null) {
  1402. updateContactWay(this.form).then(response => {
  1403. this.msgSuccess("修改成功");
  1404. this.open = false;
  1405. this.getList();
  1406. });
  1407. } else {
  1408. addContactWay(this.form).then(response => {
  1409. this.msgSuccess("新增成功");
  1410. this.open = false;
  1411. this.getList();
  1412. });
  1413. }
  1414. }
  1415. });
  1416. },
  1417. /** 删除按钮操作 */
  1418. handleDelete(row) {
  1419. const ids = row.id || this.ids;
  1420. this.$confirm('是否确认删除企微活码编号为"' + ids + '"的数据项?', "警告", {
  1421. confirmButtonText: "确定",
  1422. cancelButtonText: "取消",
  1423. type: "warning"
  1424. }).then(function() {
  1425. return delContactWay(ids);
  1426. }).then(() => {
  1427. this.getList();
  1428. this.msgSuccess("删除成功");
  1429. }).catch(() => {});
  1430. },
  1431. /** 导出按钮操作 */
  1432. handleExport() {
  1433. const queryParams = this.queryParams;
  1434. this.$confirm('是否确认导出所有企微活码数据项?', "警告", {
  1435. confirmButtonText: "确定",
  1436. cancelButtonText: "取消",
  1437. type: "warning"
  1438. }).then(() => {
  1439. this.exportLoading = true;
  1440. return exportContactWay(queryParams);
  1441. }).then(response => {
  1442. this.download(response.msg);
  1443. this.exportLoading = false;
  1444. }).catch(() => {});
  1445. },
  1446. //选择企微员工时
  1447. handleListUser(type, sendType, selectOne) {
  1448. setTimeout(() => {
  1449. this.$refs.QwUserList.getDetails(this.form.corpId, type, sendType, selectOne);
  1450. }, 1);
  1451. this.listUser.title = "选择企微员工"
  1452. this.listUser.open = true;
  1453. },
  1454. //企业微信员工信息子组件返回
  1455. selectUserList(list) {
  1456. this.listUser.open = false;
  1457. console.log("选择的员工",list)
  1458. // 判断是全天在线还是自动上下线
  1459. if (this.currentEditingTimeSlotIndex === -1) {
  1460. // 全天在线模式
  1461. list.forEach(obj => {
  1462. if (!this.userSelectList.some(item => item.id === obj.id)) {
  1463. this.userSelectList.push(obj); // 存储完整对象
  1464. this.userIds.push(obj.qwUserId);
  1465. }
  1466. });
  1467. } else {
  1468. // 自动上下线模式 - 为特定时间段添加员工
  1469. const timeSlot = this.userTimeJson[this.currentEditingTimeSlotIndex];
  1470. if (!timeSlot.userList) {
  1471. this.$set(timeSlot, 'userList', []);
  1472. }
  1473. if (!timeSlot.userIds) {
  1474. this.$set(timeSlot, 'userIds', []);
  1475. }
  1476. list.forEach(obj => {
  1477. if (!timeSlot.userList.some(item => item.id === obj.id)) {
  1478. timeSlot.userList.push(obj);
  1479. timeSlot.userIds.push(obj.qwUserId);
  1480. }
  1481. });
  1482. // 重置索引
  1483. this.currentEditingTimeSlotIndex = -1;
  1484. }
  1485. },
  1486. // 全天在线模式 - 删除员工标签
  1487. handleCloseGroupUser(user) {
  1488. const index = this.userSelectList.findIndex(t => t.id === user.id);
  1489. if (index !== -1) {
  1490. this.userSelectList.splice(index, 1);
  1491. this.userIds.splice(index, 1);
  1492. }
  1493. },
  1494. // 自动上下线模式 - 打开员工选择弹窗
  1495. handleListUserForTimeSlot(timeSlotIndex) {
  1496. this.currentEditingTimeSlotIndex = timeSlotIndex;
  1497. setTimeout(() => {
  1498. this.$refs.QwUserList.getDetails(this.form.corpId, this.form.type, this.form.sendType, true);
  1499. }, 1);
  1500. this.listUser.title = "选择企微员工"
  1501. this.listUser.open = true;
  1502. },
  1503. // 自动上下线模式 - 删除时间段员工标签
  1504. handleCloseTimeSlotUser(timeSlotIndex, user) {
  1505. const timeSlot = this.userTimeJson[timeSlotIndex];
  1506. const userListIndex = timeSlot.userList.findIndex(t => t.id === user.id);
  1507. if (userListIndex !== -1) {
  1508. // 使用 splice 删除并强制更新
  1509. timeSlot.userList.splice(userListIndex, 1);
  1510. timeSlot.userIds.splice(userListIndex, 1);
  1511. // 强制更新整个 userTimeJson 数组以触发响应式更新
  1512. this.$set(this.userTimeJson, timeSlotIndex, {...timeSlot});
  1513. }
  1514. },
  1515. }
  1516. };
  1517. </script>
  1518. <style scoped>
  1519. .avatar-uploader .el-upload {
  1520. border: 1px dashed #d9d9d9;
  1521. border-radius: 6px;
  1522. cursor: pointer;
  1523. position: relative;
  1524. overflow: hidden;
  1525. }
  1526. .avatar-uploader .el-upload:hover {
  1527. border-color: #409EFF;
  1528. }
  1529. .avatar-uploader-icon {
  1530. font-size: 28px;
  1531. color: #8c939d;
  1532. width: 150px;
  1533. height: 150px;
  1534. line-height: 150px;
  1535. text-align: center;
  1536. }
  1537. </style>
  1538. <style scoped>
  1539. /* CSS 样式 */
  1540. .tag-container {
  1541. display: flex;
  1542. flex-wrap: wrap; /* 超出宽度时自动换行 */
  1543. gap: 8px; /* 设置标签之间的间距 */
  1544. }
  1545. .name-background {
  1546. display: inline-block;
  1547. background-color: #abece6; /* 背景颜色 */
  1548. padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
  1549. border-radius: 4px; /* 可选:设置圆角 */
  1550. }
  1551. .tag-box {
  1552. padding: 8px 12px;
  1553. border: 1px solid #989797;
  1554. border-radius: 4px;
  1555. cursor: pointer;
  1556. display: inline-block;
  1557. }
  1558. .tag-selected {
  1559. background-color: #00bc98;
  1560. color: #fff;
  1561. border-color: #00bc98;
  1562. }
  1563. .el-tag + .el-tag {
  1564. margin-left: 10px;
  1565. }
  1566. .button-new-tag {
  1567. margin-left: 10px;
  1568. height: 32px;
  1569. line-height: 30px;
  1570. padding-top: 0;
  1571. padding-bottom: 0;
  1572. }
  1573. .input-new-tag {
  1574. width: 90px;
  1575. margin-left: 10px;
  1576. vertical-align: bottom;
  1577. }
  1578. /* 新增的滚动容器样式(不影响原有样式) */
  1579. .scroll-wrapper {
  1580. max-height: 130px; /* 大约三行的高度 */
  1581. overflow-y: auto; /* 垂直滚动 */
  1582. padding-right: 5px; /* 为滚动条留出空间 */
  1583. }
  1584. /* 美化滚动条(可选) */
  1585. .scroll-wrapper::-webkit-scrollbar {
  1586. width: 6px;
  1587. }
  1588. .scroll-wrapper::-webkit-scrollbar-thumb {
  1589. background: rgba(0, 0, 0, 0.2);
  1590. border-radius: 3px;
  1591. }
  1592. </style>