plan.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. <template>
  2. <div class="app-container">
  3. <div class="title-container">
  4. <breadcrumb id="breadcrumb-container" class="breadcrumb-container"/>
  5. </div>
  6. <div style="padding-top: 30px;">
  7. <el-tabs v-model="activeName">
  8. <el-tab-pane :label="itemName +'【排期】' " name="first" class="pane">
  9. <el-form ref="postForm" :model="postForm" class="form-container" style="padding-left: 100px">
  10. <div class="postInfo-container">
  11. <el-row>
  12. <el-col>
  13. <el-form-item
  14. label="阶段名称:"
  15. prop="name"
  16. label-width="180px"
  17. class="postInfo-container-item"
  18. >
  19. <el-input type="text" v-model="postForm.name" class="filter-item" />
  20. </el-form-item>
  21. </el-col>
  22. </el-row>
  23. <div class="postInfo-container">
  24. <el-row>
  25. <el-col>
  26. <el-form-item label="上个阶段:"
  27. prop="headerId"
  28. label-width="180px"
  29. class="postInfo-container-item">
  30. <el-select
  31. v-model="postForm.headerId"
  32. placeholder=""
  33. clearable
  34. filterable
  35. class="filter-item"
  36. >
  37. <el-option v-for="item in stages"
  38. :key="item.footerId"
  39. :label="item.name"
  40. :value="item.footerId"/>
  41. </el-select>
  42. </el-form-item>
  43. </el-col>
  44. </el-row>
  45. </div>
  46. <div class="postInfo-container">
  47. <el-row>
  48. <el-col>
  49. <el-form-item
  50. label="阶段目标:"
  51. prop="target"
  52. label-width="180px"
  53. class="postInfo-container-item"
  54. >
  55. <el-input type="text" v-model="postForm.target" class="filter-item"/>
  56. </el-form-item>
  57. </el-col>
  58. </el-row>
  59. </div>
  60. </div>
  61. <div class="postInfo-container">
  62. <el-row>
  63. <el-col >
  64. <el-form-item
  65. label="开始日期:"
  66. prop="startDate"
  67. :rules="{required: true, message: '请选择日志日期', trigger: 'blur'}"
  68. label-width="180px"
  69. class="postInfo-container-item"
  70. >
  71. <el-date-picker
  72. v-model="postForm.startDate"
  73. type="date"
  74. value-format="yyyy-MM-dd"
  75. placeholder="选择日期"
  76. class="filter-item"
  77. style="width: 200px"
  78. />
  79. </el-form-item>
  80. </el-col>
  81. </el-row>
  82. </div>
  83. <div class="postInfo-container">
  84. <el-row>
  85. <el-col>
  86. <el-form-item
  87. label="结束日期:"
  88. prop="endDate"
  89. :rules="{required: true, message: '请选择日志日期', trigger: 'blur'}"
  90. label-width="180px"
  91. class="postInfo-container-item"
  92. >
  93. <el-date-picker
  94. v-model="postForm.endDate"
  95. type="date"
  96. value-format="yyyy-MM-dd"
  97. placeholder="选择日期"
  98. class="filter-item"
  99. style="width: 200px"
  100. />
  101. </el-form-item>
  102. </el-col>
  103. </el-row>
  104. </div>
  105. <div class="postInfo-container">
  106. <el-row>
  107. <el-col>
  108. <el-form-item label="负责人:"
  109. prop="endDate"
  110. label-width="180px"
  111. class="postInfo-container-item">
  112. <el-select
  113. v-model="postForm.dutyerId"
  114. placeholder=""
  115. clearable
  116. filterable
  117. class="filter-item"
  118. >
  119. <el-option
  120. v-for="item in users"
  121. :key="item.id"
  122. :label="item.name"
  123. :value="item.id"
  124. />
  125. </el-select>
  126. </el-form-item>
  127. </el-col>
  128. </el-row>
  129. </div>
  130. <div class="postInfo-container">
  131. <el-row>
  132. <el-col>
  133. <el-form-item
  134. label="阶段权重:"
  135. prop="weight"
  136. :rules="{required: true, message: '请填写阶段权重(0-100)', trigger: 'blur'}"
  137. label-width="180px"
  138. class="postInfo-container-item"
  139. >
  140. <el-input type="text" v-model="postForm.weight" class="filter-item" placeholder="计算参与人员提成">
  141. <i slot="suffix" style="font-size:normal;margin-right: 10px;line-height: 30px">%</i>
  142. </el-input>
  143. </el-form-item>
  144. </el-col>
  145. </el-row>
  146. </div>
  147. <div class="postInfo-container">
  148. <el-row>
  149. <el-col>
  150. <el-form-item
  151. label="逾期提成系数:"
  152. prop="coefficient"
  153. :rules="{required: true, message: '请填写逾期提成系数(0-100)', trigger: 'blur'}"
  154. label-width="180px"
  155. class="postInfo-container-item"
  156. >
  157. <el-input type="text" v-model="postForm.coefficient" class="filter-item" placeholder="计算参与人员提成">
  158. <i slot="suffix" style="font-size:normal;margin-right: 10px;line-height: 30px">%</i>
  159. </el-input>
  160. </el-form-item>
  161. </el-col>
  162. </el-row>
  163. </div>
  164. <div class="postInfo-container">
  165. <el-row>
  166. <el-col>
  167. <el-form-item
  168. label="备注信息:"
  169. prop="remark"
  170. label-width="180px"
  171. class="postInfo-container-item"
  172. >
  173. <el-input type="textarea" v-model="postForm.remark" class="filter-item" placeholder="200字符"/>
  174. </el-form-item>
  175. </el-col>
  176. </el-row>
  177. </div>
  178. <div class="postInfo-container">
  179. <el-form-item
  180. label="参与人员:"
  181. prop="remark"
  182. label-width="180px"
  183. class="postInfo-container-item"
  184. >
  185. <el-button type="primary" icon="el-icon-edit" class="filter-item" @click="openJoiner" >设置</el-button>
  186. </el-form-item>
  187. <el-dialog
  188. width="600px"
  189. :title=" '['+postForm.name +']参与人员提成系数设置'"
  190. :visible.sync="dialogFormVisible"
  191. :close-on-click-modal="true"
  192. >
  193. <y-page-list-layout :get-page-list="getJoinUsers" >
  194. <el-table
  195. slot="table"
  196. row-key="id"
  197. :data="joinUsers"
  198. ref="multipleTable"
  199. :header-row-style="{color: '#333333'}"
  200. @selection-change="handleSelectionChange"
  201. style="border-left: 1px solid #EBECED;border-right: 1px solid #EBECED;color: #333333;"
  202. >
  203. <el-table-column
  204. type="selection"
  205. width="55">
  206. </el-table-column>
  207. <el-table-column label="人员" width="100" align="center">
  208. <template slot-scope="{row}">
  209. <span>{{ row.userName }}</span>
  210. </template>
  211. </el-table-column>
  212. <el-table-column label="提成系数" align="center">
  213. <template slot-scope="{row}">
  214. <el-input v-model="row.weight" placeholder="请输入数字">
  215. <i slot="suffix" style="font-size:normal;margin-right: 10px;line-height: 30px">%</i>
  216. </el-input>
  217. </template>
  218. </el-table-column>
  219. </el-table>
  220. </y-page-list-layout>
  221. </el-dialog>
  222. </div>
  223. <el-button type="success" id="addNode" @click="saveNode">保存</el-button>
  224. <el-button type="normal" @click="clean">清空</el-button>
  225. </el-form>
  226. <div class="nodeFlow">
  227. <div style="height: 300px;">
  228. <el-timeline v-if="stageFlow.length>0">
  229. <el-timeline-item v-for="(s,index) in stageFlow" :key="index" :timestamp="s.name" placement="top" color="green"
  230. @click.native="getDetail(s.id)">
  231. <el-card class="card">
  232. <div class="it">
  233. <icon class="el-icon-s-flag"/> <el-tag type="success">{{s.target}}</el-tag>
  234. </div>
  235. <div class="it">
  236. <icon class="el-icon-time"/> <el-tag>{{s.startDate}}</el-tag> 至 <el-tag>{{s.endDate}}</el-tag>
  237. </div>
  238. <div v-if="s.dutyer" class="it">
  239. <icon class="el-icon-user"/> <el-tag>{{s.dutyer}}</el-tag>
  240. </div>
  241. <el-button class="del" type="danger" icon="el-icon-delete" @click="remove(s.id)"/>
  242. </el-card>
  243. </el-timeline-item>
  244. </el-timeline>
  245. </div>
  246. </div>
  247. </el-tab-pane>
  248. </el-tabs>
  249. </div>
  250. </div>
  251. </template>
  252. <script>
  253. import Breadcrumb from '@/components/Breadcrumb'
  254. export default {
  255. name: 'itemDetail',
  256. components: {
  257. Breadcrumb,
  258. },
  259. data() {
  260. return {
  261. type: 'detail',
  262. postForm: {
  263. itemId: this.$route.query.id,
  264. id:null,
  265. participators:[],
  266. name:null
  267. },
  268. itemId: this.$route.query.id,
  269. itemName: this.$route.query.itemName,
  270. id:null,
  271. activeName: 'first',
  272. vLoading: false,
  273. listQuery:{},
  274. filterMethod(query, item) {
  275. return item.label.indexOf(query) > -1;
  276. },
  277. stageFlow:[],
  278. stages:[],
  279. users: [],
  280. joinUsers: [],
  281. dialogFormVisible:false,
  282. }
  283. },
  284. created() {
  285. this.getFlow();
  286. this.getSimpleAll();
  287. this.$api.user.simpleAll().then(res => {
  288. this.users = res.data;
  289. });
  290. this.getJoinUsers();
  291. },
  292. methods: {
  293. toggleSelection(rows) {
  294. if (rows) {
  295. rows.forEach(row => {
  296. if (row.id!=null){
  297. this.$refs.multipleTable.toggleRowSelection(row, true);
  298. }
  299. });
  300. }
  301. },
  302. handleSelectionChange(val){
  303. this.postForm.participators = val;
  304. },
  305. openJoiner(){
  306. this.dialogFormVisible = true;
  307. setTimeout(() => {
  308. this.toggleSelection(this.joinUsers);
  309. }, 200)
  310. },
  311. getJoinUsers(){
  312. const that = this;
  313. that.$api.item.itemUser({itemId:this.itemId, stageId:this.id}).then(data => {
  314. if (data.code === 200) {
  315. this.joinUsers = data.data;
  316. } else {
  317. this.$message({
  318. type: 'error',
  319. message: data.msg
  320. })
  321. }
  322. })
  323. },
  324. getSimpleAll(){
  325. this.$api.itemStage.simpleAll(this.itemId).then(res => {
  326. this.stages = res.data;
  327. });
  328. },
  329. getFlow(){
  330. this.$api.itemStage.flow(this.itemId).then(res => {
  331. this.stageFlow = res.data===null?[]:res.data;
  332. });
  333. },
  334. getDetail(id) {
  335. if (id) {
  336. this.$api.itemStage.detail(id).then(res => {
  337. this.postForm = res.data;
  338. this.id = this.postForm.id;
  339. this.getJoinUsers();
  340. });
  341. }
  342. },
  343. remove(id){
  344. const that = this;
  345. that.$confirm('确认删除当前记录吗?', '警告', {
  346. confirmButtonText: '确认',
  347. cancelButtonText: '取消',
  348. type: 'warning'
  349. })
  350. .then(async () => {
  351. this.$api.itemStage.delete(id).then(res => {
  352. if (res.code === 200) {
  353. this.$notify({
  354. title: '成功',
  355. message: '删除成功',
  356. type: 'success',
  357. duration: 2000
  358. });
  359. this.getSimpleAll();
  360. this.getFlow();
  361. }
  362. })
  363. })
  364. .catch(err => { console.error(err) })
  365. },
  366. saveNode(){
  367. if (this.postForm.startDate>this.postForm.endDate){
  368. this.$notify({
  369. title: '错误',
  370. message: '开始日期不能大于结束日期',
  371. type: 'error',
  372. duration: 2000
  373. });
  374. return;
  375. }
  376. if (this.postForm.remark && this.postForm.remark.length>200){
  377. this.$notify({
  378. title: '错误',
  379. message: '备注信息不超过200字符',
  380. type: 'error',
  381. duration: 2000
  382. });
  383. return;
  384. }
  385. this.vLoading = true;
  386. this.$refs.postForm.validate(valid => {
  387. if (valid) {
  388. if (this.itemId && this.id===null) {
  389. this.$api.itemStage.add(Object.assign({}, this.postForm, {
  390. })).then(res => {
  391. if (res.code === 200) {
  392. this.$notify({
  393. title: '成功',
  394. message: '新增成功',
  395. type: 'success',
  396. duration: 2000
  397. });
  398. this.getSimpleAll();
  399. this.getFlow();
  400. this.vLoading = false
  401. }
  402. }).catch(() => {
  403. this.vLoading = false
  404. })
  405. } else {
  406. this.$api.itemStage.edit(Object.assign({}, this.postForm, {
  407. })).then(res => {
  408. if (res.code === 200) {
  409. this.$notify({
  410. title: '成功',
  411. message: '保存成功',
  412. type: 'success',
  413. duration: 2000
  414. });
  415. this.getSimpleAll();
  416. this.getFlow();
  417. this.vLoading = false
  418. }
  419. }).catch(() => {
  420. this.vLoading = false
  421. })
  422. }
  423. }
  424. })
  425. },
  426. clean(){
  427. this.postForm = {id:null};
  428. this.postForm.itemId = this.itemId;
  429. this.id = null;
  430. },
  431. },
  432. }
  433. </script>
  434. <style lang="css" scoped>
  435. .pane{
  436. display: flex;
  437. }
  438. .pane>div{
  439. flex: 1;
  440. }
  441. .form-container{
  442. padding-top: 30px;
  443. width: 700px;
  444. height: 800px;
  445. border: 1px solid darkgray;
  446. box-shadow: 10px 10px 5px #888888;;
  447. border-radius: 10px;
  448. }
  449. .form-container:hover{
  450. }
  451. .filter-item{
  452. width: 200px;
  453. }
  454. .nodeFlow{
  455. width: 300px;
  456. /*height: 800px;*/
  457. margin-left: 100px;
  458. overflow: auto;
  459. }
  460. #addNode{
  461. margin-left: 180px;
  462. }
  463. div.it{
  464. margin-top: 5px;
  465. }
  466. .card{
  467. cursor: pointer;
  468. display: flex;
  469. width: 500px;
  470. }
  471. .del{
  472. position: absolute;
  473. top:60px;
  474. left: 480px;
  475. }
  476. </style>