process.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <template>
  2. <div class="mod-menu">
  3. <div class="my-menu">
  4. <div class="menu-head">流程类别</div>
  5. <div v-for="(item, index) in menuList" :key="index" :class="{'menu-item': true, 'menu-active': active === index}">{{ item }}</div>
  6. </div>
  7. <div class="my-process">
  8. <div class="template_box">
  9. <div class="template_in">
  10. <div class="step_box">
  11. <div class='start-steps'>
  12. <button class='start-btn'>开始</button>
  13. </div>
  14. <draggable :list="list" disabled class="list-group" ghost-class="ghost" @start="dragging = true" @end="dragging = false" filter=".undraggable">
  15. <div class="step" v-for="(v, i) in list" :key="v.id">
  16. <textarea class="list-group-item" placeholder="请选择流程" maxlength='30' autofocus readonly="readonly" @focus='iptFocus(v, i)' @blur='iptBlur(v, i)' :value='v.step_name' />
  17. <div class='stepsAdd stepsAdd-before' @click='addBefore(i)'>+</div>
  18. <div class='stepsAdd stepsAdd-after' @click='addAfter(i)'>+</div>
  19. <div class='sb-close' @click='deleteStep(i)'>-</div>
  20. </div>
  21. <div class='end-steps undraggable'>
  22. <button class='end-btn'>结束</button>
  23. <div class='stepsAdd stepsAdd-end' v-if='showEndSteps' @click='addBefore()'>+</div>
  24. </div>
  25. </draggable>
  26. </div>
  27. <div class="stepInfo">
  28. <p>步骤详情(请点击上方加号添加步骤)</p>
  29. <div class="stepDetails">
  30. <el-form ref="stepForm" label-width="120px" :model="stepForm" :rules="stepRules">
  31. <el-form-item label="步骤名称:" prop="step_name">
  32. <el-input v-model="stepForm.step_name" @change='stepnameChange' :disabled="templateAddDisable" placeholder='请输入步骤名称' />
  33. </el-form-item>
  34. <el-form-item label="审批类型:" prop="step_type">
  35. <el-radio-group v-model="stepForm.step_type" :disabled="templateAddDisable">
  36. <el-radio label="1">会签</el-radio>
  37. <el-radio label="2">或签</el-radio>
  38. </el-radio-group>
  39. </el-form-item>
  40. <el-form-item label="节点审批员:" prop="step_func">
  41. <el-select class='typeBox' v-model='stepForm.step_func' placeholder='节点审批员' @change='featureChange' :disabled="templateAddDisable">
  42. <el-option v-for='i in featureItem' :key='i.id' :label='i.label' :value='i.value' />
  43. </el-select>
  44. </el-form-item>
  45. </el-form>
  46. </div>
  47. </div>
  48. <div class='confirmBox'>
  49. <el-button type='primary' size='medium' style='padding:8px 18px; margin-left:20px; font-size:14px;' @click="replace">重置</el-button>
  50. <el-button type='success' size='medium' style='padding:8px 18px; margin-left:20px; font-size:14px;' @click="confirm">提交</el-button>
  51. </div>
  52. </div>
  53. </div>
  54. <!-- <el-steps :active="process.length" align-center>
  55. <el-step v-for="item in process" :key="item.num" :title="item.name" description="可以写流程备注"></el-step>
  56. </el-steps> -->
  57. </div>
  58. <!-- 弹窗, 新增 / 修改 -->
  59. <!-- <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update> -->
  60. </div>
  61. </template>
  62. <script>
  63. // import AddOrUpdate from './menu-add-or-update'
  64. import draggable from 'vuedraggable'
  65. export default {
  66. data () {
  67. return {
  68. id: 0,
  69. showEndSteps: true,
  70. dragging: false,
  71. active: 0,
  72. menuList: ['订单流程', '采购流程'],
  73. list: [],
  74. templateAddDisable: true,
  75. featureItem: [
  76. { id: '1', label: 'Jenkins构建', value: 'build' },
  77. { id: '2', label: '应用部署', value: 'deploy' },
  78. { id: '3', label: '应用验证', value: 'validate' },
  79. { id: '4', label: '镜像同步', value: 'sync' }
  80. ],
  81. stepForm: {
  82. new_or_edit: 'new',
  83. step_name: '',
  84. step_type: '',
  85. step_func: ''
  86. },
  87. stepRules: {
  88. step_name: [{ required: true, message: '步骤名不能为空', trigger: 'blur' }],
  89. step_type: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
  90. step_func: [{ required: true, message: '功能不能为空', trigger: 'blur' }]
  91. },
  92. index: '',
  93. selectValue: '',
  94. addOrUpdateVisible: false
  95. }
  96. },
  97. components: {
  98. draggable
  99. },
  100. activated () {
  101. this.getDataList()
  102. },
  103. methods: {
  104. // 获取数据列表
  105. getDataList () {
  106. this.dataListLoading = true
  107. this.$http({
  108. url: this.$http.adornUrl('/user-service/menu/tree'),
  109. method: 'get',
  110. params: this.$http.adornParams()
  111. }).then(({data}) => {
  112. if (data.code === '200') {
  113. this.dataList = JSON.parse(JSON.stringify(data.data).replace(/"list":/g, '"children":').replace(/"children":null/g, '"children":[]'))
  114. console.log(this.dataList)
  115. }
  116. this.dataListLoading = false
  117. })
  118. },
  119. // 添加
  120. addBefore (i) {
  121. this.templateAddDisable = false
  122. this.stepForm.step_name = ''
  123. this.stepForm.step_type = ''
  124. this.stepForm.step_func = ''
  125. this.list.splice(i, 0, {
  126. id: this.id++,
  127. new_or_edit: 'new',
  128. step_name: '',
  129. step_type: '',
  130. step_func: ''
  131. })
  132. if (this.list.length !== 0) {
  133. this.showEndSteps = false
  134. }
  135. this.selectValue = ''
  136. let stepsArrey = document.getElementsByTagName('textarea')
  137. if (i) {
  138. window.setTimeout(() => {
  139. stepsArrey[i].focus()
  140. }, 0)
  141. } else {
  142. window.setTimeout(() => {
  143. stepsArrey[0].focus()
  144. }, 0)
  145. }
  146. },
  147. addAfter (i) {
  148. this.stepForm.step_name = ''
  149. this.stepForm.step_type = ''
  150. this.stepForm.step_func = ''
  151. let stepsArrey = document.getElementsByTagName('textarea')
  152. if (i === 0) {
  153. i = i + 1
  154. window.setTimeout(() => { stepsArrey[1].focus() }, 0)
  155. } else if (i > 0) {
  156. i = i + 1
  157. window.setTimeout(() => { stepsArrey[i].focus() }, 0)
  158. }
  159. this.list.splice(i, 0, {
  160. id: this.id++,
  161. new_or_edit: 'new',
  162. step_name: '',
  163. step_type: '',
  164. step_func: ''
  165. })
  166. },
  167. deleteStep (i) {
  168. this.list.splice(i, 1)
  169. if (this.list.length === 0) {
  170. this.showEndSteps = true
  171. this.templateAddDisable = true
  172. this.stepForm = { new_or_edit: 'new', step_name: '', step_type: '', step_func: '' }
  173. }
  174. let stepsArrey = document.querySelectorAll('textarea')
  175. for (let i = 0; i < stepsArrey.length; i++) {
  176. stepsArrey[i].style.backgroundColor = '#ecf5ff'
  177. stepsArrey[i].style.color = '#409eff'
  178. }
  179. },
  180. iptFocus (v, i) {
  181. this.stepForm.step_name = v.step_name
  182. this.stepForm.step_type = v.step_type
  183. this.stepForm.step_func = v.step_func
  184. let stepsArrey = document.querySelectorAll('textarea')
  185. this.index = i
  186. for (let i = 0; i < stepsArrey.length; i++) {
  187. stepsArrey[i].style.backgroundColor = '#ecf5ff'
  188. stepsArrey[i].style.color = '#409eff'
  189. }
  190. stepsArrey[this.index].style.backgroundColor = '#409eff'
  191. stepsArrey[this.index].style.color = '#fff'
  192. },
  193. iptBlur (v, i) {
  194. this.index = i
  195. },
  196. stepnameChange (selVal) {
  197. this.list[this.index].step_name = selVal
  198. this.stepForm.step_name = selVal
  199. },
  200. steptypeChange (selVal) {
  201. this.list[this.index].step_type = selVal
  202. },
  203. featureChange (selVal) {
  204. this.list[this.index].step_func = selVal
  205. },
  206. confirm () {
  207. if (this.stepForm.step_name === '') return this.$message.error('步骤名称不能为空')
  208. if (this.stepForm.step_type === '') return this.$message.error('审批类型不能为空')
  209. if (this.stepForm.step_func === '') return this.$message.error('节点审批员不能为空')
  210. let stepsMessage = []
  211. let stepsArrey = document.querySelectorAll('textarea')
  212. for (let i = 0; i < stepsArrey.length; i++) {
  213. stepsArrey[i].style.backgroundColor = '#ecf5ff'
  214. stepsArrey[i].style.color = '#409eff'
  215. }
  216. for (let i = 0; i < stepsArrey.length; i++) {
  217. if (stepsArrey[i].value !== '') {
  218. stepsMessage.push(stepsArrey[i].value)
  219. } else {
  220. for (let i = 0; i < stepsArrey.length; i++) {
  221. if (stepsArrey[i].value === '') {
  222. stepsArrey[i].style.backgroundColor = '#EE1111'
  223. stepsArrey[i].style.color = '#fff'
  224. };
  225. }
  226. return this.$message({type: 'error', message: '请填写完整的流程'})
  227. }
  228. }
  229. let params = {
  230. id: 0,
  231. name: this.templateForm.name,
  232. msg: this.templateForm.msg,
  233. steps: this.list
  234. }
  235. console.log(params)
  236. },
  237. replace () {
  238. this.list = []
  239. this.stepForm = { new_or_edit: 'new', step_name: '', step_type: '', step_func: '' }
  240. this.templateAddDisable = true
  241. this.showEndSteps = true
  242. }
  243. }
  244. }
  245. </script>
  246. <style lang="scss" scoped>
  247. .my-menu{
  248. width: 200px;
  249. position: absolute;
  250. top: 20px;
  251. bottom: 30px;
  252. background: #efefef;
  253. .menu-head{
  254. background-color: #17B3A3;
  255. color: #fff;
  256. font-size: 20px;
  257. line-height: 40px;
  258. padding-left: 10px;
  259. margin-bottom: 10px;
  260. }
  261. .menu-item{
  262. padding-left: 10px;
  263. line-height: 30px;
  264. font-size: 14px;
  265. &:hover{
  266. background-color: #efefef;
  267. cursor: pointer;
  268. }
  269. }
  270. .menu-active{
  271. color: #fff;
  272. background-color: #17B3A3;
  273. }
  274. }
  275. .my-process{
  276. padding-left: 210px;
  277. }
  278. .template_box {
  279. background-color: #fff;
  280. .template_in {
  281. padding: 15px 0;
  282. width: 100%;
  283. letter-spacing: 1px;
  284. }
  285. }
  286. /deep/ .el-form-item--small.el-form-item {
  287. margin-bottom: 12px;
  288. }
  289. /deep/ .el-input--small .el-input__inner, .el-input--small .el-textarea__inner {
  290. font-size: 12px;
  291. }
  292. /deep/ .el-input--small .el-textarea__inner {
  293. font-size: 12px;
  294. }
  295. /deep/ .el-input--small .el-input__inner {
  296. height: 28px;
  297. line-height: 28px;
  298. }
  299. /deep/ textarea {
  300. font: 400 13.3333px Arial;
  301. resize: none;
  302. }
  303. /deep/ .step_box textarea {
  304. outline: 0;
  305. caret-color: transparent;
  306. }
  307. .step_box textarea::-webkit-input-placeholder {
  308. color: #ccc;
  309. }
  310. .templateInfo {
  311. padding: 0 30px 2px 50px;
  312. margin: 0 auto;
  313. margin-top: 10px;
  314. width: 600px;
  315. }
  316. .stepInfo {
  317. background-image: linear-gradient(to right, #ccc 0%, #ccc 50%, transparent 50%);
  318. background-size: 14px 2px;
  319. background-repeat: repeat-x;
  320. padding: 10px;
  321. margin: 10px auto 25px;
  322. width: 600px;
  323. p {
  324. font-size: 14px;
  325. color: grey;
  326. margin: 5px 0 15px -10px;
  327. }
  328. }
  329. .confirmBox {
  330. text-align: center;
  331. }
  332. button {
  333. outline: 0;
  334. }
  335. .step_box {
  336. min-height: 72px;
  337. width: 100%;
  338. text-align: center;
  339. display: flex;
  340. justify-content:center;
  341. .start-steps{
  342. width: 120px;
  343. position: relative;
  344. padding: 15px 30px 15px 0;
  345. }
  346. .end-steps {
  347. width: 90px;
  348. position: relative;
  349. padding: 15px 30px 15px 0;
  350. }
  351. .end-steps {
  352. box-sizing: border-box;
  353. position: relative;
  354. padding: 15px 0 15px 15px;
  355. .stepsAdd {
  356. left: -19px;
  357. }
  358. }
  359. .start-btn,
  360. .end-btn {
  361. width: 90px;
  362. height: 40px;
  363. border: 1px solid #b3d8ff;
  364. border-radius: 20px;
  365. text-align: center;
  366. color: #409eff;
  367. line-height: 40px;
  368. font-size: 12px;
  369. cursor: pointer;
  370. background: #ecf5ff;
  371. }
  372. }
  373. .end-steps::before {
  374. content: '';
  375. position: absolute;
  376. top: 50%;
  377. left: -30px;
  378. width: 40px;
  379. height: 1px;
  380. background: #c0c4cc;
  381. }
  382. .end-steps::after {
  383. position: absolute;
  384. content: '';
  385. width: 0;
  386. height: 0;
  387. border-width: 5px;
  388. border-style: dashed solid;
  389. top: 50%;
  390. left: 10px;
  391. margin-top: -4px;
  392. border-color: transparent transparent transparent #c0c4cc;
  393. }
  394. .stepsAdd-before {
  395. display: none;
  396. left: -19px;
  397. z-index: 2;
  398. }
  399. .stepsAdd {
  400. font-size: 14px;
  401. text-align: center;
  402. position: absolute;
  403. top: 50%;
  404. border-radius: 100%;
  405. width: 20px;
  406. height: 20px;
  407. line-height: 18px;
  408. margin-top: -10px;
  409. background-color: #409eff;
  410. color: #fff;
  411. z-index: 1;
  412. cursor: pointer;
  413. }
  414. .stepsAdd-end {
  415. display: block;
  416. }
  417. .stepsAdd-after {
  418. display: none;
  419. right: -1px;
  420. z-index: 2;
  421. }
  422. .end-steps:hover {
  423. .stepsAdd-after {
  424. display: block;
  425. }
  426. }
  427. .step:hover {
  428. .stepsAdd-before {
  429. display: block;
  430. }
  431. .stepsAdd-after {
  432. display: block;
  433. }
  434. .sb-close {
  435. display: block;
  436. }
  437. }
  438. .sb-close {
  439. cursor: default;
  440. display: none;
  441. width: 16px;
  442. height: 16px;
  443. border-radius: 16px;
  444. color: #fff;
  445. text-align: center;
  446. position: absolute;
  447. color: #fff;
  448. background: #f56c6c;
  449. font-size: 16px;
  450. border-radius: 50%;
  451. top: 3px;
  452. right: 23px;
  453. line-height: 12px;
  454. }
  455. .buttons {
  456. margin-top: 35px;
  457. }
  458. .ghost {
  459. opacity: 0.5;
  460. background: #c8ebfb;
  461. }
  462. .list-group {
  463. display: flex;
  464. flex-wrap: wrap;
  465. }
  466. .step::before {
  467. content: '';
  468. position: absolute;
  469. top: 50%;
  470. left: -30px;
  471. width: 40px;
  472. height: 1px;
  473. background: #c0c4cc;
  474. }
  475. .step {
  476. position: relative;
  477. padding: 10px 30px 10px 15px;
  478. }
  479. .step::after {
  480. position: absolute;
  481. content: '';
  482. width: 0;
  483. height: 0;
  484. border-width: 5px;
  485. border-style: dashed solid;
  486. top: 50%;
  487. left: 10px;
  488. margin-top: -4px;
  489. border-color: transparent transparent transparent #c0c4cc;
  490. }
  491. .list-group-item {
  492. position: relative;
  493. width: 90px;
  494. box-sizing: border-box;
  495. border-radius: 4px;
  496. border: 1px solid #409eff;
  497. height: 48px;
  498. overflow: hidden;
  499. cursor: pointer;
  500. text-align: center;
  501. padding: 0 5px;
  502. font-size: 12px;
  503. line-height: 48px;
  504. background: #ecf5ff;
  505. color: #409eff;
  506. }
  507. </style>