You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.0 KiB

  1. <template>
  2. <layout-text v-if="doc.id">
  3. <template v-slot:header>
  4. <toolbar-laptop
  5. :doc-id="doc.id"
  6. :enable-auto-labeling.sync="enableAutoLabeling"
  7. :guideline-text="project.guideline"
  8. :is-reviewd="doc.isApproved"
  9. :show-approve-button="project.permitApprove"
  10. :total="docs.count"
  11. class="d-none d-sm-block"
  12. @click:clear-label="clear"
  13. @click:review="approve"
  14. >
  15. <v-btn-toggle
  16. v-model="labelOption"
  17. mandatory
  18. class="ms-2"
  19. >
  20. <v-btn icon>
  21. <v-icon>mdi-format-list-bulleted</v-icon>
  22. </v-btn>
  23. <v-btn icon>
  24. <v-icon>mdi-text</v-icon>
  25. </v-btn>
  26. </v-btn-toggle>
  27. </toolbar-laptop>
  28. <toolbar-mobile
  29. :total="docs.count"
  30. class="d-flex d-sm-none"
  31. />
  32. </template>
  33. <template v-slot:content>
  34. <v-card
  35. v-shortkey="shortKeys"
  36. @shortkey="addOrRemove"
  37. >
  38. <v-card-title>
  39. <label-group
  40. v-if="labelOption === 0"
  41. :labels="labels"
  42. :annotations="annotations"
  43. :single-label="project.singleClassClassification"
  44. @add="add"
  45. @remove="remove"
  46. />
  47. <label-select
  48. v-else
  49. :labels="labels"
  50. :annotations="annotations"
  51. :single-label="project.singleClassClassification"
  52. @add="add"
  53. @remove="remove"
  54. />
  55. </v-card-title>
  56. <v-divider />
  57. <v-card-text class="title highlight text-pre-wrap" v-text="doc.text" />
  58. </v-card>
  59. </template>
  60. <template v-slot:sidebar>
  61. <list-metadata :metadata="doc.meta" />
  62. </template>
  63. </layout-text>
  64. </template>
  65. <script>
  66. import _ from 'lodash'
  67. import LabelGroup from '@/components/tasks/textClassification/LabelGroup'
  68. import LabelSelect from '@/components/tasks/textClassification/LabelSelect'
  69. import LayoutText from '@/components/tasks/layout/LayoutText'
  70. import ListMetadata from '@/components/tasks/metadata/ListMetadata'
  71. import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
  72. import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
  73. export default {
  74. layout: 'workspace',
  75. components: {
  76. LabelGroup,
  77. LabelSelect,
  78. LayoutText,
  79. ListMetadata,
  80. ToolbarLaptop,
  81. ToolbarMobile
  82. },
  83. async fetch() {
  84. this.docs = await this.$services.example.fetchOne(
  85. this.projectId,
  86. this.$route.query.page,
  87. this.$route.query.q,
  88. this.$route.query.isChecked,
  89. this.project.filterOption
  90. )
  91. const doc = this.docs.items[0]
  92. if (this.enableAutoLabeling) {
  93. await this.autoLabel(doc.id)
  94. }
  95. await this.list(doc.id)
  96. },
  97. data() {
  98. return {
  99. annotations: [],
  100. docs: [],
  101. labels: [],
  102. project: {},
  103. enableAutoLabeling: false,
  104. labelOption: 0
  105. }
  106. },
  107. computed: {
  108. shortKeys() {
  109. return Object.fromEntries(this.labels.map(item => [item.id, [item.suffixKey]]))
  110. },
  111. projectId() {
  112. return this.$route.params.id
  113. },
  114. doc() {
  115. if (_.isEmpty(this.docs) || this.docs.items.length === 0) {
  116. return {}
  117. } else {
  118. return this.docs.items[0]
  119. }
  120. }
  121. },
  122. watch: {
  123. '$route.query': '$fetch',
  124. enableAutoLabeling(val) {
  125. if (val) {
  126. this.list(this.doc.id)
  127. }
  128. }
  129. },
  130. async created() {
  131. this.labels = await this.$services.label.list(this.projectId)
  132. this.project = await this.$services.project.findById(this.projectId)
  133. },
  134. methods: {
  135. async list(docId) {
  136. this.annotations = await this.$services.textClassification.list(this.projectId, docId)
  137. },
  138. async remove(id) {
  139. await this.$services.textClassification.delete(this.projectId, this.doc.id, id)
  140. await this.list(this.doc.id)
  141. },
  142. async add(labelId) {
  143. await this.$services.textClassification.create(this.projectId, this.doc.id, labelId)
  144. await this.list(this.doc.id)
  145. },
  146. async addOrRemove(event) {
  147. const label = this.labels.find(item => item.id === parseInt(event.srcKey, 10))
  148. const annotation = this.annotations.find(item => item.label === label.id)
  149. if (annotation) {
  150. await this.remove(annotation.id)
  151. } else {
  152. await this.add(label.id)
  153. }
  154. },
  155. async clear() {
  156. await this.$services.textClassification.clear(this.projectId, this.doc.id)
  157. await this.list(this.doc.id)
  158. },
  159. async autoLabel(docId) {
  160. try {
  161. await this.$services.textClassification.autoLabel(this.projectId, docId)
  162. } catch (e) {
  163. console.log(e.response.data.detail)
  164. }
  165. },
  166. async approve() {
  167. const approved = !this.doc.isApproved
  168. await this.$services.example.approve(this.projectId, this.doc.id, approved)
  169. await this.$fetch()
  170. }
  171. },
  172. validate({ params, query }) {
  173. return /^\d+$/.test(params.id) && /^\d+$/.test(query.page)
  174. }
  175. }
  176. </script>
  177. <style scoped>
  178. .text-pre-wrap {
  179. white-space: pre-wrap !important;
  180. }
  181. </style>