index.vue 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  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="sendType">
  5. <el-select v-model="queryParams.sendType" placeholder="选择看课方式" clearable size="small" @change="handleSendTypeChange">
  6. <el-option
  7. v-for="dict in sendTypeOptions"
  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="项目" prop="project">-->
  15. <!-- <el-select v-model="queryParams.project" placeholder="请选择项目" clearable size="small" >-->
  16. <!-- <el-option-->
  17. <!-- v-for="item in projectOptions"-->
  18. <!-- :key="item.dictValue"-->
  19. <!-- :label="item.dictLabel"-->
  20. <!-- :value="item.dictValue"-->
  21. <!-- />-->
  22. <!-- </el-select>-->
  23. <!-- </el-form-item>-->
  24. <el-form-item label="会员昵称" prop="nickName" v-if="queryParams.sendType == 1">
  25. <el-input
  26. v-model="queryParams.nickName"
  27. placeholder="请输入会员昵称"
  28. clearable
  29. size="small"
  30. @keyup.enter.native="handleQuery"
  31. />
  32. </el-form-item>
  33. <el-form-item label="会员id" prop="userId" v-if="queryParams.sendType == 1">
  34. <el-input
  35. v-model="queryParams.userId"
  36. placeholder="请输入会员昵称"
  37. clearable
  38. size="small"
  39. @keyup.enter.native="handleQuery"
  40. />
  41. </el-form-item>
  42. <el-form-item label="企微客户昵称" prop="nickName" v-if="queryParams.sendType == 2">
  43. <el-input
  44. v-model="queryParams.externalUserName"
  45. placeholder="请输入企微客户昵称"
  46. clearable
  47. size="small"
  48. @keyup.enter.native="handleQuery"
  49. />
  50. </el-form-item>
  51. <el-form-item label="课程" prop="courseId">
  52. <el-select filterable v-model="queryParams.courseId" placeholder="请选择课程" clearable size="small" @change="courseChange(queryParams.courseId)">
  53. <el-option
  54. v-for="dict in courseLists"
  55. :key="dict.dictValue"
  56. :label="dict.dictLabel"
  57. :value="dict.dictValue"
  58. />
  59. </el-select>
  60. </el-form-item>
  61. <el-form-item label="小节" prop="videoId">
  62. <el-select filterable v-model="queryParams.videoId" placeholder="请选择小节" clearable size="small">
  63. <el-option
  64. v-for="dict in videoList"
  65. :key="dict.dictValue"
  66. :label="dict.dictLabel"
  67. :value="dict.dictValue"
  68. />
  69. </el-select>
  70. </el-form-item>
  71. <el-form-item v-if="companyName === undefined || companyName === 1" label="所属销售" prop="companyUserId">
  72. <el-select v-model="queryParams.companyUserId" clearable filterable remote
  73. placeholder="请输入关键词" :remote-method="loadCompanyUserOptions"
  74. v-select-load-more="loadMoreCompanyUserOptions"
  75. :loading="companyUserOptionsLoading">
  76. <el-option
  77. v-for="item in companyUserOptions"
  78. :key="item.dictValue"
  79. :label="item.dictLabel"
  80. :value="item.dictValue">
  81. </el-option>
  82. </el-select>
  83. </el-form-item>
  84. <el-form-item v-if="companyName==2" label="所属销售" prop="companyUserId">
  85. <el-select v-model="queryParams.companyUserId" clearable filterable remote
  86. placeholder="请输入关键词"
  87. v-select-load-more="loadMoreCompanyUserOptions"
  88. :loading="companyUserOptionsLoading">
  89. <el-option
  90. v-for="item in companyUserOptionsByAll"
  91. :key="item.dictValue"
  92. :label="item.dictLabel"
  93. :value="item.dictValue">
  94. </el-option>
  95. </el-select>
  96. </el-form-item>
  97. <el-form-item label="所属企微" prop="qwUserName">
  98. <el-select v-model="queryParams.qwUserName" clearable filterable remote
  99. placeholder="请输入关键词" :remote-method="loadQwUserOptions"
  100. v-select-load-more="loadMoreQwUserOptions"
  101. :loading="qwUserOptionsLoading">
  102. <el-option
  103. v-for="item in qwUserOptions"
  104. :key="item.qwUserId"
  105. :label="item.qwUserName"
  106. :value="item.qwUserName">
  107. </el-option>
  108. </el-select>
  109. </el-form-item>
  110. <!-- sop名称 -->
  111. <el-form-item label="SOP名称" prop="sopId" v-if="queryParams.sendType == 2">
  112. <el-autocomplete
  113. v-model="sopSearchText"
  114. :fetch-suggestions="querySopAsync"
  115. placeholder="请输入SOP名称"
  116. clearable
  117. size="small"
  118. style="width: 200px"
  119. @select="handleSopSelect"
  120. @clear="handleSopClear"
  121. :trigger-on-focus="false"
  122. >
  123. <template slot-scope="{ item }">
  124. <div class="sop-item">
  125. <span class="sop-name">{{ item.name }}</span>
  126. </div>
  127. </template>
  128. </el-autocomplete>
  129. </el-form-item>
  130. <!-- 营期时间 -->
  131. <!-- <el-form-item label="营期时间" prop="scheduleTime">
  132. <el-input
  133. v-model="scheduleTimeText"
  134. placeholder="请选择营期时间"
  135. readonly
  136. @click.native="showScheduleCalendar = true"
  137. />
  138. <calendar
  139. v-model="scheduleTime"
  140. mode="during"
  141. :show.sync="showScheduleCalendar"
  142. @change="handleScheduleTimeChange"
  143. :key="scheduleCalendarKey"
  144. />
  145. </el-form-item>-->
  146. <el-form-item label="营期时间" prop="scheduleTime">
  147. <el-date-picker
  148. v-model="scheduleTimeText"
  149. type="daterange"
  150. range-separator="至"
  151. start-placeholder="开始日期"
  152. end-placeholder="结束日期"
  153. value-format="yyyy-MM-dd"
  154. style="width: 240px"
  155. @change="handleScheduleTimeChange"
  156. />
  157. </el-form-item>
  158. <!-- 创建时间 -->
  159. <!-- <el-form-item label="创建时间" prop="createTime">
  160. <el-input
  161. v-model="createTimeText"
  162. placeholder="请选择创建时间"
  163. readonly
  164. @click.native="showCreateCalendar = true"
  165. />
  166. <calendar
  167. v-model="createTime"
  168. mode="during"
  169. :show.sync="showCreateCalendar"
  170. @change="createChange"
  171. :key="createCalendarKey"
  172. />
  173. </el-form-item> -->
  174. <el-form-item label="创建时间" prop="createTime">
  175. <el-date-picker
  176. v-model="createTimeText"
  177. type="daterange"
  178. range-separator="至"
  179. start-placeholder="开始日期"
  180. end-placeholder="结束日期"
  181. value-format="yyyy-MM-dd"
  182. style="width: 240px"
  183. @change="createChange"
  184. />
  185. </el-form-item>
  186. <!-- 最新更新时间 -->
  187. <!-- <el-form-item label="最新更新时间" prop="updateTime">
  188. <el-input
  189. v-model="updateTimeText"
  190. placeholder="请选择更新时间"
  191. readonly
  192. @click.native="showUpdateCalendar = true"
  193. />
  194. <calendar
  195. v-model="updateTime"
  196. mode="during"
  197. :show.sync="showUpdateCalendar"
  198. @change="updateChange"
  199. :key="updateCalendarKey"
  200. />
  201. </el-form-item> -->
  202. <el-form-item label="最新更新时间" prop="updateTime">
  203. <el-date-picker
  204. v-model="updateTimeText"
  205. type="daterange"
  206. range-separator="至"
  207. start-placeholder="开始日期"
  208. end-placeholder="结束日期"
  209. value-format="yyyy-MM-dd"
  210. style="width: 240px"
  211. @change="updateChange"
  212. />
  213. </el-form-item>
  214. <!-- 进线时间 -->
  215. <!-- <el-form-item label="进线时间" prop="qecCreateTime">
  216. <el-input
  217. v-model="qecCreateTimeText"
  218. placeholder="请选择进线时间"
  219. readonly
  220. @click.native="showQecCalendar = true"
  221. />
  222. <calendar
  223. v-model="qecCreateTime"
  224. mode="during"
  225. :show.sync="showQecCalendar"
  226. @change="qecCreateTimeChange"
  227. :key="qecCalendarKey"
  228. />
  229. </el-form-item> -->
  230. <el-form-item label="进线时间" prop="qecCreateTime">
  231. <el-date-picker
  232. v-model="qecCreateTimeText"
  233. type="daterange"
  234. range-separator="至"
  235. start-placeholder="开始日期"
  236. end-placeholder="结束日期"
  237. value-format="yyyy-MM-dd"
  238. style="width: 240px"
  239. @change="qecCreateTimeChange"
  240. />
  241. </el-form-item>
  242. <el-form-item label="营期课程时间" prop="periodTime" v-if="queryParams.sendType==1">
  243. <el-date-picker
  244. v-model="periodTimeText"
  245. type="datetimerange"
  246. align="right"
  247. unlink-panels
  248. value-format="yyyy-MM-dd HH:mm:ss"
  249. range-separator="至"
  250. start-placeholder="开始日期"
  251. end-placeholder="结束日期"
  252. :picker-options="pickerOptions"
  253. @change="qecPeriodTimeChange"
  254. :default-time="['00:00:00', '23:59:59']">
  255. </el-date-picker>
  256. </el-form-item>
  257. <el-form-item label="是否注册" prop="isVip">
  258. <el-select
  259. filterable
  260. v-model="queryParams.isVip"
  261. placeholder="请选择是否注册"
  262. clearable size="small">
  263. <el-option
  264. v-for="dict in isVipList"
  265. :key="dict.dictValue"
  266. :label="dict.dictLabel"
  267. :value="dict.dictValue"
  268. />
  269. </el-select>
  270. </el-form-item>
  271. <el-form-item>
  272. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  273. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  274. </el-form-item>
  275. </el-form>
  276. <el-row :gutter="10" class="mb8">
  277. <el-col :span="1.5">
  278. <el-button
  279. type="warning"
  280. plain
  281. icon="el-icon-download"
  282. size="mini"
  283. :loading="exportLoading"
  284. @click="handleExport"
  285. v-hasPermi="['course:courseWatchLog:export']"
  286. >导出</el-button>
  287. <el-col :span="1.5" v-if="queryParams.sendType == 2">
  288. <el-button
  289. type="primary"
  290. plain
  291. size="mini"
  292. @click="addUserTag"
  293. v-hasPermi="['qw:externalContact:addTag']"
  294. >批量添加标签</el-button>
  295. </el-col>
  296. <el-col :span="1.5" v-if="queryParams.sendType == 2" >
  297. <el-button
  298. type="primary"
  299. plain
  300. size="mini"
  301. @click="delUserTag"
  302. v-hasPermi="['qw:externalContact:delTag']"
  303. >批量移除标签</el-button>
  304. </el-col>
  305. </el-col>
  306. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  307. </el-row>
  308. <el-tabs type="card" v-model="activeName" @tab-click="handleClickX">
  309. <el-tab-pane label="全部" name="00"></el-tab-pane>
  310. <el-tab-pane v-for="(item,index) in logTypeOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
  311. </el-tabs>
  312. <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">
  313. <el-table-column type="selection" width="55" align="center" />
  314. <el-table-column label="记录编号" align="center" prop="logId" />
  315. <el-table-column label="用户昵称" align="center">
  316. <template slot-scope="scope">
  317. {{ queryParams.sendType=='1' ? scope.row.fsNickName : scope.row.externalUserName }}
  318. </template>
  319. </el-table-column>
  320. <el-table-column label="头像" align="center">
  321. <template slot-scope="scope">
  322. <img v-if="queryParams.sendType=='1'" :src="scope.row.fsAvatar" style="width:50px;height:50px" />
  323. <img v-else :src="scope.row.externalUserAvatar" style="width:50px;height:50px" />
  324. </template>
  325. </el-table-column>
  326. <el-table-column label="会员ID" align="center" prop="userId" />
  327. <el-table-column label="会员昵称" align="center" prop="fsNickName">
  328. <template slot-scope="scope">
  329. <div style="display: flex;white-space: nowrap">
  330. <div style="margin: auto">
  331. {{scope.row.fsNickName}}
  332. </div>
  333. <el-popover
  334. placement="right"
  335. title=""
  336. trigger="hover">
  337. <img slot="reference" :src="scope.row.fsAvatar" style="width: 30px;height: 30px">
  338. <img :src="scope.row.fsAvatar" style="max-width: 200px;max-height: 200px">
  339. </el-popover>
  340. </div>
  341. </template>
  342. </el-table-column>
  343. <el-table-column label="营期名称" align="center" prop="periodIdName" v-if="this.queryParams.sendType==1" />
  344. <el-table-column label="课程名称" align="center" prop="courseName" />
  345. <el-table-column label="小节名称" align="center" prop="videoName" />
  346. <el-table-column label="记录类型" align="center" prop="logType">
  347. <template slot-scope="scope">
  348. <dict-tag :options="logTypeOptions" :value="scope.row.logType"/>
  349. </template>
  350. </el-table-column>
  351. <el-table-column label="播放时长" align="center" prop="duration" />
  352. <el-table-column label="所属销售" align="center" prop="companyUserName" />
  353. <!-- <el-table-column label="所属公司" align="center" prop="companyName" />-->
  354. <el-table-column label="所属企微" align="center" prop="qwUserName" v-if="queryParams.sendType==2" />
  355. <!-- <el-table-column label="所属发送方式" align="center" prop="sendType" />-->
  356. <el-table-column label="创建时间" align="center" prop="createTime" />
  357. <el-table-column label="更新时间" align="center" prop="updateTime" />
  358. <el-table-column label="完课时间" align="center" prop="finishTime" />
  359. <el-table-column label="营期时间" align="center" prop="campPeriodTime" />
  360. <el-table-column label="进线时间" align="center" prop="qecCreateTime" />
  361. <el-table-column
  362. fixed="right"
  363. label="操作"
  364. width="100">
  365. <template slot-scope="scope">
  366. <el-button @click="openAnswerLogFun(scope.row)" type="text" size="small">答题记录</el-button>
  367. <el-button @click="openRedLogFun(scope.row)" type="text" size="small">红包记录</el-button>
  368. </template>
  369. </el-table-column>
  370. </el-table>
  371. <pagination
  372. v-show="total>0"
  373. :total="total"
  374. :page.sync="queryParams.pageNum"
  375. :limit.sync="queryParams.pageSize"
  376. @pagination="getList"
  377. />
  378. <el-drawer title="答题记录" :visible.sync="openAnswerLog" size="70%" append-to-body>
  379. <el-table border v-loading="" :data="answerLogsList">
  380. <el-table-column label="会员用户" align="center" prop="userName">
  381. <template slot-scope="scope">
  382. <div style="display: flex;white-space: nowrap">
  383. <div style="margin: auto">
  384. {{ scope.row.userName }}
  385. </div>
  386. <el-popover
  387. placement="right"
  388. title=""
  389. trigger="hover">
  390. <img slot="reference" :src="scope.row.fsAvatar" style="width: 30px;height: 30px">
  391. <img :src="scope.row.fsAvatar" style="max-width: 200px;max-height: 200px">
  392. </el-popover>
  393. </div>
  394. </template>
  395. </el-table-column>
  396. <el-table-column label="课程名称" align="center" prop="courseName"/>
  397. <el-table-column label="小节名称" align="center" prop="videoName"/>
  398. <el-table-column label="是否全部正确" align="center" prop="isRight">
  399. <template slot-scope="scope">
  400. <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>
  401. </template>
  402. </el-table-column>
  403. <el-table-column label="销售名称" align="center" prop="companyUserName"/>
  404. <el-table-column label="企微员工名称" align="center" prop="qwUserName"/>
  405. <el-table-column label="公司名称" align="center" prop="companyName"/>
  406. <el-table-column label="创建时间" align="center" prop="createTime"/>
  407. </el-table>
  408. <pagination
  409. v-show="answerLogTotal>0"
  410. :total="answerLogTotal"
  411. :page.sync="answerLogQueryParams.pageNum"
  412. :limit.sync="answerLogQueryParams.pageSize"
  413. @pagination="answerLogList"
  414. />
  415. </el-drawer>
  416. <el-drawer title="红包记录" :visible.sync="openRedLog" size="70%" append-to-body>
  417. <el-table border v-loading="" :data="redLogsList">
  418. <el-table-column type="selection" width="55" align="center" />
  419. <el-table-column label="记录编号" align="center" prop="logId" />
  420. <el-table-column label="批次单号" align="center" prop="outBatchNo" />
  421. <el-table-column label="课程名称" align="center" prop="courseId" >
  422. <template slot-scope="scope">
  423. <span prop="status" v-for="(item, index) in courseLists" v-if="scope.row.courseId==item.dictValue">{{item.dictLabel}}</span>
  424. </template>
  425. </el-table-column>
  426. <el-table-column label="小节名称" align="center" prop="title" />
  427. <!-- <el-table-column label="会员id" align="center" prop="userId" />-->
  428. <el-table-column label="会员用户" align="center" prop="fsNickName">
  429. <template slot-scope="scope">
  430. <div style="display: flex;white-space: nowrap">
  431. <div style="margin: auto">
  432. {{scope.row.fsNickName}}
  433. </div>
  434. <el-popover
  435. placement="right"
  436. title=""
  437. trigger="hover">
  438. <img slot="reference" :src="scope.row.fsAvatar" style="width: 30px;height: 30px">
  439. <img :src="scope.row.fsAvatar" style="max-width: 200px;max-height: 200px">
  440. </el-popover>
  441. </div>
  442. </template>
  443. </el-table-column>
  444. <!-- <el-table-column label="会员电话" align="center" prop="phone" />-->
  445. <!-- <el-table-column label="所属销售" align="center" prop="companyUserName" />-->
  446. <!-- <el-table-column label="所属公司" align="center" prop="companyName" />-->
  447. <el-table-column label="转帐金额" align="center" prop="amount" />
  448. <el-table-column label="状态" align="center" prop="status" >
  449. <template slot-scope="scope">
  450. <el-tag>
  451. {{
  452. scope.row.status === 0 ? "发送中" :
  453. scope.row.status === 2 ? "待补发" :
  454. "已完成"
  455. }}
  456. </el-tag>
  457. </template>
  458. </el-table-column>
  459. <el-table-column label="所属企微" align="center" prop="qwUserName" />
  460. <el-table-column label="创建时间" align="center" prop="createTime" />
  461. </el-table>
  462. <pagination
  463. v-show="redLogTotal>0"
  464. :total="redLogTotal"
  465. :page.sync="redLogQueryParams.pageNum"
  466. :limit.sync="redLogQueryParams.pageSize"
  467. @pagination="redLogList"
  468. />
  469. </el-drawer>
  470. <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
  471. <div>搜索标签:
  472. <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
  473. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
  474. <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
  475. </div>
  476. <el-form ref="form" :model="addTagFormByWatch" label-width="80px">
  477. <div v-for="item in tagGroupList" :key="item.id" >
  478. <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
  479. <span class="name-background">{{ item.name }}</span>
  480. </div>
  481. <!-- 添加外层滚动容器 -->
  482. <div class="scroll-wrapper">
  483. <div class="tag-container">
  484. <a
  485. v-for="tagItem in item.tag"
  486. class="tag-box"
  487. @click="tagSelection(tagItem)"
  488. :class="{ 'tag-selected': tagItem.isSelected }"
  489. >
  490. {{ tagItem.name }}
  491. </a>
  492. </div>
  493. </div>
  494. <!-- <div class="tag-container">-->
  495. <!-- <a-->
  496. <!-- v-for="tagItem in item.tag"-->
  497. <!-- class="tag-box"-->
  498. <!-- @click="tagSelection(tagItem)"-->
  499. <!-- :class="{ 'tag-selected': tagItem.isSelected }"-->
  500. <!-- >-->
  501. <!-- {{ tagItem.name }}-->
  502. <!-- </a>-->
  503. <!-- </div>-->
  504. </div>
  505. </el-form>
  506. <pagination
  507. v-show="tagTotal>0"
  508. :total="tagTotal"
  509. :page.sync="queryTagParams.pageNum"
  510. :limit.sync="queryTagParams.pageSize"
  511. @pagination="getPageListTagGroup"
  512. />
  513. <div slot="footer" class="dialog-footer">
  514. <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
  515. <el-button @click="addTagCancel">取 消</el-button>
  516. </div>
  517. </el-dialog>
  518. <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
  519. <div>搜索标签:
  520. <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
  521. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
  522. <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
  523. </div>
  524. <el-form ref="form" :model="addTagFormByWatch" label-width="80px">
  525. <div v-for="item in tagGroupList" :key="item.id" >
  526. <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
  527. <span class="name-background">{{ item.name }}</span>
  528. </div>
  529. <!-- 添加外层滚动容器 -->
  530. <div class="scroll-wrapper">
  531. <div class="tag-container">
  532. <a
  533. v-for="tagItem in item.tag"
  534. class="tag-box"
  535. @click="tagSelection(tagItem)"
  536. :class="{ 'tag-selected': tagItem.isSelected }"
  537. >
  538. {{ tagItem.name }}
  539. </a>
  540. </div>
  541. </div>
  542. </div>
  543. </el-form>
  544. <pagination
  545. v-show="tagTotal>0"
  546. :total="tagTotal"
  547. :page.sync="queryTagParams.pageNum"
  548. :limit.sync="queryTagParams.pageSize"
  549. @pagination="getPageListTagGroup"
  550. />
  551. <div slot="footer" class="dialog-footer">
  552. <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
  553. <el-button @click="DelTagCancel">取 消</el-button>
  554. </div>
  555. </el-dialog>
  556. <el-dialog
  557. :title="resultTitle"
  558. :visible.sync="resultDialogVisible"
  559. width="50%"
  560. custom-class="feedback-dialog"
  561. >
  562. <pre style="white-space: pre-wrap; font-family: inherit;">{{ resultMessage }}</pre>
  563. <span slot="footer" class="dialog-footer">
  564. <el-button @click="resultDialogVisible = false">关闭</el-button>
  565. </span>
  566. </el-dialog>
  567. </div>
  568. </template>
  569. <script>
  570. import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
  571. import {courseList, listCourseRedPacketLog, videoList} from '@/api/course/courseRedPacketLog'
  572. import {listLogs} from "@/api/course/courseAnswerlogs";
  573. import {allListTagGroup} from "../../../api/qw/tagGroup";
  574. import {searchTags} from "../../../api/qw/tag";
  575. import {addTagByWatch, delTagByWatch} from "../../../api/qw/externalContact";
  576. import Vue from 'vue'
  577. import Calendar from 'vue-mobile-calendar'
  578. import {infoSop} from "@/api/qw/sop";
  579. import {getCompanyUserListLikeName} from "../../../api/company/companyUser";
  580. import {getQwList} from "@/api/qw/qwUser";
  581. Vue.use(Calendar)
  582. export default {
  583. name: "CourseWatchLog",
  584. data() {
  585. return {
  586. companyName:process.env.VUE_APP_COURSE_COMPANY_NAME,
  587. // 日历 key 控制刷新
  588. scheduleCalendarKey: 0,
  589. createCalendarKey: 0,
  590. updateCalendarKey: 0,
  591. qecCalendarKey: 0,
  592. periodTimeKey: 0,
  593. createTimeText: '',
  594. scheduleTimeText: '', // 新增
  595. updateTimeText: '', // 新增
  596. qecCreateTimeText: '', // 新增
  597. periodTimeText: '', // 营期课程时间
  598. scheduleTime: [], // 改为数组
  599. createTime: [], // 改为数组
  600. updateTime: [], // 改为数组
  601. qecCreateTime: [], // 改为数组
  602. periodTime: [], // 改为数组
  603. // 控制日历显隐
  604. showScheduleCalendar: false,
  605. showCreateCalendar: false,
  606. showUpdateCalendar: false,
  607. showQecCalendar: false,
  608. resultDialogVisible: false,
  609. resultMessage: '',
  610. resultTitle:'',
  611. activeName:"2",
  612. pickerOptions: {
  613. disabledDate(time) {
  614. // 获取13天前的日期(加上今天就是14天)
  615. const sixDaysAgo = new Date();
  616. sixDaysAgo.setDate(sixDaysAgo.getDate() - 13);
  617. sixDaysAgo.setHours(0, 0, 0, 0);
  618. // 获取明天的日期(不包括今天)
  619. const tomorrow = new Date();
  620. tomorrow.setDate(tomorrow.getDate() + 1);
  621. tomorrow.setHours(0, 0, 0, 0);
  622. return time.getTime() < sixDaysAgo.getTime() || time.getTime() >= tomorrow.getTime();
  623. }
  624. },
  625. courseLists:[],
  626. videoList:[],
  627. logTypeOptions:[],
  628. projectOptions:[],
  629. sendTypeOptions:[{
  630. dictLabel:"会员",dictValue:'1'
  631. },
  632. {
  633. dictLabel:"企微",dictValue:'2'
  634. }
  635. ],
  636. // 遮罩层
  637. loading: true,
  638. // 导出遮罩层
  639. exportLoading: false,
  640. // 选中数组
  641. ids: [],
  642. // 非单个禁用
  643. single: true,
  644. // 非多个禁用
  645. multiple: true,
  646. // 显示搜索条件
  647. showSearch: true,
  648. // 总条数
  649. total: 0,
  650. // 短链课程看课记录表格数据
  651. courseWatchLogList: [],
  652. // 弹出层标题
  653. title: "",
  654. // 是否显示弹出层
  655. open: false,
  656. tagOpen:false,
  657. //标签弹窗选择
  658. tagChange:{
  659. open:false,
  660. index:null,
  661. },
  662. addTagFormByWatch:{
  663. logId:[],
  664. tagIds:[]
  665. },
  666. tagGroupList: [],
  667. tagTotal:0,
  668. tagDelOpen:false,
  669. queryTagParams:{
  670. pageNum: 1,
  671. pageSize: 5,
  672. total:0,
  673. name:null,
  674. corpId:null,
  675. },
  676. //答题记录
  677. openAnswerLog: false,
  678. loadingAnswerLog: true,
  679. answerLogsList: [],
  680. answerLogTotal: 0,
  681. answerLogQueryParams: {
  682. pageNum: 1,
  683. pageSize: 10,
  684. },
  685. //红包记录
  686. openRedLog: false,
  687. loadingRedLog: true,
  688. redLogsList: [],
  689. redLogTotal: 0,
  690. redLogQueryParams: {
  691. pageNum: 1,
  692. pageSize: 10,
  693. },
  694. isVipList: [
  695. { dictLabel: '是', dictValue: 1 },
  696. { dictLabel: '否', dictValue: 0 }
  697. ],
  698. // SOP搜索相关
  699. sopSearchText: '', // SOP搜索框显示的文本
  700. selectedSopId: null, // 选中的SOP ID
  701. // 查询参数
  702. queryParams: {
  703. pageNum: 1,
  704. pageSize: 10,
  705. project: null,
  706. userId: null,
  707. nickName: null,
  708. videoId: null,
  709. logType: 2,
  710. qwExternalContactId: null,
  711. externalUserName:null,
  712. duration: null,
  713. qwUserId: null,
  714. qwUserName: null,
  715. companyUserId: null,
  716. companyId: null,
  717. courseId: null,
  718. sTime:null,
  719. eTime:null,
  720. upSTime:null,
  721. upETime:null,
  722. qecSTime:null,
  723. qecETime:null,
  724. periodSTime:null,
  725. periodETime:null,
  726. scheduleStartTime: null,
  727. scheduleEndTime: null,
  728. sendType:process.env.VUE_APP_COURSE_DEFAULT,
  729. isVip: null,
  730. sopId: null, // sopId
  731. },
  732. // 表单参数
  733. form: {},
  734. // 表单校验
  735. rules: {
  736. },
  737. // 员工选项列表
  738. companyUserOptionsParams: {
  739. name: undefined,
  740. hasNextPage: false,
  741. pageNum: 1,
  742. pageSize: 200
  743. },
  744. companyUserOptions: [],
  745. companyUserOptionsByAll: [],
  746. companyUserOptionsLoading: false,
  747. // 企微信息
  748. qwUserOptions: [],
  749. // 员工选项列表
  750. qwUserOptionsParams: {
  751. name: undefined,
  752. hasNextPage: false,
  753. pageNum: 1,
  754. pageSize: 10
  755. },
  756. qwUserOptionsLoading: false,
  757. };
  758. },
  759. created() {
  760. courseList().then(response => {
  761. this.courseLists = response.list;
  762. });
  763. this.getList();
  764. this.getDicts("sys_course_watch_log_type").then(response => {
  765. this.logTypeOptions = response.data;
  766. });
  767. this.getDicts("sys_course_project").then(response => {
  768. this.projectOptions = response.data;
  769. });
  770. this.getCompanyUserListLikeName(true);
  771. },
  772. methods: {
  773. /**
  774. * 根据名称模糊查询用户列表
  775. * @param query 参数
  776. */
  777. loadCompanyUserOptions(query) {
  778. this.companyUserOptions = [];
  779. if (query === '') {
  780. return;
  781. }
  782. this.companyUserOptionsParams.pageNum = 1
  783. this.companyUserOptionsParams.name = query
  784. this.companyUserOptionsLoading = true;
  785. this.getCompanyUserListLikeName()
  786. },
  787. /**
  788. * 根据条件查询企微列表
  789. * @param query 参数
  790. */
  791. loadQwUserOptions(query) {
  792. this.qwUserOptions = [];
  793. if (query === '') {
  794. return;
  795. }
  796. this.qwUserOptionsParams.pageNum = 1
  797. // 将搜索关键词设置到queryParams中
  798. this.queryParams.qwUserName = query
  799. this.qwUserOptionsLoading = true;
  800. this.getQwList()
  801. },
  802. /**
  803. * 加载更多员工选项
  804. */
  805. loadMoreCompanyUserOptions() {
  806. if (!this.companyUserOptionsParams.hasNextPage) {
  807. return;
  808. }
  809. this.companyUserOptionsParams.pageNum += 1
  810. this.getCompanyUserListLikeName()
  811. },
  812. /**
  813. * 获取员工列表
  814. */
  815. getCompanyUserListLikeName(isAll) {
  816. if (isAll){
  817. getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
  818. this.companyUserOptionsByAll = [...this.companyUserOptions, ...response.data.list]
  819. this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
  820. this.companyUserOptionsLoading = false;
  821. });
  822. }else {
  823. getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
  824. this.companyUserOptions = [...this.companyUserOptions, ...response.data.list]
  825. this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
  826. this.companyUserOptionsLoading = false;
  827. });
  828. }
  829. },
  830. getQwList() {
  831. console.log("企微参数", this.queryParams);
  832. getQwList(this.queryParams).then(response => {
  833. this.qwUserOptions = [...this.qwUserOptions, ...response.rows]
  834. // 根据实际返回的数据结构设置hasNextPage
  835. this.qwUserOptionsParams.hasNextPage = response.rows && response.rows.length >= this.qwUserOptionsParams.pageSize
  836. this.qwUserOptionsLoading = false;
  837. });
  838. },
  839. /**
  840. * 加载更多员工选项
  841. */
  842. loadMoreQwUserOptions() {
  843. if (!this.qwUserOptionsParams.hasNextPage) {
  844. return;
  845. }
  846. this.qwUserOptionsParams.pageNum += 1
  847. this.getQwList()
  848. },
  849. // 重置日历组件
  850. resetCalendars() {
  851. this.scheduleTime = [];
  852. this.createTime = [];
  853. this.updateTime = [];
  854. this.qecCreateTime = [];
  855. this.periodTime = [];
  856. this.scheduleTimeText = [];
  857. this.createTimeText = [];
  858. this.updateTimeText = [];
  859. this.qecCreateTimeText = [];
  860. this.periodTimeText = [];
  861. // 强制刷新日历组件
  862. this.scheduleCalendarKey++;
  863. this.createCalendarKey++;
  864. this.updateCalendarKey++;
  865. this.qecCalendarKey++;
  866. this.periodTimeKey++;
  867. },
  868. formatDateRange(dates) {
  869. if (!dates || dates.length < 2) return '';
  870. return dates.map(date => date.format('YYYY-MM-DD')).join(' ~ ');
  871. },
  872. courseChange(row){
  873. this.queryParams.videoId=null;
  874. if(row === ''){
  875. this.videoList=[];
  876. return
  877. }
  878. videoList(row).then(response => {
  879. this.videoList=response.list
  880. });
  881. },
  882. // 营期时间
  883. handleScheduleTimeChange(scheduleTime) {
  884. if (scheduleTime && scheduleTime.length >= 2) {
  885. // this.scheduleTimeText = this.formatDateRange(scheduleTime);
  886. this.queryParams.scheduleStartTime = scheduleTime[0] || null;
  887. this.queryParams.scheduleEndTime = scheduleTime[1] || null;
  888. console.log(this.queryParams.scheduleStartTime)
  889. console.log(this.queryParams.scheduleEndTime)
  890. } else {
  891. this.scheduleTimeText = '';
  892. this.queryParams.scheduleStartTime = null;
  893. this.queryParams.scheduleEndTime = null;
  894. }
  895. },
  896. // 创建时间
  897. createChange(createTime) {
  898. if (createTime && createTime.length >= 2) {
  899. // this.createTimeText = this.formatDateRange(createTime);
  900. this.queryParams.sTime = createTime[0] || null;
  901. this.queryParams.eTime = createTime[1] || null;
  902. } else {
  903. this.createTimeText = '';
  904. this.queryParams.sTime = null;
  905. this.queryParams.eTime = null;
  906. }
  907. },
  908. // 更新时间
  909. updateChange(updateTime) {
  910. if (updateTime && updateTime.length >= 2) {
  911. // this.updateTimeText = this.formatDateRange(updateTime);
  912. this.queryParams.upSTime = updateTime[0] || null;
  913. this.queryParams.upETime = updateTime[1] || null;
  914. } else {
  915. this.updateTimeText = '';
  916. this.queryParams.upSTime = null;
  917. this.queryParams.upETime = null;
  918. }
  919. },
  920. // 进线时间
  921. qecCreateTimeChange(qecCreateTime) {
  922. if (qecCreateTime && qecCreateTime.length >= 2) {
  923. // 检查选择的日期范围是否超过7天(包括起始和结束日期)
  924. const startDate = new Date(qecCreateTime[0]);
  925. const endDate = new Date(qecCreateTime[1]);
  926. // 设置时间为当天开始,避免时间部分影响计算
  927. startDate.setHours(0, 0, 0, 0);
  928. endDate.setHours(0, 0, 0, 0);
  929. const timeDiff = Math.abs(endDate - startDate);
  930. const diffDays = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
  931. // 如果超过6天的范围(总共7天,包括起始日)
  932. if (diffDays > 6) {
  933. this.$message.error('进线时间选择范围不能超过7天');
  934. // 清空选择
  935. this.qecCreateTime = [];
  936. this.qecCreateTimeText = [];
  937. this.queryParams.qecSTime = null;
  938. this.queryParams.qecETime = null;
  939. this.qecCalendarKey++;
  940. return;
  941. }
  942. // this.qecCreateTimeText = this.formatDateRange(qecCreateTime);
  943. this.queryParams.qecSTime = qecCreateTime[0] || null;
  944. this.queryParams.qecETime = qecCreateTime[1] || null;
  945. console.log(this.queryParams.qecSTime);
  946. console.log(this.queryParams.qecETime);
  947. } else {
  948. this.qecCreateTimeText = '';
  949. this.queryParams.qecSTime = null;
  950. this.queryParams.qecETime = null;
  951. }
  952. },
  953. //营期课程时间
  954. qecPeriodTimeChange(periodTime){
  955. if (periodTime && periodTime.length >= 2) {
  956. // 检查选择的日期范围是否超过7天(包括起始和结束日期)
  957. const startDate = new Date(periodTime[0]);
  958. const endDate = new Date(periodTime[1]);
  959. // 设置时间为当天开始,避免时间部分影响计算
  960. startDate.setHours(0, 0, 0, 0);
  961. endDate.setHours(0, 0, 0, 0);
  962. const timeDiff = Math.abs(endDate - startDate);
  963. const diffDays = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
  964. // 如果超过6天的范围(总共7天,包括起始日)
  965. if (diffDays > 13) {
  966. this.$message.error('时间选择范围不能超过14天');
  967. // 清空选择
  968. this.periodTime = [];
  969. this.periodTimeText = [];
  970. this.queryParams.periodSTime = null;
  971. this.queryParams.periodETime = null;
  972. this.periodTimeKey++;
  973. return;
  974. }
  975. this.queryParams.periodSTime = this.formatDate(periodTime[0]) || null;
  976. this.queryParams.periodETime = this.formatDate(periodTime[1]) || null;
  977. } else {
  978. this.periodTimeText = '';
  979. this.queryParams.periodSTime = null;
  980. this.queryParams.periodETime = null;
  981. }
  982. },
  983. formatDate(date) {
  984. if (!date) return ''
  985. // 确保 date 是 Date 对象
  986. let dateObj = date
  987. if (typeof date === 'string') {
  988. dateObj = new Date(date)
  989. }
  990. // 如果转换失败,返回空字符串
  991. if (!(dateObj instanceof Date) || isNaN(dateObj.getTime())) {
  992. return ''
  993. }
  994. // 使用更安全的格式化方法
  995. const year = dateObj.getFullYear()
  996. const month = String(dateObj.getMonth() + 1).padStart(2, '0')
  997. const day = String(dateObj.getDate()).padStart(2, '0')
  998. const hours = String(dateObj.getHours()).padStart(2, '0')
  999. const minutes = String(dateObj.getMinutes()).padStart(2, '0')
  1000. const seconds = String(dateObj.getSeconds()).padStart(2, '0')
  1001. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  1002. },
  1003. handleClickX(tab,event){
  1004. this.activeName=tab.name;
  1005. if(tab.name=="00"){
  1006. this.queryParams.logType=null;
  1007. }else{
  1008. this.queryParams.logType=tab.name;
  1009. }
  1010. this.getList()
  1011. },
  1012. /** 查询短链课程看课记录列表 */
  1013. getList() {
  1014. this.loading = true;
  1015. if(this.queryParams.logType == "10"){
  1016. this.queryParams.logType = null;
  1017. }
  1018. listCourseWatchLog(this.queryParams).then(response => {
  1019. this.courseWatchLogList = response.rows;
  1020. this.total = response.total;
  1021. this.loading = false;
  1022. });
  1023. },
  1024. // 取消按钮
  1025. cancel() {
  1026. this.open = false;
  1027. this.reset();
  1028. },
  1029. // 表单重置
  1030. reset() {
  1031. this.form = {
  1032. logId: null,
  1033. userId: null,
  1034. videoId: null,
  1035. logType: null,
  1036. createTime: null,
  1037. updateTime: null,
  1038. qwExternalContactId: null,
  1039. externalUserName:null,
  1040. duration: null,
  1041. qwUserId: null,
  1042. companyUserId: null,
  1043. companyId: null,
  1044. courseId: null,
  1045. sTime:null,
  1046. eTime:null,
  1047. upSTime:null,
  1048. upETime:null,
  1049. qecSTime:null,
  1050. qecETime:null,
  1051. scheduleStartTime: null,
  1052. scheduleEndTime: null,
  1053. };
  1054. // 统一重置日历组件
  1055. this.resetCalendars();
  1056. this.resetForm("form");
  1057. },
  1058. /** 搜索按钮操作 */
  1059. handleQuery() {
  1060. this.queryParams.pageNum = 1;
  1061. this.getList();
  1062. },
  1063. /** 重置按钮操作 */
  1064. resetQuery() {
  1065. this.resetForm("queryForm");
  1066. this.queryParams.sTime = null;
  1067. this.queryParams.project = null;
  1068. this.queryParams.eTime = null;
  1069. this.queryParams.upSTime = null;
  1070. this.queryParams.upETime = null;
  1071. this.queryParams.qecSTime = null;
  1072. this.queryParams.qecETime = null;
  1073. this.queryParams.periodSTime = null;
  1074. this.queryParams.periodDTime = null;
  1075. this.queryParams.scheduleStartTime = null;
  1076. this.queryParams.scheduleEndTime = null;
  1077. this.queryParams.sopId = null; // 重置SOP ID
  1078. // 重置SOP搜索
  1079. this.handleSopClear();
  1080. // 统一重置日历组件
  1081. this.resetCalendars();
  1082. this.handleQuery();
  1083. },
  1084. // 多选框选中数据
  1085. handleSelectionChange(selection) {
  1086. this.ids = selection.map(item => item.logId)
  1087. this.single = selection.length!==1
  1088. this.multiple = !selection.length
  1089. },
  1090. /** 新增按钮操作 */
  1091. handleAdd() {
  1092. this.reset();
  1093. this.open = true;
  1094. this.title = "添加短链课程看课记录";
  1095. },
  1096. /** 修改按钮操作 */
  1097. handleUpdate(row) {
  1098. this.reset();
  1099. const logId = row.logId || this.ids
  1100. getCourseWatchLog(logId).then(response => {
  1101. this.form = response.data;
  1102. this.open = true;
  1103. this.title = "修改短链课程看课记录";
  1104. });
  1105. },
  1106. /** 提交按钮 */
  1107. submitForm() {
  1108. this.$refs["form"].validate(valid => {
  1109. if (valid) {
  1110. if (this.form.logId != null) {
  1111. updateCourseWatchLog(this.form).then(response => {
  1112. this.msgSuccess("修改成功");
  1113. this.open = false;
  1114. this.getList();
  1115. });
  1116. } else {
  1117. addCourseWatchLog(this.form).then(response => {
  1118. this.msgSuccess("新增成功");
  1119. this.open = false;
  1120. this.getList();
  1121. });
  1122. }
  1123. }
  1124. });
  1125. },
  1126. /** 删除按钮操作 */
  1127. handleDelete(row) {
  1128. const logIds = row.logId || this.ids;
  1129. this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
  1130. confirmButtonText: "确定",
  1131. cancelButtonText: "取消",
  1132. type: "warning"
  1133. }).then(function() {
  1134. return delCourseWatchLog(logIds);
  1135. }).then(() => {
  1136. this.getList();
  1137. this.msgSuccess("删除成功");
  1138. }).catch(() => {});
  1139. },
  1140. /** 导出按钮操作 */
  1141. handleExport() {
  1142. const queryParams = this.queryParams;
  1143. this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
  1144. confirmButtonText: "确定",
  1145. cancelButtonText: "取消",
  1146. type: "warning"
  1147. }).then(() => {
  1148. this.exportLoading = true;
  1149. return exportCourseWatchLog(queryParams);
  1150. }).then(response => {
  1151. this.download(response.msg);
  1152. this.exportLoading = false;
  1153. }).catch(() => {});
  1154. },
  1155. openAnswerLogFun(row) {
  1156. this.openAnswerLog = true;
  1157. this.answerLogQueryParams.watchLogId = row.logId;
  1158. this.answerLogList();
  1159. },
  1160. answerLogList() {
  1161. this.loadingAnswerLog = true;
  1162. listLogs(this.answerLogQueryParams).then(e => {
  1163. this.answerLogsList = e.rows;
  1164. this.answerLogTotal = e.total;
  1165. this.loadingAnswerLog = false;
  1166. })
  1167. },
  1168. openRedLogFun(row) {
  1169. this.openRedLog = true;
  1170. this.redLogQueryParams.watchLogId = row.logId;
  1171. this.redLogList();
  1172. },
  1173. redLogList() {
  1174. this.loadingRedLog = true;
  1175. console.info("-----index",this.redLogQueryParams)
  1176. listCourseRedPacketLog(this.redLogQueryParams).then(e => {
  1177. this.redLogsList = e.rows;
  1178. this.redLogTotal = e.total;
  1179. this.loadingRedLog = false;
  1180. })
  1181. },
  1182. handleSendTypeChange() {
  1183. this.handleQuery(); // 重新查询列表
  1184. },
  1185. addUserTag(){
  1186. if(this.ids==null||this.ids==""){
  1187. return this.$message('请选择需要添加标签的客户');
  1188. }
  1189. this.getPageListTagGroup();
  1190. setTimeout(() => {
  1191. for (let i = 0; i < this.tagGroupList.length; i++) {
  1192. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1193. this.tagGroupList[i].tag[x].isSelected=false;
  1194. }
  1195. }
  1196. }, 200);
  1197. this.tagOpen = true;
  1198. },
  1199. delUserTag(){
  1200. if(this.ids==null||this.ids==""){
  1201. return this.$message('请选择需要移除标签的客户');
  1202. }
  1203. this.getPageListTagGroup();
  1204. setTimeout(() => {
  1205. for (let i = 0; i < this.tagGroupList.length; i++) {
  1206. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1207. this.tagGroupList[i].tag[x].isSelected=false;
  1208. }
  1209. }
  1210. }, 200);
  1211. this.tagDelOpen = true;
  1212. },
  1213. getPageListTagGroup(){
  1214. this.queryTagParams.corpId=this.queryParams.corpId
  1215. allListTagGroup(this.queryTagParams).then(response => {
  1216. this.tagGroupList = response.rows;
  1217. this.tagTotal = response.total;
  1218. });
  1219. },
  1220. tagSelection(row){
  1221. row.isSelected= !row.isSelected;
  1222. this.$forceUpdate();
  1223. },
  1224. handleSearchTags(name){
  1225. if (!name){
  1226. return this.$message.error("请输入要搜索的标签")
  1227. }
  1228. this.queryTagParams.name=name;
  1229. this.queryTagParams.corpId=this.queryParams.corpId;
  1230. searchTags(this.queryTagParams).then(response => {
  1231. this.tagGroupList = response.rows;
  1232. });
  1233. // searchTags({name:name,corpId:this.queryParams.corpId}).then(response => {
  1234. // this.tagGroupList = response.rows;
  1235. // });
  1236. },
  1237. cancelSearchTags(){
  1238. this.resetSearchQueryTag()
  1239. this.getPageListTagGroup();
  1240. },
  1241. resetSearchQueryTag(){
  1242. this.queryTagParams= {
  1243. pageNum: 1,
  1244. pageSize: 5,
  1245. total:0,
  1246. name:null,
  1247. };
  1248. },
  1249. addTagSubmitForm(){
  1250. for (let i = 0; i < this.tagGroupList.length; i++) {
  1251. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1252. if(this.tagGroupList[i].tag[x].isSelected==true){
  1253. this.addTagFormByWatch.tagIds.push(this.tagGroupList[i].tag[x].tagId)
  1254. }
  1255. }
  1256. }
  1257. if(this.addTagFormByWatch.tagIds==[]||this.addTagFormByWatch.tagIds==null||this.addTagFormByWatch.tagIds==""){
  1258. return this.$message('请选择标签');
  1259. }
  1260. this.addTagFormByWatch.logIds=this.ids;
  1261. let loadingRock = this.$loading({
  1262. lock: true,
  1263. text: '正在执行中请稍后~~请不要刷新页面!!',
  1264. spinner: 'el-icon-loading',
  1265. background: 'rgba(0, 0, 0, 0.7)'
  1266. });
  1267. addTagByWatch(this.addTagFormByWatch).then(response => {
  1268. // this.msgSuccess(response.msg);
  1269. this.resultMessage = response.msg;
  1270. this.resultDialogVisible = true; // 显示弹窗
  1271. this.resultTitle = '批量添加标签结果';
  1272. this.tagOpen = false;
  1273. loadingRock.close();
  1274. this.addTagFormByWatch={
  1275. logIds:[],
  1276. tagIds:[]
  1277. };
  1278. this.getList()
  1279. }).finally(res=>{
  1280. loadingRock.close();
  1281. });
  1282. },
  1283. tagDelSubmitForm(){
  1284. for (let i = 0; i < this.tagGroupList.length; i++) {
  1285. for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
  1286. if(this.tagGroupList[i].tag[x].isSelected==true){
  1287. this.addTagFormByWatch.tagIds.push(this.tagGroupList[i].tag[x].tagId)
  1288. }
  1289. }
  1290. }
  1291. if(this.addTagFormByWatch.tagIds==[]||this.addTagFormByWatch.tagIds==null||this.addTagFormByWatch.tagIds==""){
  1292. return this.$message('请选择标签');
  1293. }
  1294. this.addTagFormByWatch.corpId=this.queryParams.corpId
  1295. this.addTagFormByWatch.logIds=this.ids;
  1296. let loadingRock = this.$loading({
  1297. lock: true,
  1298. text: '正在执行中请稍后~~请不要刷新页面!!',
  1299. spinner: 'el-icon-loading',
  1300. background: 'rgba(0, 0, 0, 0.7)'
  1301. });
  1302. delTagByWatch(this.addTagFormByWatch).then(response => {
  1303. // this.msgSuccess(response.msg);
  1304. this.resultMessage = response.msg;
  1305. this.resultDialogVisible = true; // 显示弹窗
  1306. this.resultTitle = '批量移除标签结果';
  1307. this.tagDelOpen = false;
  1308. loadingRock.close();
  1309. this.addTagFormByWatch={
  1310. userIds:[],
  1311. tagIds:[]
  1312. };
  1313. this.getList()
  1314. }).finally(res=>{
  1315. loadingRock.close();
  1316. });
  1317. },
  1318. addTagCancel() {
  1319. this.tagOpen = false;
  1320. this.addTagFormByWatch={
  1321. logIds:[],
  1322. tagIds:[]
  1323. };
  1324. },
  1325. DelTagCancel() {
  1326. this.tagDelOpen = false;
  1327. this.addTagFormByWatch={
  1328. logIds:[],
  1329. tagIds:[]
  1330. };
  1331. },
  1332. /**
  1333. * 异步查询SOP列表
  1334. * @param {string} queryString - 查询字符串
  1335. * @param {function} callback - 回调函数
  1336. */
  1337. querySopAsync(queryString, callback) {
  1338. if (!queryString) {
  1339. callback([]);
  1340. return;
  1341. }
  1342. infoSop({ name: queryString }).then(response => {
  1343. if (response && response.rows) {
  1344. const suggestions = response.rows.map(item => ({
  1345. value: item.name,
  1346. id: item.id,
  1347. name: item.name
  1348. }));
  1349. callback(suggestions);
  1350. } else {
  1351. callback([]);
  1352. }
  1353. }).catch(error => {
  1354. console.error('通过sop查询失败:', error);
  1355. callback([]);
  1356. });
  1357. },
  1358. /**
  1359. * 选择SOP
  1360. * @param {object} item - 选中的SOP项
  1361. */
  1362. handleSopSelect(item) {
  1363. this.selectedSopId = item.id;
  1364. this.queryParams.sopId = item.id;
  1365. this.sopSearchText = item.name;
  1366. },
  1367. /**
  1368. * 清空SOP选择
  1369. */
  1370. handleSopClear() {
  1371. this.selectedSopId = null;
  1372. this.queryParams.sopId = null;
  1373. this.sopSearchText = '';
  1374. },
  1375. }
  1376. };
  1377. </script>
  1378. <style scoped>
  1379. /* CSS 样式 */
  1380. .tag-container {
  1381. display: flex;
  1382. flex-wrap: wrap; /* 超出宽度时自动换行 */
  1383. gap: 8px; /* 设置标签之间的间距 */
  1384. }
  1385. .name-background {
  1386. display: inline-block;
  1387. background-color: #abece6; /* 背景颜色 */
  1388. padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
  1389. border-radius: 4px; /* 可选:设置圆角 */
  1390. }
  1391. /* CSS 样式 */
  1392. .tag-container {
  1393. display: flex;
  1394. flex-wrap: wrap; /* 超出宽度时自动换行 */
  1395. gap: 8px; /* 设置标签之间的间距 */
  1396. }
  1397. .name-background {
  1398. display: inline-block;
  1399. background-color: #abece6; /* 背景颜色 */
  1400. padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
  1401. border-radius: 4px; /* 可选:设置圆角 */
  1402. }
  1403. .tag-box {
  1404. padding: 8px 12px;
  1405. border: 1px solid #989797;
  1406. border-radius: 4px;
  1407. cursor: pointer;
  1408. display: inline-block;
  1409. }
  1410. .tag-selected {
  1411. background-color: #00bc98;
  1412. color: #fff;
  1413. border-color: #00bc98;
  1414. }
  1415. .el-tag + .el-tag {
  1416. margin-left: 10px;
  1417. }
  1418. /* SOP搜索框样式 */
  1419. .sop-item {
  1420. display: flex;
  1421. align-items: center;
  1422. }
  1423. .sop-name {
  1424. font-size: 14px;
  1425. color: #606266;
  1426. }
  1427. .button-new-tag {
  1428. margin-left: 10px;
  1429. height: 32px;
  1430. line-height: 30px;
  1431. padding-top: 0;
  1432. padding-bottom: 0;
  1433. }
  1434. .input-new-tag {
  1435. width: 90px;
  1436. margin-left: 10px;
  1437. vertical-align: bottom;
  1438. }
  1439. /* 新增的滚动容器样式(不影响原有样式) */
  1440. .scroll-wrapper {
  1441. max-height: 130px; /* 大约三行的高度 */
  1442. overflow-y: auto; /* 垂直滚动 */
  1443. padding-right: 5px; /* 为滚动条留出空间 */
  1444. }
  1445. /* 美化滚动条(可选) */
  1446. .scroll-wrapper::-webkit-scrollbar {
  1447. width: 6px;
  1448. }
  1449. .scroll-wrapper::-webkit-scrollbar-thumb {
  1450. background: rgba(0, 0, 0, 0.2);
  1451. border-radius: 3px;
  1452. }
  1453. </style>