index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <template>
  2. <div class="editPublishTask">
  3. <section class="main-section pubconfig">
  4. <div v-if="showEmpty">
  5. <header>
  6. <headTitle title="checklist" />
  7. </header>
  8. <div class="empty">
  9. 未设置 <span class="createBtn" @click="addAction">点击添加</span>
  10. </div>
  11. </div>
  12. <div v-else>
  13. <header>
  14. <headTitle title="checklist" :open-edit="openEdit" @editHandle="editHandle" />
  15. </header>
  16. <div class="wrap">
  17. <redTipword title="关联任务" :isedit="edit" />
  18. <multipleSelect placeholder="🔍 请输入任务名称或ID" :isedit="edit" :data="data.tasks" :task-id="taskId" @change="changeTask" />
  19. <div v-if="edit" style="margin-top: 30px">
  20. <redTipword title="选择checklist列表" :isedit="edit" />
  21. <checkboxList :selected-list="data.selectedBizTemplateIds" :data="temList" @change="updateSelectedTemHandle" />
  22. </div>
  23. </div>
  24. <div class="moduleList wrap">
  25. <redTipword v-if="!edit" title="检查项" :isedit="edit" />
  26. <div v-for="(item, index) in data.templates" :key="item.parentTemplateId">
  27. <div v-if="item.type === 1" class="item">
  28. <p :id="`s${item.parentTemplateId}`" class="title">
  29. <el-checkbox v-if="!edit" v-model="item.isCheck" :label="item.name" class="fontRest" @change="updateCheckItemHandle(item)">{{ item.name }}</el-checkbox>
  30. <span v-else class="fontName">{{ item.name }}</span>
  31. </p>
  32. <onlineCheckList
  33. :module-id="item.parentTemplateId"
  34. :isedit="edit"
  35. :styles="{ marginLeft: '24px' }"
  36. :data="item.onlineModule"
  37. :task-id="taskId"
  38. @changeSelectedHandle="changeOnlineSelectedHandle"
  39. @changeRow="changeOnlineModuleRow"
  40. @onChangeModuleName="(val, subIdx) => onChangeModuleName(val, subIdx, index)"
  41. />
  42. </div>
  43. <div v-else class="item">
  44. <p :id="`s${item.parentTemplateId}`" class="title">
  45. <el-checkbox v-if="!edit" v-model="item.isCheck" :label="item.name" class="fontRest" @change="updateCheckItemHandle(item)">{{ item.name }}</el-checkbox>
  46. <span v-else class="fontName">{{ item.name }}</span>
  47. </p>
  48. <normal-area
  49. v-if="edit"
  50. :id="'tem'+item.parentTemplateId"
  51. :value.sync="item.content"
  52. :empty-text="'点击'"
  53. :input-button="'修改模板'"
  54. :height="300"
  55. :styles="{ padding: '0 0px 20px 0px', width: '690px', marginLeft: '24px' }"
  56. />
  57. <div v-else style="margin-left: 24px" v-html="item.content" />
  58. </div>
  59. </div>
  60. </div>
  61. <div v-if="edit" class="control">
  62. <el-button size="small" @click="cancel()">取消</el-button>
  63. <el-button type="primary" size="small" @click="saveHandle()">
  64. 保存
  65. </el-button>
  66. </div>
  67. </div>
  68. </section>
  69. <div v-if="!edit">
  70. <section class="main-section">
  71. <div>
  72. <headTitle title="动态" />
  73. </div>
  74. <actionDynamic :comments="commentlist" :change-record="changeRecordList" @addComment="createCommentHandle" />
  75. </section>
  76. <div v-if="!showEmpty" id="stepWrap" class="step">
  77. <step :data="data.templates" :type-list="data.templates" @goto="scrollToHandle" />
  78. </div>
  79. </div>
  80. </div>
  81. </template>
  82. <script>
  83. const _ = require('lodash')
  84. import redTipword from '@/components/redTipTitle'
  85. import headTitle from '@/components/headTitle'
  86. import multipleSelect from './components/multipleSelect'
  87. import checkboxList from './components/checkboxList'
  88. import onlineCheckList from './components/onlineCheckList'
  89. import actionDynamic from '@/components/actionDynamic'
  90. import step from './components/step'
  91. // 富文本
  92. // import textArea from '@/components/input/textArea'
  93. import normalArea from '@/components/input/normalArea' // 富文本
  94. import 'tinymce/plugins/table'// 插入表格插件
  95. import store from '@/store'
  96. import {
  97. getCheckListBytask,
  98. getBizBindTemList,
  99. updateChecklist,
  100. createChecklist,
  101. updateTemplateCheckStatus,
  102. getCommentList,
  103. createComment,
  104. getRecordList
  105. } from '@/api/publishTask'
  106. export default {
  107. components: {
  108. redTipword,
  109. multipleSelect,
  110. checkboxList,
  111. onlineCheckList,
  112. normalArea,
  113. headTitle,
  114. actionDynamic,
  115. step
  116. },
  117. props: {
  118. taskId: {
  119. type: Number,
  120. required: true,
  121. default: -1
  122. },
  123. taskName: {
  124. type: String,
  125. required: true,
  126. default: ''
  127. },
  128. userNames: {
  129. type: String,
  130. required: true,
  131. default: ''
  132. },
  133. userInformation: {
  134. type: String,
  135. required: true,
  136. default: ''
  137. }
  138. },
  139. data() {
  140. return {
  141. description: '<p style="color:red;">123</p>',
  142. edit: false, // 是否是编辑状态
  143. showEmpty: true,
  144. openEdit: true,
  145. data: {},
  146. temList: [],
  147. commentlist: [], // 评价列表
  148. changeRecordList: [], // 变更记录列表
  149. checkListId: -1
  150. }
  151. },
  152. mounted() {
  153. // 获取模板列表
  154. this.getBizBindTemList()
  155. // 获取checklist详情
  156. this.getList()
  157. // 获取评论列表
  158. this.getCommentList()
  159. // 监听滚动条
  160. const container = document.getElementsByClassName('main-wrapper')[0]
  161. container.addEventListener('scroll', this.handleScroll) // 监听滚动事件,然后用handleScroll这个方法进行相应的处理
  162. },
  163. methods: {
  164. // 监听滚动条
  165. handleScroll() {
  166. const containerWrap = document.getElementsByClassName('main-wrapper')[0]
  167. const stepWrap = document.getElementById('stepWrap')
  168. const fullHeight = containerWrap.scrollHeight
  169. const top = containerWrap.scrollTop
  170. if (fullHeight - top <= 1000) {
  171. stepWrap.style.bottom = '450px'
  172. stepWrap.style.top = 'auto'
  173. } else {
  174. if (stepWrap.style.bottom === '450px') {
  175. stepWrap.style.bottom = 'auto'
  176. stepWrap.style.top = '150px'
  177. }
  178. }
  179. },
  180. // 获取checklist详情
  181. async getList() {
  182. if (this.taskId) {
  183. const res = await getCheckListBytask({ taskId: this.taskId })
  184. // res.data = null
  185. if (res.data) {
  186. // 如果绑定过
  187. this.showEmpty = false
  188. this.data = res.data
  189. this.checkListId = res.data.id
  190. // 获取变更记录
  191. this.getRecordList()
  192. } else {
  193. this.showEmpty = true
  194. }
  195. }
  196. },
  197. // 获取业务线下绑定的可以选checklist列表
  198. async getBizBindTemList() {
  199. const { bizId = null } = store.state.global || {}
  200. const res = await getBizBindTemList({ name: '', bizId })
  201. this.temList = res.data
  202. },
  203. async getCommentList() {
  204. const res = await getCommentList({ type: 5, joinId: this.taskId })
  205. if (res.code === 200) {
  206. this.commentlist = res.data
  207. }
  208. },
  209. // 获取变更记录
  210. async getRecordList() {
  211. const res = await getRecordList({ checkListId: this.checkListId })
  212. if (res.code === 200) {
  213. this.changeRecordList = res.data
  214. }
  215. },
  216. // 添加评论
  217. async createCommentHandle(content, callback) {
  218. const commentInfo = {
  219. joinId: this.taskId,
  220. content,
  221. type: 5,
  222. fatherId: 0,
  223. name: this.userNames,
  224. email: this.userInformation
  225. }
  226. const user = { name: this.userNames, ename: this.userInformation, id: '' }
  227. const res = await createComment({ commentInfo, user })
  228. if (res.code === 200) {
  229. this.$message({ message: '评论成功', type: 'success', duration: 1000, offset: 150 })
  230. this.getCommentList()
  231. callback()
  232. } else {
  233. this.$message.warning(res.msg)
  234. }
  235. },
  236. // 添加或者删除线上模板的模版名
  237. changeOnlineSelectedHandle(id, subIdx, value, type) {
  238. /**
  239. * id: 模块id
  240. * name: 线上模块中哪个模块下的模块名称
  241. * value: 模块名
  242. * type: 是添加还是删除
  243. **/
  244. // const tem = this.data.templates
  245. this.data.templates.map(t => {
  246. if (t.parentTemplateId === id) {
  247. if (type === 'del') {
  248. t.onlineModule.onlineOrder = t.onlineModule.onlineOrder.filter(g => g !== value)
  249. t.onlineModule.tableContent.map((t, i) => {
  250. if (i === subIdx) {
  251. t.moduleNames = t.moduleNames.filter(g => g !== value)
  252. }
  253. })
  254. } else if (!t.onlineModule.onlineOrder.includes(value)) {
  255. t.onlineModule.onlineOrder.push(value)
  256. t.onlineModule.tableContent.map((t, i) => {
  257. if (i === subIdx) {
  258. t.moduleNames.push(value)
  259. }
  260. })
  261. } else {
  262. this.$message({
  263. message: '已经添加过该模块名称',
  264. type: 'error'
  265. })
  266. }
  267. }
  268. })
  269. },
  270. changeOnlineModuleRow(type, mId, index) {
  271. this.data.templates.map(t => {
  272. if (t.parentTemplateId === mId) {
  273. if (type === 'del') {
  274. const delModuleNames = t.onlineModule.tableContent[index].moduleNames
  275. t.onlineModule.onlineOrder = t.onlineModule.onlineOrder.filter(t => !delModuleNames.includes(t))
  276. t.onlineModule.tableContent.splice(index, 1)
  277. } else {
  278. t.onlineModule.tableContent.splice(index + 1, 0, {
  279. module: '',
  280. moduleNames: []
  281. })
  282. }
  283. }
  284. })
  285. },
  286. // 保存
  287. async saveHandle() {
  288. if (this.data.tasks.length < 1) {
  289. this.$message({
  290. message: '请关联一个任务',
  291. type: 'error'
  292. })
  293. return
  294. }
  295. let res = null
  296. if (this.data.id) {
  297. res = await updateChecklist(this.data)
  298. } else {
  299. res = await createChecklist(this.data)
  300. }
  301. if (res.code === 200) {
  302. this.edit = false
  303. this.openEdit = true
  304. // 保存更新变更记录
  305. this.getRecordList()
  306. this.getList()
  307. this.$message({
  308. message: '保存成功',
  309. type: 'success'
  310. })
  311. }
  312. },
  313. // 取消
  314. cancel() {
  315. this.edit = false
  316. this.openEdit = true
  317. this.data = this.copyData
  318. if (!this.data || JSON.stringify(this.data) === '{}') {
  319. this.showEmpty = true
  320. }
  321. },
  322. // 点击添加
  323. addAction() {
  324. // 校验是否绑定过checklist模板
  325. if (!this.RegHasCheckListTem()) {
  326. return
  327. }
  328. // 复制一份数据,以便取消时复原
  329. this.copyData = this.data
  330. // 编辑按钮隐藏
  331. this.openEdit = false
  332. // 编辑状态打开
  333. this.edit = true
  334. // 是否显示空状态
  335. this.showEmpty = false
  336. this.data = {
  337. selectedBizTemplateIds: [],
  338. templates: [],
  339. tasks: [{
  340. id: this.taskId,
  341. name: this.taskName
  342. }]
  343. }
  344. // this.checkAllTem()
  345. },
  346. // 编辑
  347. editHandle() {
  348. // 校验是否绑定过checklist模板
  349. if (!this.RegHasCheckListTem()) {
  350. return
  351. }
  352. // 复制一份数据,以便取消时复原
  353. this.copyData = this.data
  354. // 编辑状态打开
  355. this.edit = true
  356. // 编辑按钮隐藏
  357. this.openEdit = false
  358. // this.checkAllTem()
  359. },
  360. // 添加和编辑checklist时 如果没有选择模版默认全选。
  361. // checkAllTem() {
  362. // const { selectedBizTemplateIds } = this.data
  363. // if (!selectedBizTemplateIds || selectedBizTemplateIds.length < 1) {
  364. // this.temList.map(t => {
  365. // this.data.selectedBizTemplateIds.push(t.id)
  366. // const { content, isCheck, name, onlineModule, type, id: parentTemplateId } = t
  367. // this.data.templates.push({
  368. // content,
  369. // isCheck,
  370. // name,
  371. // onlineModule,
  372. // type,
  373. // parentTemplateId,
  374. // belongType: 2 // checklist的模板
  375. // })
  376. // })
  377. // }
  378. // },
  379. // 校验是否该业务线有绑定checklist模板
  380. RegHasCheckListTem() {
  381. if (!this.temList || this.temList.length < 1) {
  382. this.$message({
  383. message: '该业务线暂无绑定checklist模板,请先绑定checklist模板',
  384. type: 'error'
  385. })
  386. return false
  387. } else {
  388. return true
  389. }
  390. },
  391. // 修改checklist绑定模版列表
  392. updateSelectedTemHandle(checkedIds) {
  393. const selectedBizTemplateIds = []
  394. const tems = []
  395. const newcheckedIds = []
  396. const { templates } = this.data
  397. // 循环都有哪些tem被选择了
  398. this.temList.forEach(t => {
  399. if (checkedIds.includes(t.id)) {
  400. newcheckedIds.push(t.id)
  401. }
  402. })
  403. newcheckedIds.map(checkedId => {
  404. // 先循环是否有存过模板数据
  405. this.temList.map(g => {
  406. if (g.id === checkedId) {
  407. selectedBizTemplateIds.push(g.id)
  408. const { content, isCheck, name, onlineModule, type, id: parentTemplateId } = g
  409. tems.push({
  410. content,
  411. isCheck,
  412. name,
  413. onlineModule,
  414. type,
  415. parentTemplateId,
  416. belongType: 2 // checklist的模板
  417. })
  418. }
  419. })
  420. })
  421. tems.map((h, index) => templates.map(j => {
  422. if (h.parentTemplateId === j.parentTemplateId) {
  423. tems[index] = { ...j }
  424. }
  425. }))
  426. this.data = { ...this.data, templates: tems, selectedBizTemplateIds }
  427. },
  428. // 锚点
  429. scrollToHandle(targe) {
  430. const anchorH = document.getElementById(targe).offsetTop
  431. const container = document.getElementsByClassName('main-wrapper')[0]
  432. container.scrollTop = anchorH - 30
  433. },
  434. // 解绑删除任务
  435. changeTask(task, type) {
  436. let hasTask = false
  437. let tasks = []
  438. this.data.tasks.map(g => {
  439. if (g.id === task.id) {
  440. hasTask = true
  441. }
  442. })
  443. if (type === 'del') {
  444. tasks = this.data.tasks.filter(t => t.id !== task.id)
  445. } else if (!hasTask) {
  446. tasks = [...this.data.tasks, task]
  447. } else {
  448. this.$message({
  449. message: '已经添加过该任务',
  450. type: 'error'
  451. })
  452. return
  453. }
  454. this.data = { ...this.data, tasks }
  455. },
  456. // 更新检查项到数据库
  457. async updateCheckItemHandle(item) {
  458. const { isCheck, id } = item
  459. const res = await updateTemplateCheckStatus({ isCheck, id, checkListId: this.checkListId })
  460. if (res.code === 200) {
  461. this.getRecordList()
  462. this.$message({
  463. message: '检查项状态更新成功',
  464. type: 'success'
  465. })
  466. }
  467. },
  468. // 修改线上问题模块
  469. onChangeModuleName: _.debounce(function(val, subIdx, index) {
  470. this.data.templates[index].onlineModule.tableContent[subIdx].module = val
  471. })
  472. }
  473. }
  474. </script>
  475. <style scoped lang="scss">
  476. @import '@/styles/detail-pages.scss';
  477. .editPublishTask {
  478. min-height: 400px;
  479. overflow-y: auto;
  480. padding-bottom: 20px;
  481. .step {
  482. position: fixed;
  483. top: 200px;
  484. right:150px;
  485. }
  486. .pubconfig {
  487. .control {
  488. padding: 20px 0px 20px 690px;
  489. }
  490. }
  491. .main-section {
  492. @include main-section;
  493. }
  494. .wrap{
  495. padding: 0 40px;
  496. }
  497. .moduleList {
  498. margin-top: 40px;
  499. padding-bottom: 16px;
  500. .title {
  501. font-weight: 400;
  502. color: #444444;
  503. font-size: 14px;
  504. margin-bottom: 16px;
  505. margin-top: 24px;
  506. .fontRest {
  507. color: #444;
  508. }
  509. }
  510. .item {
  511. width: 690px;
  512. overflow-y: auto;
  513. .fontName {
  514. font-weight: 500;
  515. }
  516. }
  517. }
  518. }
  519. .empty {
  520. padding: 0px 30px 40px 30px;
  521. color: #444;
  522. font-size: 14px;
  523. .createBtn {
  524. color: #409EFF;
  525. margin-left: 5px;
  526. cursor: pointer;
  527. }
  528. }
  529. .main-title {
  530. @include main-title;
  531. }
  532. </style>