detail.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <template>
  2. <el-dialog v-model="visible" :title="titleMap[mode]" :width="860" :close-on-click-modal="false" @closed="$emit('closed')">
  3. <el-form ref="formRef" :model="form" :rules="rules" label-width="120">
  4. <el-row>
  5. <el-col v-if="props.projectId != 1" :md="12" :xs="24">
  6. <el-form-item label="所属项目" prop="projectId">
  7. <el-select v-model="form.projectId" filterable :disabled="mode != 'add'" placeholder="请选择所属项目">
  8. <el-option v-for="item in $TOOL.data.get('PROJECT')" :key="item.fpiId" :label="item.projectName" :value="item.fpiId"></el-option>
  9. </el-select>
  10. </el-form-item>
  11. </el-col>
  12. <el-col :md="12" :xs="24">
  13. <el-form-item label="上级节点" prop="parentId">
  14. <el-tree-select v-model="form.parentId" v-bind="treeSelectProps" :disabled="mode != 'add'"></el-tree-select>
  15. </el-form-item>
  16. </el-col>
  17. <el-col :md="12" :xs="24">
  18. <el-form-item label="节点名称" prop="nodeName">
  19. <el-input v-model="form.nodeName" placeholder="请输入节点名称"></el-input>
  20. </el-form-item>
  21. </el-col>
  22. <el-col :md="12" :xs="24">
  23. <el-form-item label="节点排序" prop="nodeSeq">
  24. <el-input-number v-model="form.nodeSeq" :min="0" step-strictly :controls="false" placeholder="请输入节点排序"></el-input-number>
  25. </el-form-item>
  26. </el-col>
  27. <el-col :md="12" :xs="24">
  28. <el-form-item label="节点状态" prop="nodeStatus">
  29. <el-select v-model="form.nodeStatus" filterable placeholder="请选择节点状态">
  30. <el-option v-for="(label, key) in nodeStatusDic" :key="key" :label="label" :value="key"></el-option>
  31. </el-select>
  32. </el-form-item>
  33. </el-col>
  34. <el-col :md="12" :xs="24">
  35. <el-form-item label="计划开始时间">
  36. <el-date-picker v-model="form.planStartTime" type="datetime" :clearable="false" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择计划开始时间"></el-date-picker>
  37. </el-form-item>
  38. </el-col>
  39. <el-col :md="12" :xs="24">
  40. <el-form-item label="计划完成时间">
  41. <el-date-picker v-model="form.planFinishTime" type="datetime" :clearable="false" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择计划完成时间"></el-date-picker>
  42. </el-form-item>
  43. </el-col>
  44. <el-col :md="12" :xs="24">
  45. <el-form-item label="实际开始时间">
  46. <el-date-picker v-model="form.actualStartTime" type="datetime" :clearable="false" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择实际开始时间"></el-date-picker>
  47. </el-form-item>
  48. </el-col>
  49. <el-col :md="12" :xs="24">
  50. <el-form-item label="实际完成时间">
  51. <el-date-picker v-model="form.actualFinishTime" type="datetime" :clearable="false" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择实际完成时间"></el-date-picker>
  52. </el-form-item>
  53. </el-col>
  54. <el-col :xs="24">
  55. <el-form-item label="可选事项">
  56. <el-select v-model="form.todoIdList" filterable clearable multiple collapse-tags collapse-tags-tooltip :max-collapse-tags="2" placeholder="请选择可选事项">
  57. <el-option v-for="item in filterTodoL" :key="item.id" :label="item.content" :value="item.id"></el-option>
  58. </el-select>
  59. </el-form-item>
  60. </el-col>
  61. <el-col :xs="24">
  62. <el-form-item label="描述内容">
  63. <el-input v-model="form.remark" type="textarea" :rows="4" placeholder="请输入描述内容"></el-input>
  64. </el-form-item>
  65. </el-col>
  66. </el-row>
  67. </el-form>
  68. <template #footer>
  69. <el-button :loading="isSaving" type="primary" auto-insert-space @click="submit">保存</el-button>
  70. <el-button auto-insert-space @click="visible = false">取消</el-button>
  71. </template>
  72. </el-dialog>
  73. </template>
  74. <script setup>
  75. import XEUtils from "xe-utils";
  76. import API from "@/api";
  77. import TOOL from "@/utils/tool";
  78. import { nodeStatusDic } from "@/views/milestone/main";
  79. const $emit = defineEmits(["success", "closed"]);
  80. const props = defineProps({
  81. projectId: { type: Number, default: TOOL.data.get("PROJECT_ID") }
  82. });
  83. const visible = ref(false);
  84. const isSaving = ref(false);
  85. const mode = ref("add");
  86. const titleMap = reactive({
  87. add: "新增",
  88. add_child: "新增子节点",
  89. edit: "修改"
  90. })
  91. const form = ref({
  92. id: null,
  93. projectId: null,
  94. parentId: "0",
  95. nodeName: null,
  96. nodeSeq: null,
  97. nodeStatus: null,
  98. planStartTime: null,
  99. planFinishTime: null,
  100. actualStartTime: null,
  101. actualFinishTime: null,
  102. todoIdList: [],
  103. remark: null
  104. })
  105. const rules = reactive({
  106. projectId: [{ required: true, message: "请选择所属项目" }],
  107. parentId: [{ required: true, message: "请选择上级节点" }],
  108. nodeName: [{ required: true, message: "请输入节点名称" }],
  109. nodeSeq: [{ required: true, message: "请输入节点排序" }],
  110. nodeStatus: [{ required: true, message: "请选择节点状态" }]
  111. })
  112. const treeSelectProps = reactive({
  113. popperClass: "vxe-table-slot--popper",
  114. data: [{ id: "0", nodeName: "根目录" }],
  115. filterable: true,
  116. checkStrictly: true,
  117. placeholder: "请选择上级节点",
  118. props: { label: "nodeName", value: "id" }
  119. })
  120. const todoTasks = ref([]);
  121. const filterTodoL = computed(() => XEUtils.filter(todoTasks.value, item => item.planId == "-" || item.planId == form.value.id));
  122. const getTreeData = async projectId => {
  123. const planRes = await API.milestone.plan.all({ orderBy: "nodeSeq_asc", projectId });
  124. treeSelectProps.data = XEUtils.toArrayTree([{ id: "0", nodeName: "根目录" }, ...planRes], { parentKey: "parentId", key: "id" });
  125. const taskRes = await API.milestone.matters.all({ orderBy: "sortNum_asc", projectId });
  126. todoTasks.value = taskRes;
  127. }
  128. watch(() => form.value.projectId, val => val && getTreeData(val));
  129. const open = data => {
  130. visible.value = true;
  131. form.value.projectId = !XEUtils.isEmpty(data) ? data.projectId : props.projectId;
  132. if (!XEUtils.isEmpty(data)) {
  133. mode.value = "add_child";
  134. form.value.parentId = data.id;
  135. }
  136. }
  137. const setData = data => {
  138. open();
  139. mode.value = "edit";
  140. XEUtils.objectEach(form.value, (_, key) => XEUtils.set(form.value, key, XEUtils.get(data, key)));
  141. }
  142. const formRef = ref();
  143. const submit = () => {
  144. formRef.value.validate(valid => {
  145. if (valid) {
  146. isSaving.value = true;
  147. API.milestone.plan[XEUtils.first(mode.value.split("_"))](form.value).then(() => {
  148. isSaving.value = false;
  149. ElMessage.success("操作成功");
  150. visible.value = false;
  151. $emit("success", mode.value);
  152. }).catch(() => isSaving.value = false);
  153. } else {
  154. return false;
  155. }
  156. });
  157. }
  158. defineExpose({
  159. open,
  160. setData
  161. })
  162. </script>
  163. <style scoped>
  164. .el-form {
  165. padding-right: calc(var(--el-dialog-padding-primary) + var(--el-message-close-size, 16px));
  166. }
  167. .el-form-item .el-input-number {width: 100%;}
  168. .el-form-item .el-input-number :deep(.el-input__prefix) {margin-right: 8px;}
  169. .el-form-item .el-input-number :deep(.el-input__inner) {text-align: unset;}
  170. .el-form-item .el-select :deep(.el-select__selection) .el-select__selected-item .el-tag{max-width: 204px !important;}
  171. </style>