index.vue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. <template>
  2. <div class="app-container">
  3. <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
  4. <el-form-item label="企微主体" prop="corpId">
  5. <el-select v-model="queryParams.corpId" placeholder="企微主体" size="small" @change="updateCorpId()">
  6. <el-option
  7. v-for="dict in myQwCompanyList"
  8. :key="dict.dictValue"
  9. :label="dict.dictLabel"
  10. :value="dict.dictValue"
  11. />
  12. </el-select>
  13. </el-form-item>
  14. <el-form-item label="企微部门">
  15. <treeselect :clearable="false" v-model="queryParams.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门"/>
  16. </el-form-item>
  17. <el-form-item label="企微账号" prop="qwUserId">
  18. <el-input
  19. v-model="queryParams.qwUserId"
  20. placeholder="请输入企微账号"
  21. clearable
  22. size="small"
  23. @keyup.enter.native="handleQuery"
  24. />
  25. </el-form-item>
  26. <el-form-item label="企微昵称" prop="qwUserName">
  27. <el-input
  28. v-model="queryParams.qwUserName"
  29. placeholder="请输入企微昵称"
  30. clearable
  31. size="small"
  32. @keyup.enter.native="handleQuery"
  33. />
  34. </el-form-item>
  35. <el-form-item label="授权码" prop="appKey">
  36. <el-input
  37. v-model="queryParams.appKey"
  38. placeholder="请输入授权码"
  39. clearable
  40. size="small"
  41. @keyup.enter.native="handleQuery"
  42. />
  43. </el-form-item>
  44. <el-form-item label="员工状态" prop="isDel">
  45. <el-select v-model="queryParams.isDel" placeholder="请选择员工状态" clearable>
  46. <el-option
  47. v-for="item in optionsStatus"
  48. :key="item.value"
  49. :label="item.label"
  50. :value="item.value">
  51. </el-option>
  52. </el-select>
  53. </el-form-item>
  54. <el-form-item>
  55. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  56. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  57. </el-form-item>
  58. </el-form>
  59. <el-row :gutter="10" class="mb8">
  60. <el-col :span="1.5">
  61. <el-button
  62. type="primary"
  63. :disabled="multiple"
  64. plain
  65. icon="el-icon-edit"
  66. size="mini"
  67. @click="updateSendType"
  68. >修改发送方式
  69. </el-button>
  70. </el-col>
  71. <el-col :span="1.5">
  72. <el-button
  73. type="warning"
  74. plain
  75. icon="el-icon-download"
  76. size="mini"
  77. :loading="exportLoading"
  78. @click="handleExport"
  79. v-hasPermi="['qw:user:export']"
  80. >导出</el-button>
  81. </el-col>
  82. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  83. </el-row>
  84. <el-table border v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
  85. <el-table-column type="selection" width="55" align="center" />
  86. <el-table-column label="企微成员ID" align="center" prop="id" />
  87. <el-table-column label="企微账号" align="center" prop="qwUserId" />
  88. <el-table-column label="企微昵称" align="center" prop="qwUserName" />
  89. <el-table-column label="员工称呼" align="center" prop="welcomeText" />
  90. // 部门
  91. <el-table-column label="部门" align="center" prop="departmentName" />
  92. <el-table-column label="员工状态" align="center" prop="isDel">
  93. <template slot-scope="scope">
  94. <el-tag v-if="scope.row.isDel == 0" type="success">正常</el-tag>
  95. <el-tag v-else type="error">离职</el-tag>
  96. </template>
  97. </el-table-column>
  98. <el-table-column label="联系我二维码" align="center" prop="contactWay" >
  99. <template slot-scope="scope">
  100. <el-image
  101. v-if="scope.row.contactWay!=null"
  102. style="width: 100px; height: 100px"
  103. :src="scope.row.contactWay"
  104. fit="contain"
  105. @click="openImageViewer(scope.row.contactWay)"/>
  106. </template>
  107. </el-table-column>
  108. <el-table-column label="绑定的AI客服" align="center" prop="fastGptRoleName" />
  109. <el-table-column label="授权码" align="center" prop="appKey" />
  110. <el-table-column label="发送方式" align="center" prop="sendMsgType">
  111. <template slot-scope="scope">
  112. <el-tag v-if="scope.row.sendMsgType == 0">方式一</el-tag>
  113. <el-tag v-if="scope.row.sendMsgType == 1" type="success">方式二</el-tag>
  114. <el-tag v-if="scope.row.sendMsgType == 2" type="warning">掉线通知</el-tag>
  115. </template>
  116. </el-table-column>
  117. <el-table-column label="vid" align="center" prop="vid" />
  118. <el-table-column label="uid" align="center" prop="uid" />
  119. <el-table-column label="serverId" align="center" prop="serverId" />
  120. <el-table-column label="ipad状态" align="center" prop="loginStatus">
  121. <template slot-scope="scope">
  122. <el-tag v-if="scope.row.ipadStatus == 1" type="success">在线</el-tag>
  123. <el-tag v-else type="danger">离线</el-tag>
  124. </template>
  125. </el-table-column>
  126. <!-- <el-table-column label="插件状态" align="center" prop="toolStatus">-->
  127. <!-- <template slot-scope="scope">-->
  128. <!-- <el-tag v-if="scope.row.toolStatus == 1" type="success">在线</el-tag>-->
  129. <!-- <el-tag v-else type="danger">离线</el-tag>-->
  130. <!-- </template>-->
  131. <!-- </el-table-column>-->
  132. <!-- <el-table-column label="插件版本" align="center" prop="version"/>-->
  133. <!-- <el-table-column label="服务器地址" align="center" prop="loginCodeUrl">-->
  134. <!-- <template slot-scope="scope">-->
  135. <!-- <el-tooltip class="item" effect="dark" :content="scope.row.loginCodeUrl" placement="top">-->
  136. <!-- <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">-->
  137. <!-- <span>{{ scope.row.loginCodeUrl }}</span>-->
  138. <!-- </div>-->
  139. <!-- </el-tooltip>-->
  140. <!-- </template>-->
  141. <!-- </el-table-column>-->
  142. <el-table-column label="自动发课" align="center" prop="isAuto">
  143. <template slot-scope="scope">
  144. <dict-tag :options="isAutoOptions" :value="scope.row.isAuto"/>
  145. </template>
  146. </el-table-column>
  147. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
  148. <template slot-scope="scope">
  149. <el-button
  150. size="mini"
  151. type="text"
  152. icon="el-icon-user-solid"
  153. plain
  154. @click="handleAppellation(scope.row)"
  155. >
  156. 修改员工称呼
  157. </el-button>
  158. <el-button
  159. size="mini"
  160. type="text"
  161. icon="el-icon-user-solid"
  162. plain
  163. @click="handleAutoRemark(scope.row)"
  164. >
  165. 完课备注修改
  166. </el-button>
  167. <el-button
  168. v-if="scope.row.serverStatus==1&&scope.row.ipadStatus!=1"
  169. size="mini"
  170. type="text"
  171. icon="el-icon-sunny"
  172. plain
  173. @click="handleLoginQwCode(scope.row)"
  174. v-hasPermi="['qw:user:login']"
  175. >
  176. 登录企微
  177. </el-button>
  178. <el-button
  179. v-if="scope.row.serverStatus==1&&scope.row.ipadStatus==1"
  180. size="mini"
  181. type="text"
  182. icon="el-icon-moon"
  183. plain
  184. @click="handleLoginOutQwStatus(scope.row)"
  185. v-hasPermi="['qw:user:login']"
  186. >
  187. 退出企微
  188. </el-button>
  189. <el-button
  190. v-if="scope.row.ipadStatus==1"
  191. size="mini"
  192. type="text"
  193. icon="el-icon-moon"
  194. plain
  195. @click="handleTwoCode(scope.row)"
  196. v-hasPermi="['qw:user:login']">
  197. 二次验证
  198. </el-button>
  199. <el-button
  200. v-if="scope.row.serverStatus!=1"
  201. size="mini"
  202. type="text"
  203. icon="el-icon-moon"
  204. plain
  205. @click="handleGetQwIpad(scope.row)"
  206. v-hasPermi="['qw:user:login']"
  207. >
  208. 获取Ai主机
  209. </el-button>
  210. <el-button
  211. v-if="scope.row.serverStatus==1 && scope.row.ipadStatus!=1"
  212. size="mini"
  213. type="text"
  214. icon="el-icon-moon"
  215. plain
  216. @click="handleDelQwIpad(scope.row)"
  217. v-hasPermi="['qw:user:login']"
  218. >
  219. 解绑Ai主机
  220. </el-button>
  221. <el-button
  222. v-if="scope.row.isAuto=='00'"
  223. size="mini"
  224. type="text"
  225. icon="el-icon-moon"
  226. plain
  227. @click="handleUpdateIsAuto(scope.row,'01')"
  228. v-hasPermi="['qw:user:isauto']"
  229. >
  230. 启用插件
  231. </el-button>
  232. <el-button
  233. v-if="scope.row.isAuto=='01'"
  234. size="mini"
  235. type="text"
  236. icon="el-icon-moon"
  237. plain
  238. @click="handleUpdateIsAuto(scope.row,'00')"
  239. v-hasPermi="['qw:user:isauto']"
  240. >
  241. 禁用插件
  242. </el-button>
  243. </template>
  244. </el-table-column>
  245. <el-table-column label="主机" align="center" class-name="small-padding fixed-width" width="110px" fixed="right">
  246. <template slot-scope="scope">
  247. <el-button
  248. v-if="scope.row.appKey==null"
  249. size="mini"
  250. type="text"
  251. icon="el-icon-s-check"
  252. plain
  253. v-hasPermi="['qw:user:authAppKey']"
  254. @click="uploadAuthorizeKey2(scope.row)"
  255. >授权key
  256. </el-button>
  257. <el-button
  258. v-if="scope.row.loginCodeUrl==null && scope.row.appKey !=null"
  259. size="mini"
  260. type="text"
  261. icon="el-icon-sunny"
  262. plain
  263. @click="handleBindCloudHost(scope.row)"
  264. v-hasPermi="['qw:user:loginIp']"
  265. >
  266. 绑定主机
  267. </el-button>
  268. <!-- <el-button-->
  269. <!-- v-if="scope.row.loginCodeUrl!=null"-->
  270. <!-- size="mini"-->
  271. <!-- type="text"-->
  272. <!-- icon="el-icon-video-camera-solid"-->
  273. <!-- plain-->
  274. <!-- @click="handleCloudAP(scope.row.loginCodeUrl)"-->
  275. <!-- v-hasPermi="['qw:user:cloudAP']"-->
  276. <!-- >-->
  277. <!-- 获取主机帐密-->
  278. <!-- </el-button>-->
  279. <el-button
  280. v-if="scope.row.loginCodeUrl!=null"
  281. size="mini"
  282. type="text"
  283. icon="el-icon-moon"
  284. plain
  285. @click="handleUnbindCloudHost(scope.row)"
  286. v-hasPermi="['qw:user:loginIpOut']"
  287. >
  288. 解除主机
  289. </el-button>
  290. <el-button
  291. size="mini"
  292. type="text"
  293. :icon="scope.row.videoGetStatus == 0 ? 'el-icon-circle-check' : 'el-icon-remove-outline'"
  294. plain
  295. @click="changeVideoStatus(scope.row)"
  296. >
  297. {{ scope.row.videoGetStatus == 0 ? "开启" : "禁用" }}视频号接收
  298. </el-button>
  299. </template>
  300. </el-table-column>
  301. <el-table-column label="AI客服" align="center" class-name="small-padding fixed-width" width="100px" fixed="right">
  302. <template slot-scope="scope">
  303. <el-button
  304. size="mini"
  305. type="text"
  306. icon="el-icon-connection"
  307. plain
  308. v-if="scope.row.fastGptRoleName!=null"
  309. @click="bindFastGptRole(scope.row)"
  310. >换绑AI客服</el-button>
  311. <el-button
  312. size="mini"
  313. type="text"
  314. plain
  315. icon="el-icon-link"
  316. v-else
  317. @click="bindFastGptRole(scope.row)"
  318. >绑定AI客服</el-button>
  319. <el-button
  320. size="mini"
  321. type="text"
  322. icon="el-icon-unlock"
  323. plain
  324. v-if="scope.row.fastGptRoleName!=null"
  325. @click="relieveFastGptRole(scope.row)"
  326. >解绑AI客服</el-button>
  327. </template>
  328. </el-table-column>
  329. </el-table>
  330. <pagination
  331. v-show="total>0"
  332. :total="total"
  333. :page.sync="queryParams.pageNum"
  334. :limit.sync="queryParams.pageSize"
  335. @pagination="getList"
  336. />
  337. <!-- 绑定AI客服-->
  338. <el-dialog :title="bindAiTitle" :visible.sync="bindAiOpen" width="1200px" append-to-body>
  339. <fast-gpt-role ref="fastGptRole" @refreshFastGptList="refreshFastGptList" ></fast-gpt-role>
  340. </el-dialog>
  341. <!-- <el-dialog :visible.sync="updateIp.open" width="600px" append-to-body>-->
  342. <!-- <el-form ref="updateIpForm" :model="updateIpForm" :rules="updateIpRule" label-width="100px">-->
  343. <!-- <el-form-item label="新云主机IP" prop="Ip">-->
  344. <!-- <el-input v-model="updateIpForm.newIp" placeholder="请输入新IP" />-->
  345. <!-- </el-form-item>-->
  346. <!-- </el-form>-->
  347. <!-- <div slot="footer" class="dialog-footer" >-->
  348. <!-- <el-button type="primary" @click="submitUpdateIpForm">确 定</el-button>-->
  349. <!-- </div>-->
  350. <!-- </el-dialog>-->
  351. <el-dialog title="云主机信息" :visible.sync="cloudAPOpen.open" append-to-body>
  352. <el-card class="box-card">
  353. <div slot="header" class="clearfix">
  354. <span>账号:{{cloudAPOpen.admin}}</span>
  355. </div>
  356. <div slot="header" class="clearfix">
  357. <span>密码:{{cloudAPOpen.passWord}}</span>
  358. </div>
  359. </el-card>
  360. </el-dialog>
  361. <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
  362. <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
  363. <el-form-item label="员工称呼" prop="welcomeText">
  364. <el-input v-model="callOpenFrom.welcomeText" placeholder="请输入员工称呼" />
  365. </el-form-item>
  366. </el-form>
  367. <div slot="footer" class="dialog-footer" >
  368. <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
  369. </div>
  370. </el-dialog>
  371. <el-dialog :title="editRemarkOpen.title" :visible.sync="editRemarkOpen.open" width="500px" append-to-body>
  372. <el-form ref="callOpenFrom" :model="editRemarkOpen" label-width="110px">
  373. <el-radio-group v-model="editRemarkOpen.isSendMsg">
  374. <el-card>
  375. <el-row :gutter="20">
  376. <el-col>
  377. <el-radio
  378. :label="1"
  379. style="font-size: 16px; margin: 10px 0;"
  380. >添加【完课备注】在最【旧备注-(前面)】</el-radio>
  381. </el-col>
  382. <el-col>
  383. <el-radio
  384. :label="2"
  385. style="font-size: 16px; margin: 10px 0;"
  386. >添加【完课备注】在最【旧备注-(后面)】</el-radio>
  387. </el-col>
  388. <el-col>
  389. <el-radio
  390. :label="3"
  391. style="font-size: 16px; margin: 10px 0;"
  392. >使用简洁版备注【*日期完】,在【旧备注-前面】</el-radio>
  393. </el-col>
  394. <el-col>
  395. <el-radio
  396. :label="4"
  397. style="font-size: 16px; margin: 10px 0;"
  398. >使用简洁版备注【*日期完】,在【旧备注-后面】</el-radio>
  399. </el-col>
  400. <el-col>
  401. <el-radio
  402. :label="5"
  403. style="font-size: 16px; margin: 10px 0;"
  404. >不用完课备注</el-radio>
  405. </el-col>
  406. </el-row>
  407. </el-card>
  408. </el-radio-group>
  409. </el-form>
  410. <div slot="footer" class="dialog-footer">
  411. <el-button type="primary" @click="submitEditRemarkOpenFrom">确 定</el-button>
  412. </div>
  413. </el-dialog>
  414. <el-dialog title="授权key" :visible.sync="authorizeKeyOpen" width="500px" append-to-body>
  415. <el-form ref="authorizeKeyFrom" :model="authorizeKeyFrom" :rules="authorizeKeyRule" label-width="110px">
  416. <el-form-item label="授权的key值" prop="appKey">
  417. <el-input v-model="authorizeKeyFrom.appKey" placeholder="请输入授权key" type="Number"/>
  418. </el-form-item>
  419. </el-form>
  420. <div slot="footer" class="dialog-footer" >
  421. <el-button type="primary" @click="submitAuthorizeKeyForm">确 定</el-button>
  422. </div>
  423. </el-dialog>
  424. <!--二维码 -->
  425. <el-dialog
  426. title="企微二次认证"
  427. :visible.sync="qwLoginTwo.open"
  428. width="600px"
  429. append-to-body
  430. custom-class="qr-login-dialog"
  431. >
  432. <div class="qr-login-container">
  433. <div class="image-wrapper" v-loading="imageLoading" >
  434. <el-image
  435. :src="'data:image/png;base64,' +qwLoginTwo.codeUrl"
  436. style="display: block; margin: 0 auto; width: 300px; height: 300px;"
  437. />
  438. </div>
  439. <p class="qr-login-instructions">二次验证二维码</p>
  440. </div>
  441. <div slot="footer" class="dialog-footer" >
  442. <el-button type="primary" @click="qwLoginTwo.open=false">确 定</el-button>
  443. </div>
  444. </el-dialog>
  445. <el-dialog
  446. :title="qwLogin.title"
  447. :visible.sync="qwLogin.open"
  448. width="600px"
  449. append-to-body
  450. custom-class="qr-login-dialog"
  451. >
  452. <div class="qr-login-container">
  453. <div class="image-wrapper" v-loading="imageLoading" >
  454. <el-image
  455. :src="'data:image/png;base64,' +qwLogin.codeUrl"
  456. style="display: block; margin: 0 auto; width: 300px; height: 300px;"
  457. />
  458. </div>
  459. <p class="qr-login-instructions">使用企业微信扫码授权登录</p>
  460. </div>
  461. </el-dialog>
  462. <el-dialog
  463. title="输入企微验证码"
  464. :visible.sync="qwCode.open"
  465. width="600px"
  466. append-to-body>
  467. <el-form :model="qwCode" label-width="80px" @submit.native.prevent="handleSubmit">
  468. <el-form-item label="验证码" prop="companyName">
  469. <el-input v-model="qwCode.code" placeholder="输入企微6位验证码" />
  470. </el-form-item>
  471. </el-form>
  472. <div slot="footer" class="dialog-footer">
  473. <el-button type="primary" @click="submitCodeForm">确 定</el-button>
  474. </div>
  475. </el-dialog>
  476. <!-- 大图预览对话框 -->
  477. <el-dialog
  478. :visible.sync="dialogVisible"
  479. :modal="false"
  480. width="1200"
  481. append-to-body>
  482. <img
  483. :src="this.dialogImageUrl"
  484. style="display: block; max-width: 100%; margin: 0 auto"
  485. />
  486. </el-dialog>
  487. <el-dialog
  488. :visible.sync="updateSendOpen"
  489. width="1000px"
  490. append-to-body>
  491. <el-form label-width="80px">
  492. <p>是否修改企微账号发送方式:
  493. <el-tag style="margin-left: 10px" v-for="name in names">{{ name }}</el-tag>
  494. </p>
  495. <el-form-item label="发送方式" prop="type">
  496. <el-radio-group v-model="type">
  497. <el-radio
  498. :label="0"
  499. >方式一
  500. </el-radio>
  501. <el-radio
  502. :label="1"
  503. >方式二
  504. </el-radio>
  505. <el-radio
  506. :label="2"
  507. >掉线通知
  508. </el-radio>
  509. </el-radio-group>
  510. </el-form-item>
  511. </el-form>
  512. <div slot="footer" class="dialog-footer">
  513. <el-button type="primary" @click="submitUpdateSendTypeForm">确 定</el-button>
  514. </div>
  515. </el-dialog>
  516. </div>
  517. </template>
  518. <script>
  519. import {
  520. updateIsAuto,
  521. updateUser,
  522. getMyQwCompanyList,
  523. relieveFastGptRoleById,
  524. loginQwIpad,
  525. loginQwCodeMsg,
  526. twoCode,
  527. twoCodeStatus,
  528. qrCodeStatus,
  529. updateSendType,
  530. getQwIpad,
  531. delQwIpad,
  532. qrCodeVerify,
  533. outLoginQwIpad,
  534. changeVideoStatus,
  535. handleAllocateRemoteHost,
  536. qwBindCloudHost, qwUnbindCloudHost, handleAuthAppKey, handleInputAuthAppKey, selectCloudAP, staffListUser, exportStaff
  537. } from '../../../api/qw/user'
  538. import fastGptRole from "@/views/fastGpt/fastGptRole/fastGptRole";
  539. import { treeselect } from "@/api/qw/qwDept";
  540. import Treeselect from "@riophae/vue-treeselect";
  541. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  542. export default {
  543. name: "cuDeptIdIndex",
  544. components: { fastGptRole,Treeselect},
  545. data() {
  546. return {
  547. deptOptions:[], // 企微部门
  548. isAutoOptions:[],
  549. updateIp:{
  550. open:false,
  551. title: "修改云主机IP"
  552. },
  553. updateIpForm:{
  554. id:null,
  555. newIp:null,
  556. },
  557. authorizeKeyOpen:false,
  558. authorizeKeyFrom:{
  559. id:null,
  560. appKey:null,
  561. qwUserId:null,
  562. qwUserName:null
  563. },
  564. updateIpRule:{},
  565. newIp:null,
  566. //放大图片
  567. dialogImageUrl:null,
  568. dialogVisible:false,
  569. optionsStatus: [{
  570. value: 0,
  571. label: '正常'
  572. }, {
  573. value: 2,
  574. label: '离职'
  575. }],
  576. // 遮罩层
  577. loading: true,
  578. names: [],
  579. // 导出遮罩层
  580. exportLoading: false,
  581. // 选中数组
  582. ids: [],
  583. // 非单个禁用
  584. single: true,
  585. // 非多个禁用
  586. multiple: true,
  587. // 显示搜索条件
  588. showSearch: true,
  589. updateSendOpen: false,
  590. // 总条数
  591. total: 0,
  592. //公司列表
  593. myQwCompanyList:[],
  594. // 企微用户表格数据
  595. userList: [],
  596. allowSelectOptions:[],
  597. // 弹出层标题
  598. bindAiTitle: "",
  599. bindAiOpen: false,
  600. qwLogin:{
  601. title:"",
  602. open:false,
  603. codeUrl:null,
  604. code:null,
  605. appKey:null,
  606. },
  607. qwLoginTwo:{
  608. title:"",
  609. open:false,
  610. codeUrl:null,
  611. code:null,
  612. appKey:null,
  613. },
  614. qwCode:{
  615. title:"",
  616. open:false,
  617. code:null,
  618. },
  619. cloudAPOpen:{
  620. open:false,
  621. admin:null,
  622. passWord:null,
  623. },
  624. callOpen:{
  625. open:false,
  626. title: '修改员工称呼',
  627. },
  628. callOpenFrom:{
  629. id:null,
  630. welcomeText:null,
  631. },
  632. isAutoForm:{
  633. id:null,
  634. isAuto:null,
  635. },
  636. editRemarkOpen: {
  637. open: false,
  638. title: '修改员工自动给完课客户打备注的规则',
  639. id:null,
  640. isSendMsg:null,
  641. },
  642. twoCodeInterval:null,
  643. type: 0,
  644. loginQwInterval:null,
  645. imageLoading: true, // 控制加载状态
  646. // 查询参数
  647. queryParams: {
  648. pageNum: 1,
  649. pageSize: 10,
  650. qwUserId: null,
  651. corpId: null,
  652. qwUserName: null,
  653. deptId:null,
  654. },
  655. qwUserId:null,
  656. companyUserList:[],
  657. // 表单参数
  658. form: {
  659. isSendMsg: '2',
  660. },
  661. authorizeKeyRule:{
  662. appKey:[{required:true,message:"授权码不能为空",trigger:"blur"}]
  663. },
  664. callOpenRule:{
  665. welcomeText:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
  666. },
  667. // 表单校验
  668. rules: {
  669. },
  670. //欢迎语表单校验
  671. weclomeRules:{
  672. welcomeText:[{required:true,message:"消息文本不能为空",trigger:"blur"}]
  673. },
  674. };
  675. },
  676. created() {
  677. this.getDicts("qw_user_is_auto").then(response => {
  678. this.isAutoOptions = response.data;
  679. });
  680. getMyQwCompanyList().then(response => {
  681. this.myQwCompanyList = response.data;
  682. if(this.myQwCompanyList && this.myQwCompanyList.length>0){
  683. this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
  684. // 查询部门下拉树结构
  685. this.getTreeselect()
  686. this.getList();
  687. }
  688. });
  689. this.loading = false;
  690. },
  691. watch: {
  692. // 监听弹窗的可见性变化
  693. 'qwLogin.open'(newVal) {
  694. if (!newVal) {
  695. // 如果弹窗关闭,清除定时器
  696. clearInterval(this.loginQwInterval);
  697. }
  698. },
  699. },
  700. methods: {
  701. /** 查询部门下拉树结构 */
  702. getTreeselect() {
  703. var that=this;
  704. let query = {
  705. corpId: this.queryParams.corpId
  706. }
  707. // 企微主体不能为空
  708. if(!query.corpId){
  709. this.$message.error("请选择企微主体");
  710. return;
  711. }
  712. treeselect(query).then((response) => {
  713. this.deptOptions = response.data;
  714. console.log(this.deptOptions)
  715. if(response.data!=null&&response.data.length>0){
  716. this.queryParams.deptId=response.data[0].id;
  717. }
  718. });
  719. },
  720. getList() {
  721. this.loading = true;
  722. staffListUser(this.queryParams).then(response => {
  723. this.userList = response.rows;
  724. this.total = response.total;
  725. this.loading = false;
  726. });
  727. },
  728. updateCorpId() {
  729. this.reset();
  730. this.getTreeselect();
  731. this.getList();
  732. },
  733. changeVideoStatus(val){
  734. changeVideoStatus(val.id).then(res => {
  735. this.$message.success("修改状态成功");
  736. this.getList()
  737. })
  738. },
  739. //绑定AI客服
  740. bindFastGptRole(row) {
  741. this.bindAiTitle = "绑定AI客服";
  742. this.bindAiOpen = true;
  743. setTimeout(() => {
  744. this.$refs.fastGptRole.handleBindAiData(row)
  745. }, 200);
  746. },
  747. handleAppellation(val) {
  748. this.callOpen.open = true;
  749. this.callOpenFrom.welcomeText = val.welcomeText;
  750. this.callOpenFrom.id = val.id;
  751. },
  752. handleAutoRemark(val) {
  753. this.editRemarkOpen.open = true;
  754. this.editRemarkOpen.id = val.id;
  755. this.editRemarkOpen.isSendMsg = val.isSendMsg;
  756. },
  757. //登录
  758. handleLoginQwCode(val) {
  759. if (val.appKey == null || val.appKey === '') {
  760. return this.$message.warning("没有授权码,无法登录企业微信,请授权");
  761. }
  762. loginQwIpad({qwUserId: val.id}).then(res => {
  763. this.qwUserId = val.id;
  764. this.qwLogin.code = null;
  765. this.imageLoading = false;
  766. console.log(res)
  767. if (res.msg == "success") {
  768. this.qwLogin.codeUrl = res.qrCode64
  769. this.qwLogin.open = true;
  770. this.loginQwPolling();
  771. } else {
  772. this.$message.success(res.msg);
  773. this.getList()
  774. }
  775. })
  776. },
  777. handleTwoCode(val) {
  778. twoCode({qwUserId: val.id}).then(res => {
  779. console.log(res)
  780. this.qwLoginTwo.open = true;
  781. this.qwLoginTwo.codeUrl = res.qrCode
  782. });
  783. },
  784. twoCodePolling() {
  785. this.twoCodeInterval = setInterval(() => {
  786. twoCodeStatus({qwUserId: this.qwUserId}).then(res => {
  787. console.log(res)
  788. if (res.msg == 104001) {
  789. this.$message.success('登录成功');
  790. this.clearDl()
  791. clearInterval(this.loginQwInterval);
  792. } else if (res.msg == 100004) {
  793. this.clearDl()
  794. }
  795. });
  796. }, 3000);
  797. },
  798. loginQwPolling() {
  799. this.loginQwInterval = setInterval(() => {
  800. qrCodeStatus({qwUserId: this.qwUserId}).then(res => {
  801. console.log(res)
  802. if (res.msg == 22) {
  803. this.$message.success('账号企业不一致请重新扫码登录');
  804. this.clearDl();
  805. }
  806. if (res.msg == 104001) {
  807. this.$message.success('登录成功');
  808. this.clearDl()
  809. } else if (res.msg == 100004) {
  810. this.qwCode.open = true;
  811. clearInterval(this.loginQwInterval);
  812. }
  813. });
  814. }, 3000);
  815. },
  816. submitCodeForm() {
  817. qrCodeVerify({code: this.qwCode.code, qwUserId: this.qwUserId}).then(res => {
  818. console.log(res)
  819. this.$message.success('验证成功账号信息确认中。。。。');
  820. this.qwCode.open = false;
  821. this.loginQwInterval = setTimeout(() => {
  822. qrCodeStatus({qwUserId: this.qwUserId}).then(res => {
  823. console.log(res);
  824. if (res.msg == 23) {
  825. this.$message.error('账号不一致请重新扫码登录');
  826. this.clearDl();
  827. }
  828. if (res.msg == 22) {
  829. this.$message.error('账号企业不一致请重新扫码登录');
  830. this.clearDl();
  831. }
  832. if (res.msg == 104001) {
  833. this.$message.success('登录成功');
  834. this.clearDl();
  835. }
  836. });
  837. }, 4000);
  838. });
  839. },
  840. clearDl() {
  841. this.qwCode.open = false;
  842. this.qwLogin.open = false;
  843. clearInterval(this.loginQwInterval);
  844. this.getList()
  845. },
  846. //退出
  847. handleLoginOutQwStatus(val) {
  848. outLoginQwIpad({qwUserId: val.id}).then(res => {
  849. this.$message.success("退出登录成功");
  850. this.getList()
  851. })
  852. },
  853. handleGetQwIpad(val) {
  854. getQwIpad({qwUserId: val.id}).then(res => {
  855. this.$message.success("获取主机成功");
  856. this.getList();
  857. }).catch(error => {
  858. console.log(error);
  859. if (error.code === 501) {
  860. this.$confirm(
  861. '当前区域没有多余的名额,将为你分配异地名额,会导致企业微信需要扫脸重新登录,并且半个小时后需要进行验证',
  862. '提示',
  863. {
  864. confirmButtonText: '确定',
  865. cancelButtonText: '取消',
  866. type: 'warning',
  867. dangerouslyUseHTMLString: true
  868. }
  869. ).then(() => {
  870. return handleAllocateRemoteHost({qwUserId: val.id});
  871. }).then(res => {
  872. this.$message.success('异地主机分配成功');
  873. this.getList();
  874. }).catch(() => {
  875. this.$message.info('已取消异地主机分配');
  876. });
  877. } else {
  878. this.$message.error('获取主机失败');
  879. }
  880. });
  881. },
  882. handleDelQwIpad(val) {
  883. delQwIpad({qwUserId: val.id}).then(res => {
  884. this.$message.success("解绑主机成功");
  885. this.getList()
  886. })
  887. },
  888. handleUpdateIsAuto(val,code) {
  889. this.isAutoForm={
  890. id:val.id,
  891. isAuto:code
  892. }
  893. updateIsAuto(this.isAutoForm).then(res => {
  894. if (code==='00'){
  895. this.$message.success('禁用成功');
  896. }else {
  897. this.$message.success('启用成功');
  898. }
  899. this.getList();
  900. });
  901. },
  902. //传验证码
  903. handleLoginQwCodeMsg() {
  904. loginQwCodeMsg({appKey: this.qwLogin.appKey, code: this.qwLogin.code}).then(res => {
  905. this.qwLogin.open = false;
  906. this.$message.success("登录成功");
  907. })
  908. },
  909. validateCode() {
  910. // 只允许输入数字并限制长度为6
  911. this.qwLogin.code = this.qwLogin.code.replace(/\D/g, "").slice(0, 6);
  912. },
  913. handleCloudAP(urlAP) {
  914. selectCloudAP({ipAddress: urlAP}).then(res => {
  915. this.cloudAPOpen.open = true
  916. this.cloudAPOpen.admin = res.data.apAdmin;
  917. this.cloudAPOpen.passWord = res.data.apPassword;
  918. })
  919. },
  920. handleUnbindCloudHost(val) {
  921. const appKey = val.appKey;
  922. this.$confirm(
  923. '确定要给企微账号:<span style="color: green;">' + val.qwUserId + '' +
  924. '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
  925. '</span><br><span style="color: orange;">解绑【Ps:解绑后此云主机可能会分配给他人】</span></span>',
  926. "警告",
  927. {
  928. confirmButtonText: "确定",
  929. cancelButtonText: "取消",
  930. type: "warning",
  931. dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
  932. }
  933. ).then(() => {
  934. return qwUnbindCloudHost(appKey);
  935. }).then(response => {
  936. this.$message.success('解绑成功');
  937. }).finally(res => {
  938. this.getList();
  939. })
  940. },
  941. handleAuthorizeKey(val) {
  942. this.authorizeKeyFrom.id = val.id;
  943. this.authorizeKeyFrom.qwUserId = val.qwUserId;
  944. this.authorizeKeyFrom.qwUserName = val.qwUserName;
  945. this.authorizeKeyOpen = true;
  946. },
  947. submitAuthorizeKeyForm() {
  948. this.$refs["authorizeKeyFrom"].validate(valid => {
  949. if (valid) {
  950. if (this.authorizeKeyFrom.id != null && this.authorizeKeyFrom.appKey != null) {
  951. this.uploadAuthorizeKey();
  952. }
  953. }
  954. });
  955. },
  956. submitCallOpenFrom() {
  957. this.$refs["callOpenFrom"].validate(valid => {
  958. if (valid) {
  959. if (this.callOpenFrom.id != null && this.callOpenFrom.welcomeText != null) {
  960. updateUser(this.callOpenFrom).then(res => {
  961. this.$message.success('修改成功');
  962. this.callOpen.open = false;
  963. this.getList();
  964. });
  965. }
  966. }
  967. });
  968. },
  969. submitEditRemarkOpenFrom() {
  970. if (this.editRemarkOpen.id != null && this.editRemarkOpen.isSendMsg != null) {
  971. updateUser(this.editRemarkOpen).then(res => {
  972. this.$message.success('修改成功');
  973. this.editRemarkOpen.open = false;
  974. this.getList();
  975. });
  976. } else {
  977. this.$message.error("请选择条件")
  978. }
  979. },
  980. uploadAuthorizeKey() {
  981. this.$confirm(
  982. '确定要给企微账号:<span style="color: green;">' + this.authorizeKeyFrom.qwUserId + '' +
  983. '</span><br>企微昵称:<span style="color: red;">【' + this.authorizeKeyFrom.qwUserName + '】</span>' +
  984. '</span><br>授权key:<span style="color: #04adf6;">【' + this.authorizeKeyFrom.appKey + '】</span>?',
  985. "警告",
  986. {
  987. confirmButtonText: "确定",
  988. cancelButtonText: "取消",
  989. type: "warning",
  990. dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
  991. }
  992. ).then(() => {
  993. this.authorizeKeyOpen = false;
  994. return handleInputAuthAppKey(this.authorizeKeyFrom);
  995. }).then(response => {
  996. this.msgSuccess("授权key完成");
  997. }).finally(res => {
  998. this.resetAuthorizeKeyFrom();
  999. this.getList();
  1000. })
  1001. },
  1002. uploadAuthorizeKey2(val) {
  1003. const id = val.id;
  1004. this.$confirm(
  1005. '确定要给企微账号:<span style="color: green;">' + val.qwUserId + '' +
  1006. '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
  1007. '</span><br>授权key</span>?',
  1008. "警告",
  1009. {
  1010. confirmButtonText: "确定",
  1011. cancelButtonText: "取消",
  1012. type: "warning",
  1013. dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
  1014. }
  1015. ).then(() => {
  1016. return handleAuthAppKey({id: id});
  1017. }).then(response => {
  1018. this.msgSuccess("授权key完成");
  1019. }).finally(res => {
  1020. this.resetAuthorizeKeyFrom();
  1021. this.getList();
  1022. })
  1023. },
  1024. handleBindCloudHost(val) {
  1025. if (val.appKey == null || val.appKey == '') {
  1026. return this.$message.warning('没有授权码,无法绑定主机,请联系管理员');
  1027. }
  1028. const appKey = val.appKey;
  1029. this.$confirm(
  1030. '确定要给企微账号:<span style="color: green;">' + val.qwUserId + '' +
  1031. '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
  1032. '</span><br><span style="color: dodgerblue;">绑定云主机?</span></span>',
  1033. "警告",
  1034. {
  1035. confirmButtonText: "确定",
  1036. cancelButtonText: "取消",
  1037. type: "warning",
  1038. dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
  1039. }
  1040. ).then(() => {
  1041. return qwBindCloudHost(appKey);
  1042. }).then(response => {
  1043. this.$message.success('绑定成功,请登录云主机进行配置~~');
  1044. }).finally(res => {
  1045. this.getList();
  1046. })
  1047. },
  1048. openImageViewer(url) {
  1049. // 打开大图预览对话框
  1050. this.dialogImageUrl = url
  1051. this.dialogVisible = true;
  1052. },
  1053. //刷新页面
  1054. refreshFastGptList() {
  1055. this.bindAiOpen = false;
  1056. this.getList();
  1057. },
  1058. // 取消按钮
  1059. cancel() {
  1060. this.open = false;
  1061. this.reset();
  1062. },
  1063. // 表单重置
  1064. reset() {
  1065. this.form = {
  1066. id: null,
  1067. qwUserId: null,
  1068. corpId: null,
  1069. qwUserName: null,
  1070. };
  1071. this.resetForm("form");
  1072. },
  1073. //重置授权
  1074. resetAuthorizeKeyFrom() {
  1075. this.authorizeKeyFrom = {
  1076. id: null,
  1077. appKey: null,
  1078. qwUserId: null,
  1079. qwUserName: null
  1080. };
  1081. },
  1082. //重置登录
  1083. resetQwLogin() {
  1084. this.qwLogin = {
  1085. title: "",
  1086. open: false,
  1087. codeUrl: null,
  1088. code: null,
  1089. corpId: null,
  1090. qwUserId: null,
  1091. }
  1092. this.qwLogin.open = false;
  1093. this.loading = false;
  1094. this.getList();
  1095. },
  1096. //解绑AI客服
  1097. relieveFastGptRole(row) {
  1098. this.$confirm('是否确认解绑AI客服?', "警告", {
  1099. confirmButtonText: "确定",
  1100. cancelButtonText: "取消",
  1101. type: "warning"
  1102. }).then(function () {
  1103. return relieveFastGptRoleById(row.id);
  1104. }).then(() => {
  1105. this.getList();
  1106. this.msgSuccess("解绑成功");
  1107. })
  1108. },
  1109. /** 搜索按钮操作 */
  1110. handleQuery() {
  1111. this.queryParams.pageNum = 1;
  1112. this.getList();
  1113. },
  1114. /** 重置按钮操作 */
  1115. resetQuery() {
  1116. this.resetForm("queryForm");
  1117. this.queryParams.corpId = this.myQwCompanyList[0].dictValue;
  1118. this.handleQuery();
  1119. },
  1120. // 多选框选中数据
  1121. handleSelectionChange(selection) {
  1122. this.ids = selection.map(item => item.id)
  1123. this.names = selection.map(item => item.qwUserName)
  1124. this.single = selection.length !== 1
  1125. this.multiple = !selection.length
  1126. },
  1127. /** 提交按钮 */
  1128. submitForm() {
  1129. this.$refs["form"].validate(valid => {
  1130. if (valid) {
  1131. if (this.form.id != null) {
  1132. // updateUser(this.form).then(response => {
  1133. // this.msgSuccess("绑定成功");
  1134. // this.open = false;
  1135. // this.getList();
  1136. //
  1137. // });
  1138. } else {
  1139. // addUser(this.form).then(response => {
  1140. // this.msgSuccess("新增成功");
  1141. // this.open = false;
  1142. // this.getList();
  1143. // });
  1144. }
  1145. }
  1146. });
  1147. },
  1148. /** 导出按钮操作 */
  1149. handleExport() {
  1150. const queryParams = this.queryParams;
  1151. this.$confirm('是否确认导出所有企微员工数据项?', "警告", {
  1152. confirmButtonText: "确定",
  1153. cancelButtonText: "取消",
  1154. type: "warning"
  1155. }).then(() => {
  1156. this.exportLoading = true;
  1157. return exportStaff(queryParams);
  1158. }).then(response => {
  1159. this.download(response.msg);
  1160. this.exportLoading = false;
  1161. }).catch(() => {
  1162. });
  1163. },
  1164. updateSendType() {
  1165. this.updateSendOpen = true;
  1166. },
  1167. cleanUpdateSendType() {
  1168. this.updateSendOpen = false;
  1169. },
  1170. submitUpdateSendTypeForm(){
  1171. updateSendType({ids: this.ids, type: this.type}).then(e => {
  1172. this.updateSendOpen = false;
  1173. this.$message.success("修改成功");
  1174. this.getList();
  1175. });
  1176. },
  1177. }
  1178. };
  1179. </script>
  1180. <style>
  1181. .text-container {
  1182. max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
  1183. overflow-y: auto; /* 内容超出时显示滚动条 */
  1184. line-height: 1.5em; /* 行高设置,确保每行高度一致 */
  1185. }
  1186. .qr-login-dialog .el-dialog__body {
  1187. display: flex;
  1188. flex-direction: column;
  1189. align-items: center;
  1190. text-align: center;
  1191. padding: 20px;
  1192. }
  1193. .qr-login-container {
  1194. width: 100%;
  1195. }
  1196. .qr-login-instructions {
  1197. font-size: 14px;
  1198. color: #666;
  1199. margin: 10px 0;
  1200. }
  1201. .verification-code-input {
  1202. margin-top: 15px;
  1203. width: 80%;
  1204. }
  1205. .vue-treeselect{
  1206. width: 217px;
  1207. height: 36px;
  1208. }
  1209. </style>