task.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. <template>
  2. <div class="app-container">
  3. <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
  4. <el-form-item label="所属分类" prop="categoryId">
  5. <el-select
  6. v-model="queryParams.categoryId"
  7. clearable
  8. style="width: 200px">
  9. <el-option v-for="item in categoryList" :key="item.id" :label="item.categoryName" :value="item.id"/>
  10. </el-select>
  11. </el-form-item>
  12. <el-form-item label="所属项目" prop="projectId">
  13. <el-select
  14. v-model="queryParams.projectId"
  15. clearable
  16. style="width: 200px">
  17. <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id"/>
  18. </el-select>
  19. </el-form-item>
  20. <el-form-item label="月份选择">
  21. <el-date-picker
  22. v-model="queryParams.month"
  23. type="month"
  24. value-format="yyyy-MM"
  25. placeholder="选择月份"
  26. clearable
  27. style="width: 200px">
  28. </el-date-picker>
  29. </el-form-item>
  30. <el-form-item label="状态" prop="status">
  31. <el-select
  32. v-model="queryParams.status"
  33. placeholder="项目状态"
  34. style="width: 200px">
  35. <el-option :key="0" label="全部" value="0"/>
  36. <el-option :key="1" label="未开始" value="1"/>
  37. <el-option :key="2" label="进行中" value="1"/>
  38. <el-option :key="3" label="延期" value="1"/>
  39. <el-option :key="4" label="完成" value="1"/>
  40. <el-option :key="5" label="终止" value="1"/>
  41. </el-select>
  42. </el-form-item>
  43. <el-form-item>
  44. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  45. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  46. </el-form-item>
  47. </el-form>
  48. <el-row :gutter="10" style="margin-bottom:8px">
  49. <el-col :span="1.5">
  50. <el-button
  51. type="primary"
  52. plain
  53. icon="el-icon-plus"
  54. size="mini"
  55. @click="handleAdd"
  56. v-hasPermi="['task:task:add']"
  57. >新增
  58. </el-button>
  59. </el-col>
  60. </el-row>
  61. <el-table :data="TaskList"
  62. @row-click="rowClick"
  63. border
  64. stripe
  65. size="mini">
  66. <el-table-column label="任务编号" prop="id" width="100"/>
  67. <el-table-column label="任务名称" prop="taskName"/>
  68. <el-table-column label="所属项目" prop="projectName"/>
  69. <el-table-column label="执行人" prop="executorName" width="100"/>
  70. <el-table-column label="进度" prop="progressValue" width="80">
  71. <template slot-scope="scope">
  72. <span>{{ (scope.row.progressValue ? scope.row.progressValue : 0) + '%' }}</span>
  73. </template>
  74. </el-table-column>
  75. <el-table-column label="状态" width="100">
  76. <template slot-scope="scope">
  77. <el-tag size="mini" :color="statusMap[scope.row.status].color">{{ statusMap[scope.row.status].name }}</el-tag>
  78. </template>
  79. </el-table-column>
  80. <el-table-column label="任务起止时间" width="200">
  81. <template slot-scope="scope">
  82. <span>{{ scope.row.beginDate + ' 至 ' + scope.row.endDate }}</span>
  83. </template>
  84. </el-table-column>
  85. <el-table-column label="创建时间" prop="createTime" width="160">
  86. <template slot-scope="scope">
  87. <span>{{ parseTime(scope.row.createTime) }}</span>
  88. </template>
  89. </el-table-column>
  90. <el-table-column label="操作" width="240">
  91. <template slot-scope="scope">
  92. <el-button
  93. size="mini"
  94. type="text"
  95. icon="el-icon-edit"
  96. @click="handleAudit(scope.row)"
  97. v-hasPermi="['task:task:audit']"
  98. >审核
  99. </el-button>
  100. <el-button
  101. size="mini"
  102. type="text"
  103. icon="el-icon-edit"
  104. @click="handleSplit(scope.row)"
  105. v-hasPermi="['task:task:split']"
  106. >分解
  107. </el-button>
  108. <el-button
  109. size="mini"
  110. type="text"
  111. icon="el-icon-edit"
  112. @click="handleUpdate(scope.row)"
  113. v-hasPermi="['task:task:edit']"
  114. >终止
  115. </el-button>
  116. <el-button
  117. size="mini"
  118. type="text"
  119. icon="el-icon-delete"
  120. @click="handleDelete(scope.row)"
  121. v-hasPermi="['task:task:delete']"
  122. >删除
  123. </el-button>
  124. </template>
  125. </el-table-column>
  126. </el-table>
  127. <div style="margin-top: 10px;text-align: center">
  128. <el-pagination
  129. background
  130. @size-change="handleSizeChange"
  131. @current-change="handleCurrentChange"
  132. :current-page="queryParams.pageNum"
  133. :page-sizes="[10, 20, 50]"
  134. :page-size="queryParams.pageSize"
  135. layout="total, sizes, prev, pager, next, jumper"
  136. :total="total">
  137. </el-pagination>
  138. </div>
  139. <!-- 添加或修改任务配置对话框 -->
  140. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  141. <el-form ref="form" :model="form" :rules="rules" label-width="100px">
  142. <el-form-item label="任务名称" prop="taskName">
  143. <el-input v-model="form.taskName" placeholder="请输入任务名称"/>
  144. </el-form-item>
  145. <el-form-item label="任务类型" prop="taskType">
  146. <el-radio-group v-model="form.taskType">
  147. <el-radio label="1">软件开发</el-radio>
  148. <el-radio label="2">硬件开发</el-radio>
  149. <el-radio label="3">测试</el-radio>
  150. <el-radio label="4">实施</el-radio>
  151. <el-radio label="5">日常事务</el-radio>
  152. </el-radio-group>
  153. </el-form-item>
  154. <el-form-item label="所属项目" prop="projectId">
  155. <el-select
  156. v-model="form.projectId"
  157. clearable
  158. style="width: 240px">
  159. <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id"/>
  160. </el-select>
  161. </el-form-item>
  162. <el-form-item label="起止时间">
  163. <el-date-picker
  164. v-model="form.rangeDate"
  165. type="daterange"
  166. value-format="yyyy-MM-dd"
  167. range-separator="至"
  168. start-placeholder="开始日期"
  169. end-placeholder="结束日期">
  170. </el-date-picker>
  171. </el-form-item>
  172. <el-form-item label="执行人" prop="executor">
  173. <el-cascader
  174. v-model="form.executor"
  175. :options="userList"
  176. @change="(val)=>selectExecutor(val,'form')"
  177. :props="{ expandTrigger: 'hover',value:'id',label:'label' }"
  178. :show-all-levels="false"></el-cascader>
  179. </el-form-item>
  180. <el-form-item label="共同执行人" prop="coExecutor">
  181. <dept-user-tree :userList="userList" @selected="selectCoExecutor"/>
  182. </el-form-item>
  183. <el-form-item label="任务附件">
  184. <!-- <el-upload-->
  185. <!-- class="upload-demo"-->
  186. <!-- action="https://jsonplaceholder.typicode.com/posts/"-->
  187. <!-- :on-preview="handlePreview"-->
  188. <!-- :on-remove="handleRemove"-->
  189. <!-- :before-remove="beforeRemove"-->
  190. <!-- multiple-->
  191. <!-- :limit="3"-->
  192. <!-- :on-exceed="handleExceed"-->
  193. <!-- :file-list="fileList">-->
  194. <!-- <el-button size="small" type="primary">点击上传</el-button>-->
  195. <!-- </el-upload>-->
  196. </el-form-item>
  197. <el-form-item label="任务描述">
  198. <el-input v-model="form.description" type="textarea" placeholder="请输入内容"></el-input>
  199. </el-form-item>
  200. </el-form>
  201. <div slot="footer" class="dialog-footer">
  202. <el-button type="primary" size="small" @click="submitForm">确 定</el-button>
  203. <el-button size="small" @click="cancel">取 消</el-button>
  204. </div>
  205. </el-dialog>
  206. <!-- 详情/审核任务对话框 -->
  207. <el-dialog :title="detailTitle" :visible.sync="detailOpen" width="500px" append-to-body>
  208. <task-detail :detail-form="detailForm"></task-detail>
  209. <div v-if="detailTitle=='审核任务'" style="margin-top: 10px">
  210. <el-form ref="auditForm" :model="auditForm" label-width="100px">
  211. <el-form-item label="审核意见">
  212. <el-radio-group v-model="auditForm.auditResult">
  213. <el-radio label="1">确认完成</el-radio>
  214. <el-radio label="0">驳回</el-radio>
  215. </el-radio-group>
  216. </el-form-item>
  217. <el-form-item label="审核备注">
  218. <el-input v-model="auditForm.auditOpinion" type="textarea"/>
  219. </el-form-item>
  220. </el-form>
  221. </div>
  222. <div slot="footer" class="dialog-footer">
  223. <el-button type="primary" size="small" @click="submitAudit">确 定</el-button>
  224. <el-button size="small" @click="detailCancel">取 消</el-button>
  225. </div>
  226. </el-dialog>
  227. <!-- 分解任务对话框 -->
  228. <el-dialog title="分解任务" :visible.sync="splitOpen" width="500px" append-to-body>
  229. <el-form ref="splitForm" class="split-form">
  230. <el-form-item label="任务名称:">
  231. <div>{{ splitForm.taskName }}</div>
  232. </el-form-item>
  233. <el-form-item label="所属项目:">
  234. <span>{{ splitForm.projectName }}</span>
  235. <el-button type="text" size="medium" icon="el-icon-circle-plus-outline"
  236. style="float: right; padding: -1px 3px" @click="addChild"></el-button>
  237. </el-form-item>
  238. <el-card shadow="always" v-for="(c,index) in splitForm.children" :key="index">
  239. <div slot="header" class="clearfix">
  240. <span>子任务{{ index + 1 }}</span>
  241. <el-button type="text" icon="el-icon-close" @click="delChild(index)"
  242. style="float: right; padding: 3px 0"></el-button>
  243. </div>
  244. <el-form label-width="80px">
  245. <el-form-item label="任务名称">
  246. <el-input v-model="c.taskName" size="small" style="width: 350px"/>
  247. </el-form-item>
  248. <el-form-item label="执行人" prop="executor">
  249. <el-cascader
  250. ref="dut"
  251. v-model="c.executor"
  252. :options="userList"
  253. @change="(val)=>selectExecutor(val,'splitForm',index)"
  254. :props="{ expandTrigger: 'hover',value:'id',label:'label' }"
  255. :show-all-levels="false"></el-cascader>
  256. </el-form-item>
  257. <el-form-item label="起止时间">
  258. <el-date-picker
  259. v-model="c.rangeDate"
  260. type="daterange"
  261. size="small"
  262. value-format="yyyy-MM-dd"
  263. range-separator="至"
  264. start-placeholder="开始日期"
  265. end-placeholder="结束日期">
  266. </el-date-picker>
  267. </el-form-item>
  268. </el-form>
  269. </el-card>
  270. </el-form>
  271. <div slot="footer" class="dialog-footer">
  272. <el-button type="primary" size="small" @click="submitSplit">确 定</el-button>
  273. <el-button size="small" @click="splitCancel">取 消</el-button>
  274. </div>
  275. </el-dialog>
  276. </div>
  277. </template>
  278. <script>
  279. import {
  280. listTask,
  281. getTask,
  282. delTask,
  283. addTask,
  284. updateTask,
  285. auditTask,
  286. splitTask
  287. } from "@/api/task/task";
  288. import {getCategoryList} from "@/api/task/category";
  289. import {getProjectList} from "@/api/task/project";
  290. import {getDeptUserTree} from "@/api/system/user";
  291. import DateUtil from "@/utils/date"
  292. import TaskDetail from "./components/taskDetail"
  293. import DeptUserTree from "@/components/DeptUserTree"
  294. const statusMap = {
  295. '0': {name: '待查看', color: '#E8EBEE'},
  296. '1': {name: '未开始', color: '#f4f4f5'},
  297. '2': {name: '进行中', color: '#ecf5ff'},
  298. '3': {name: '延期', color: '#ECD994'},
  299. '4': {name: '完成', color: '#f0f9eb'},
  300. '5': {name: '终止', color: '#F97C07'}
  301. }
  302. export default {
  303. name: "Task",
  304. components: {TaskDetail, DeptUserTree},
  305. data() {
  306. return {
  307. categoryList: [],
  308. projectList: [],
  309. userList: [],
  310. // 总条数
  311. total: 0,
  312. // 项目表格数据
  313. TaskList: [],
  314. statusMap: statusMap,
  315. // 弹出层标题
  316. title: "",
  317. // 是否显示弹出层
  318. open: false,
  319. // 查询参数
  320. queryParams: {
  321. pageNum: 1,
  322. pageSize: 10,
  323. categoryId: undefined,
  324. projectId: undefined,
  325. month: DateUtil.month(),
  326. status: '0'
  327. },
  328. // 表单参数
  329. form: {},
  330. detailTitle: "",
  331. detailOpen: false,
  332. detailForm: {},
  333. auditForm: {},
  334. splitOpen: false,
  335. splitForm: {},
  336. // 表单校验
  337. rules: {
  338. taskName: [
  339. {required: true, message: "项目名称不能为空", trigger: "blur"}
  340. ],
  341. taskType: [
  342. {required: true, message: "任务类型不能为空", trigger: "change"}
  343. ],
  344. projectId: [
  345. {required: true, message: "所属项目不能为空", trigger: "change"}
  346. ],
  347. rangeDate: [
  348. {required: true, message: "起止时间不能为空", trigger: "change"}
  349. ],
  350. executor: [
  351. {required: true, message: "执行人不能为空", trigger: "change"}
  352. ]
  353. }
  354. };
  355. },
  356. created() {
  357. this.getList();
  358. },
  359. methods: {
  360. /** 查询项目列表 */
  361. getList() {
  362. getCategoryList("").then(res => {
  363. this.categoryList = res.data;
  364. })
  365. getProjectList("").then(res => {
  366. this.projectList = res.data;
  367. })
  368. listTask(this.queryParams).then(res => {
  369. this.TaskList = res.data.records;
  370. this.total = res.data.total;
  371. }
  372. );
  373. },
  374. /** 搜索按钮操作 */
  375. handleQuery() {
  376. this.queryParams.pageNum = 1;
  377. this.getList();
  378. },
  379. /** 重置按钮操作 */
  380. resetQuery() {
  381. this.resetForm("queryForm");
  382. this.handleQuery();
  383. },
  384. handleSizeChange(val) {
  385. this.pageSize = val;
  386. this.getList();
  387. },
  388. handleCurrentChange(val) {
  389. this.pageNum = val;
  390. this.getList();
  391. },
  392. // 取消按钮
  393. cancel() {
  394. this.open = false;
  395. this.reset()
  396. },
  397. reset() {
  398. this.form = {
  399. id: undefined,
  400. taskName: undefined,
  401. categoryId: undefined,
  402. description: undefined,
  403. status: "0",
  404. };
  405. this.resetForm("form");
  406. },
  407. // 取消按钮(详情/审核)
  408. detailCancel() {
  409. this.detailOpen = false;
  410. this.detailForm = {};
  411. this.auditForm = {}
  412. this.resetForm("auditForm");
  413. },
  414. // 取消按钮(分解任务)
  415. splitCancel() {
  416. this.splitOpen = false;
  417. this.splitForm = {}
  418. this.resetForm("splitForm");
  419. },
  420. /** 查看任务详情*/
  421. rowClick(row, column, event) {
  422. if (!column.property) {
  423. return
  424. }
  425. getTask(row.id).then(res => {
  426. this.detailForm = res.data;
  427. this.detailOpen = true;
  428. this.detailTitle = "任务详情";
  429. })
  430. },
  431. /** 新增按钮操作 */
  432. handleAdd() {
  433. getDeptUserTree().then(res => {
  434. this.userList = res.data
  435. })
  436. this.reset();
  437. this.open = true;
  438. this.title = "添加项目";
  439. },
  440. selectExecutor(val, form, index) {
  441. if (form === 'splitForm') {
  442. let child = this.splitForm.children[index];
  443. child.executor = val[val.length - 1]
  444. }
  445. if (form === 'form') {
  446. this.form.executor = val[val.length - 1]
  447. }
  448. },
  449. selectCoExecutor(val) {
  450. this.form.coExecutor = val.join();
  451. },
  452. /** 审核按钮操作 */
  453. handleAudit(row) {
  454. getTask(row.id).then(res => {
  455. this.detailForm = res.data;
  456. this.detailOpen = true;
  457. this.detailTitle = "审核任务";
  458. })
  459. },
  460. /** 分解按钮操作 */
  461. handleSplit(row) {
  462. getDeptUserTree().then(res => {
  463. this.userList = res.data
  464. this.splitForm = {
  465. parentId: row.id,
  466. taskName: row.taskName,
  467. projectName: row.projectName,
  468. children: []
  469. }
  470. this.splitOpen = true
  471. })
  472. },
  473. /** 提交按钮 */
  474. submitForm() {
  475. this.$refs["form"].validate(valid => {
  476. if (valid) {
  477. this.form.beginDate = this.form.rangeDate[0]
  478. this.form.endDate = this.form.rangeDate[1]
  479. addTask(this.form).then(res => {
  480. this.$message.success("新增成功");
  481. this.open = false;
  482. this.getList();
  483. });
  484. }
  485. });
  486. },
  487. /** 审核提交按钮 */
  488. submitAudit() {
  489. },
  490. /** 分解任务提交按钮 */
  491. submitSplit() {
  492. splitTask(this.splitForm).then(res => {
  493. this.getList()
  494. this.splitOpen = false
  495. this.$message.success("操作成功");
  496. })
  497. },
  498. /** 终止按钮操作 */
  499. handleUpdate(row) {
  500. this.$confirm('是否确认终止任务编号为"' + row.id + '"的任务?').then(() => {
  501. return updateTask({id: row.id, status: '5'});
  502. }).then(() => {
  503. this.getList();
  504. this.$message.success("终止成功");
  505. }).catch(() => {
  506. });
  507. },
  508. /** 删除按钮操作 */
  509. handleDelete(row) {
  510. this.$confirm('是否确认删除任务编号为"' + row.id + '"的数据项?').then(() => {
  511. return delTask(row.id);
  512. }).then(() => {
  513. this.getList();
  514. this.$message.success("删除成功");
  515. }).catch(() => {
  516. });
  517. },
  518. addChild() {
  519. let child = {
  520. taskName: undefined,
  521. executor: undefined,
  522. rangeDate: []
  523. }
  524. this.splitForm.children.push(child)
  525. },
  526. delChild(index) {
  527. this.splitForm.children.splice(index, 1)
  528. },
  529. }
  530. };
  531. </script>
  532. <style scoped lang="scss">
  533. .split-form {
  534. ::v-deep .el-form-item__label {
  535. font-size: 13px;
  536. }
  537. ::v-deep.el-form-item {
  538. margin-bottom: 0;
  539. }
  540. ::v-deep.el-card__header {
  541. padding: 5px 10px;
  542. }
  543. ::v-deep.el-card__body {
  544. padding: 5px;
  545. }
  546. }
  547. </style>