LeftSidebar.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <nav class="left-sidebar">
  3. <template v-for="{ type, name } in taskTypeArray">
  4. <div
  5. v-if="[TASK_EXPLAIN, taskType].includes(type)"
  6. :key="type"
  7. :class="[`${type}-task`, curTaskType === type ? 'active' : '']"
  8. @click="changeTaskType(type)"
  9. >
  10. <span>{{ name }}</span>
  11. <span v-if="type !== TASK_EXPLAIN">
  12. {{ taskNumAndSubtaskNum(type) }}
  13. </span>
  14. </div>
  15. <!-- 导航栏任务列表 -->
  16. <div v-if="[taskType].includes(type)" :key="`${type}-task`" class="task-list">
  17. <template v-for="({ name: taskName, child_task_list }, index) in taskList">
  18. <div
  19. :key="`sidebar-task-${index}`"
  20. :class="['task-list-item', curSelectMark === `${type}-${index}` ? 'active' : '']"
  21. >
  22. <span class="task-index" @click="setSelectMark(type, index)">{{ index + 1 }}.</span>
  23. <span class="task-name" @click="setSelectMark(type, index)">{{ taskName }}</span>
  24. </div>
  25. <div
  26. v-for="({ name: subtaskName }, subtask_index) in child_task_list"
  27. :key="`sidebar-subtask-${index}-${subtask_index}`"
  28. :class="['task-list-subtask', curSelectMark === `${type}-${index}-${subtask_index}` ? 'active' : '']"
  29. >
  30. <span class="task-index" @click="setSelectMark(type, index, subtask_index)">
  31. {{ `${index + 1}.${subtask_index + 1}` }}
  32. </span>
  33. <span class="task-name" @click="setSelectMark(type, index, subtask_index)">{{ subtaskName }}</span>
  34. </div>
  35. </template>
  36. </div>
  37. </template>
  38. </nav>
  39. </template>
  40. <script>
  41. export default {
  42. name: 'LeftSidebar'
  43. };
  44. </script>
  45. <script setup>
  46. import { ref, nextTick, inject } from 'vue';
  47. import { TASK_EXPLAIN, taskTypeArray } from '../data/TaskType';
  48. defineProps({
  49. curTaskType: {
  50. type: String,
  51. required: true
  52. },
  53. changeTaskType: {
  54. type: Function,
  55. required: true
  56. },
  57. taskType: {
  58. type: String,
  59. required: true
  60. }
  61. });
  62. /**
  63. * 处理选中任务导航事件
  64. */
  65. let curSelectMark = ref(''); // 当前选中任务标记
  66. function setSelectMark(type, index, subtask_index = -1) {
  67. curSelectMark.value = `${type}-${index}${subtask_index >= 0 ? `-${subtask_index}` : ''}`;
  68. nextTick(() => {
  69. document.querySelector(`.${curSelectMark.value}`)?.scrollIntoView({ behavior: 'smooth' });
  70. });
  71. }
  72. let curTaskTypeObj = inject('curTaskTypeObj');
  73. let taskList = inject('taskList');
  74. // 任务数量和子任务数量显示名
  75. function taskNumAndSubtaskNum(taskType) {
  76. if (!taskList.value) return;
  77. return taskList.value.length > 0
  78. ? `${taskList.value.length}/${taskList.value.reduce((pre, { child_task_list }) => pre + child_task_list.length, 0)}`
  79. : 0;
  80. }
  81. </script>
  82. <style lang="scss" scoped>
  83. $basic-background-color: #f7f7f7;
  84. .left-sidebar {
  85. width: 155px;
  86. padding: 16px 0 16px 8px;
  87. overflow: auto;
  88. font-size: 14px;
  89. background-color: $basic-background-color;
  90. border-right: 1px solid $border-color;
  91. .explain-task {
  92. width: 138px;
  93. height: 28px;
  94. padding: 2px 16px;
  95. margin-bottom: 14px;
  96. font-weight: bold;
  97. line-height: 22px;
  98. text-align: center;
  99. cursor: pointer;
  100. background-color: #fff;
  101. border: 1px solid $border-color;
  102. border-radius: 20px;
  103. &.active {
  104. color: #fff;
  105. background-color: v-bind('curTaskTypeObj.active_color');
  106. }
  107. }
  108. .pre-task,
  109. .mid-task,
  110. .after-task {
  111. display: flex;
  112. justify-content: space-between;
  113. width: 146px;
  114. height: 28px;
  115. padding: 2px 8px;
  116. margin-top: 8px;
  117. font-weight: bold;
  118. line-height: 22px;
  119. color: #fff;
  120. text-transform: uppercase;
  121. cursor: pointer;
  122. background-color: #cfcfcf;
  123. border: 1px solid $border-color;
  124. border-radius: 4px 0 0 4px;
  125. &.active {
  126. background-color: v-bind('curTaskTypeObj.active_color');
  127. }
  128. }
  129. .task-list {
  130. margin: 6px 0 0 8px;
  131. border-left: 1px solid #d9d9d9;
  132. &-item,
  133. %item {
  134. display: flex;
  135. column-gap: 8px;
  136. padding: 3px 16px;
  137. .task-index {
  138. cursor: pointer;
  139. }
  140. .task-name {
  141. word-break: break-all;
  142. cursor: pointer;
  143. }
  144. &.active {
  145. color: #0052d9;
  146. box-shadow: -1px 0 #0052d9;
  147. }
  148. }
  149. &-subtask {
  150. @extend %item;
  151. .task-index {
  152. margin-left: 16px;
  153. cursor: pointer;
  154. }
  155. }
  156. }
  157. }
  158. </style>