mirror of https://github.com/doccano/doccano.git
9 changed files with 394 additions and 437 deletions
Unified View
Diff Options
-
76frontend/components/containers/labels/LabelActionMenu.vue
-
56frontend/components/containers/labels/LabelDeletionButton.vue
-
147frontend/components/containers/labels/LabelList.vue
-
42frontend/components/label/ActionMenu.vue
-
92frontend/components/label/FormCreate.vue
-
28frontend/components/label/FormDelete.vue
-
62frontend/components/label/FormUpload.vue
-
216frontend/components/label/LabelList.vue
-
112frontend/components/organisms/labels/LabelCreationForm.vue
@ -1,76 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<action-menu |
|
||||
:items="menuItems" |
|
||||
:text="$t('dataset.actions')" |
|
||||
@create="createDialog=true" |
|
||||
@upload="importDialog=true" |
|
||||
@download="handleDownload" |
|
||||
/> |
|
||||
<v-dialog |
|
||||
v-model="createDialog" |
|
||||
width="800" |
|
||||
> |
|
||||
<label-creation-form |
|
||||
:create-label="createLabel" |
|
||||
:keys="shortkeys" |
|
||||
@close="createDialog=false" |
|
||||
/> |
|
||||
</v-dialog> |
|
||||
<v-dialog |
|
||||
v-model="importDialog" |
|
||||
width="800" |
|
||||
> |
|
||||
<label-import-form |
|
||||
:upload-label="uploadLabel" |
|
||||
@close="importDialog=false" |
|
||||
/> |
|
||||
</v-dialog> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapActions, mapGetters } from 'vuex' |
|
||||
import ActionMenu from '@/components/molecules/ActionMenu' |
|
||||
import LabelCreationForm from '@/components/organisms/labels/LabelCreationForm' |
|
||||
import LabelImportForm from '@/components/organisms/labels/LabelImportForm' |
|
||||
|
|
||||
export default { |
|
||||
components: { |
|
||||
ActionMenu, |
|
||||
LabelCreationForm, |
|
||||
LabelImportForm |
|
||||
}, |
|
||||
|
|
||||
data() { |
|
||||
return { |
|
||||
createDialog: false, |
|
||||
importDialog: false, |
|
||||
menuItems: [ |
|
||||
{ title: this.$t('labels.createLabel'), icon: 'mdi-pencil', event: 'create' }, |
|
||||
{ title: this.$t('labels.importLabels'), icon: 'mdi-upload', event: 'upload' }, |
|
||||
{ title: this.$t('labels.exportLabels'), icon: 'mdi-download', event: 'download' } |
|
||||
] |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapGetters('labels', ['shortkeys']) |
|
||||
}, |
|
||||
|
|
||||
created() { |
|
||||
this.setCurrentProject(this.$route.params.id) |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapActions('labels', ['createLabel', 'uploadLabel', 'exportLabels']), |
|
||||
...mapActions('projects', ['setCurrentProject']), |
|
||||
|
|
||||
handleDownload() { |
|
||||
this.exportLabels({ |
|
||||
projectId: this.$route.params.id |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -1,56 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<v-btn |
|
||||
:disabled="!isLabelSelected" |
|
||||
class="text-capitalize" |
|
||||
outlined |
|
||||
@click="dialog=true" |
|
||||
> |
|
||||
{{ $t('generic.delete') }} |
|
||||
</v-btn> |
|
||||
<v-dialog |
|
||||
v-model="dialog" |
|
||||
width="800" |
|
||||
> |
|
||||
<confirm-form |
|
||||
:items="selected" |
|
||||
title="Delete Label" |
|
||||
:message="$t('labels.deleteMessage')" |
|
||||
item-key="text" |
|
||||
@ok="deleteLabel($route.params.id);dialog=false" |
|
||||
@cancel="dialog=false" |
|
||||
/> |
|
||||
</v-dialog> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapState, mapGetters, mapActions } from 'vuex' |
|
||||
import ConfirmForm from '@/components/organisms/utils/ConfirmForm' |
|
||||
|
|
||||
export default { |
|
||||
components: { |
|
||||
ConfirmForm |
|
||||
}, |
|
||||
|
|
||||
data() { |
|
||||
return { |
|
||||
dialog: false |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapState('labels', ['selected']), |
|
||||
...mapGetters('labels', ['isLabelSelected']) |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapActions('labels', ['deleteLabel']), |
|
||||
|
|
||||
handleDeleteLabel() { |
|
||||
const projectId = this.$route.params.id |
|
||||
this.deleteLabel(projectId) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -1,147 +0,0 @@ |
|||||
<template> |
|
||||
<v-data-table |
|
||||
:value="selected" |
|
||||
:headers="headers" |
|
||||
:items="items" |
|
||||
:search="search" |
|
||||
:loading="loading" |
|
||||
:loading-text="$t('generic.loading')" |
|
||||
:no-data-text="$t('vuetify.noDataAvailable')" |
|
||||
:footer-props="{ |
|
||||
'showFirstLastPage': true, |
|
||||
'items-per-page-options': [5, 10, 15, $t('generic.all')], |
|
||||
'items-per-page-text': $t('vuetify.itemsPerPageText'), |
|
||||
'page-text': $t('dataset.pageText') |
|
||||
}" |
|
||||
item-key="id" |
|
||||
show-select |
|
||||
@input="updateSelected" |
|
||||
> |
|
||||
<template v-slot:top> |
|
||||
<v-text-field |
|
||||
v-model="search" |
|
||||
prepend-inner-icon="search" |
|
||||
:label="$t('generic.search')" |
|
||||
single-line |
|
||||
hide-details |
|
||||
filled |
|
||||
/> |
|
||||
</template> |
|
||||
<template v-slot:item.text="{ item }"> |
|
||||
<v-edit-dialog> |
|
||||
{{ item.text }} |
|
||||
<template v-slot:input> |
|
||||
<v-text-field |
|
||||
:value="item.text" |
|
||||
:rules="labelNameRules($t('rules.labelNameRules'))" |
|
||||
:label="$t('generic.edit')" |
|
||||
single-line |
|
||||
@change="handleUpdateLabel({ id: item.id, text: $event })" |
|
||||
/> |
|
||||
</template> |
|
||||
</v-edit-dialog> |
|
||||
</template> |
|
||||
<template v-slot:item.suffix_key="{ item }"> |
|
||||
<v-edit-dialog> |
|
||||
<div>{{ item.suffix_key }}</div> |
|
||||
<template v-slot:input> |
|
||||
<v-select |
|
||||
:value="item.suffix_key" |
|
||||
:items="availableShortkeys(item.suffix_key)" |
|
||||
:label="$t('annotation.key')" |
|
||||
@change="handleUpdateLabel({ id: item.id, suffix_key: $event })" |
|
||||
/> |
|
||||
</template> |
|
||||
</v-edit-dialog> |
|
||||
</template> |
|
||||
<template v-slot:item.background_color="{ item }"> |
|
||||
<v-edit-dialog> |
|
||||
<v-chip |
|
||||
:color="item.background_color" |
|
||||
:text-color="textColor(item.background_color)" |
|
||||
dark |
|
||||
> |
|
||||
{{ item.background_color }} |
|
||||
</v-chip> |
|
||||
<template v-slot:input> |
|
||||
<v-color-picker |
|
||||
:value="item.background_color" |
|
||||
:rules="colorRules($t('rules.colorRules'))" |
|
||||
show-swatches |
|
||||
hide-mode-switch |
|
||||
width="800" |
|
||||
mode="hexa" |
|
||||
class="ma-2" |
|
||||
@update:color="handleUpdateLabel({ id:item.id, background_color: $event.hex })" |
|
||||
/> |
|
||||
</template> |
|
||||
</v-edit-dialog> |
|
||||
</template> |
|
||||
</v-data-table> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex' |
|
||||
import { colorRules, labelNameRules } from '@/rules/index' |
|
||||
import { idealColor } from '~/plugins/utils' |
|
||||
|
|
||||
export default { |
|
||||
data() { |
|
||||
return { |
|
||||
search: '', |
|
||||
headers: [ |
|
||||
{ |
|
||||
text: this.$t('generic.name'), |
|
||||
align: 'left', |
|
||||
value: 'text' |
|
||||
}, |
|
||||
{ |
|
||||
text: this.$t('labels.shortkey'), |
|
||||
value: 'suffix_key' |
|
||||
}, |
|
||||
{ |
|
||||
text: this.$t('labels.color'), |
|
||||
sortable: false, |
|
||||
value: 'background_color' |
|
||||
} |
|
||||
], |
|
||||
colorRules, |
|
||||
labelNameRules |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapState('labels', ['items', 'selected', 'loading']), |
|
||||
...mapGetters('labels', ['shortkeys']) |
|
||||
}, |
|
||||
|
|
||||
created() { |
|
||||
this.getLabelList({ |
|
||||
projectId: this.$route.params.id |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapActions('labels', ['getLabelList', 'updateLabel']), |
|
||||
...mapMutations('labels', ['updateSelected']), |
|
||||
|
|
||||
handleUpdateLabel(payload) { |
|
||||
const data = { |
|
||||
projectId: this.$route.params.id, |
|
||||
...payload |
|
||||
} |
|
||||
this.updateLabel(data) |
|
||||
}, |
|
||||
|
|
||||
availableShortkeys(suffixKey) { |
|
||||
const usedKeys = this.items.map(item => item.suffix_key) |
|
||||
const unusedKeys = this.shortkeys.filter(item => item === suffixKey || !usedKeys.includes(item)) |
|
||||
return unusedKeys |
|
||||
}, |
|
||||
|
|
||||
textColor(backgroundColor) { |
|
||||
return idealColor(backgroundColor) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -0,0 +1,42 @@ |
|||||
|
<template> |
||||
|
<action-menu |
||||
|
:items="items" |
||||
|
:text="$t('dataset.actions')" |
||||
|
@create="$emit('create')" |
||||
|
@upload="$emit('upload')" |
||||
|
@download="$emit('download')" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import Vue from 'vue' |
||||
|
import ActionMenu from '@/components/molecules/ActionMenu.vue' |
||||
|
|
||||
|
export default Vue.extend({ |
||||
|
components: { |
||||
|
ActionMenu |
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
items() { |
||||
|
return [ |
||||
|
{ |
||||
|
title: this.$t('labels.createLabel'), |
||||
|
icon: 'mdi-pencil', |
||||
|
event: 'create' |
||||
|
}, |
||||
|
{ |
||||
|
title: this.$t('labels.importLabels'), |
||||
|
icon: 'mdi-upload', |
||||
|
event: 'upload' |
||||
|
}, |
||||
|
{ |
||||
|
title: this.$t('labels.exportLabels'), |
||||
|
icon: 'mdi-download', |
||||
|
event: 'download' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
</script> |
@ -0,0 +1,92 @@ |
|||||
|
<template> |
||||
|
<base-card |
||||
|
:disabled="!valid" |
||||
|
:title="$t('labels.createLabel')" |
||||
|
:agree-text="$t('generic.create')" |
||||
|
:cancel-text="$t('generic.cancel')" |
||||
|
@agree="$emit('save')" |
||||
|
@cancel="$emit('cancel')" |
||||
|
> |
||||
|
<template #content> |
||||
|
<v-form |
||||
|
ref="form" |
||||
|
v-model="valid" |
||||
|
> |
||||
|
<v-text-field |
||||
|
v-model="item.text" |
||||
|
:label="$t('labels.labelName')" |
||||
|
:rules="labelNameRules($t('rules.labelNameRules'))" |
||||
|
prepend-icon="label" |
||||
|
single-line |
||||
|
counter |
||||
|
autofocus |
||||
|
/> |
||||
|
<v-select |
||||
|
v-model="item.suffix_key" |
||||
|
:items="shortkeys" |
||||
|
:label="$t('labels.key')" |
||||
|
prepend-icon="mdi-keyboard" |
||||
|
/> |
||||
|
<v-color-picker |
||||
|
v-model="item.background_color" |
||||
|
:rules="colorRules($t('rules.colorRules'))" |
||||
|
show-swatches |
||||
|
hide-mode-switch |
||||
|
width="800" |
||||
|
/> |
||||
|
</v-form> |
||||
|
</template> |
||||
|
</base-card> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import Vue from 'vue' |
||||
|
import BaseCard from '@/components/molecules/BaseCard.vue' |
||||
|
import { colorRules, labelNameRules } from '@/rules/index' |
||||
|
|
||||
|
export default Vue.extend({ |
||||
|
components: { |
||||
|
BaseCard |
||||
|
}, |
||||
|
|
||||
|
props: { |
||||
|
value: { |
||||
|
type: Object, |
||||
|
default: () => {}, |
||||
|
required: true |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
data() { |
||||
|
return { |
||||
|
valid: false, |
||||
|
labelNameRules, |
||||
|
colorRules |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
shortkeys() { |
||||
|
return '0123456789abcdefghijklmnopqrstuvwxyz'.split('') |
||||
|
}, |
||||
|
item: { |
||||
|
get() { |
||||
|
// Property '$emit' does not exist on type '() => any' |
||||
|
// @ts-ignore |
||||
|
return this.value |
||||
|
}, |
||||
|
set(val) { |
||||
|
// Property '$emit' does not exist on type '() => any' |
||||
|
// @ts-ignore |
||||
|
this.$emit('input', val) |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
hoge() { |
||||
|
this.$emit('inpupt') |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
</script> |
@ -0,0 +1,28 @@ |
|||||
|
<template> |
||||
|
<confirm-form |
||||
|
:items="selected" |
||||
|
title="Delete Label" |
||||
|
:message="$t('labels.deleteMessage')" |
||||
|
item-key="text" |
||||
|
@ok="$emit('remove')" |
||||
|
@cancel="$emit('cancel')" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import Vue from 'vue' |
||||
|
import ConfirmForm from '@/components/organisms/utils/ConfirmForm.vue' |
||||
|
|
||||
|
export default Vue.extend({ |
||||
|
components: { |
||||
|
ConfirmForm |
||||
|
}, |
||||
|
|
||||
|
props: { |
||||
|
selected: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
</script> |
@ -0,0 +1,216 @@ |
|||||
|
<template> |
||||
|
<v-data-table |
||||
|
v-model="selected" |
||||
|
:headers="headers" |
||||
|
:items="items" |
||||
|
:search="search" |
||||
|
:loading="isLoading" |
||||
|
:loading-text="$t('generic.loading')" |
||||
|
:no-data-text="$t('vuetify.noDataAvailable')" |
||||
|
:footer-props="{ |
||||
|
'showFirstLastPage': true, |
||||
|
'items-per-page-options': [5, 10, 15, $t('generic.all')], |
||||
|
'items-per-page-text': $t('vuetify.itemsPerPageText'), |
||||
|
'page-text': $t('dataset.pageText') |
||||
|
}" |
||||
|
item-key="id" |
||||
|
show-select |
||||
|
> |
||||
|
<template v-slot:top> |
||||
|
<v-toolbar flat> |
||||
|
<action-menu |
||||
|
@create="dialogCreate=true" |
||||
|
@upload="dialogUpload=true" |
||||
|
@download="download" |
||||
|
/> |
||||
|
<v-btn |
||||
|
class="text-capitalize ms-2" |
||||
|
:disabled="!canDelete" |
||||
|
outlined |
||||
|
@click.stop="dialogDelete=true" |
||||
|
> |
||||
|
{{ $t('generic.delete') }} |
||||
|
</v-btn> |
||||
|
<v-dialog v-model="dialogCreate"> |
||||
|
<form-create |
||||
|
v-model="editedItem" |
||||
|
@cancel="close" |
||||
|
@save="save" |
||||
|
/> |
||||
|
</v-dialog> |
||||
|
<v-dialog v-model="dialogUpload"> |
||||
|
<form-upload |
||||
|
@cancel="dialogUpload=false" |
||||
|
@upload="upload" |
||||
|
/> |
||||
|
</v-dialog> |
||||
|
<v-dialog v-model="dialogDelete"> |
||||
|
<form-delete |
||||
|
:selected="selected" |
||||
|
@cancel="dialogDelete=false" |
||||
|
@remove="remove" |
||||
|
/> |
||||
|
</v-dialog> |
||||
|
</v-toolbar> |
||||
|
<v-text-field |
||||
|
v-model="search" |
||||
|
prepend-inner-icon="search" |
||||
|
:label="$t('generic.search')" |
||||
|
single-line |
||||
|
hide-details |
||||
|
filled |
||||
|
/> |
||||
|
</template> |
||||
|
<template v-slot:[`item.background_color`]="props"> |
||||
|
<v-chip |
||||
|
:color="props.item.background_color" |
||||
|
:text-color="textColor(props.item.background_color)" |
||||
|
> |
||||
|
{{ props.item.background_color }} |
||||
|
</v-chip> |
||||
|
</template> |
||||
|
<template v-slot:[`item.actions`]="{ item }"> |
||||
|
<v-icon |
||||
|
small |
||||
|
@click="editItem(item)" |
||||
|
> |
||||
|
mdi-pencil |
||||
|
</v-icon> |
||||
|
</template> |
||||
|
</v-data-table> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import Vue from 'vue' |
||||
|
import { LabelDTO } from '@/services/application/label.service' |
||||
|
import ActionMenu from './ActionMenu.vue' |
||||
|
import FormCreate from './FormCreate.vue' |
||||
|
import FormDelete from './FormDelete.vue' |
||||
|
import FormUpload from './FormUpload.vue' |
||||
|
import { idealColor } from '~/plugins/utils' |
||||
|
|
||||
|
export default Vue.extend({ |
||||
|
components: { |
||||
|
ActionMenu, |
||||
|
FormCreate, |
||||
|
FormDelete, |
||||
|
FormUpload |
||||
|
}, |
||||
|
|
||||
|
data() { |
||||
|
return { |
||||
|
dialogCreate: false, |
||||
|
dialogDelete: false, |
||||
|
dialogUpload: false, |
||||
|
headers: [ |
||||
|
{ text: this.$t('generic.name'), value: 'text' }, |
||||
|
{ text: this.$t('labels.shortkey'), value: 'suffix_key' }, |
||||
|
{ text: this.$t('labels.color'), value: 'background_color' }, |
||||
|
{ text: 'Actions', value: 'actions', sortable: false }, |
||||
|
], |
||||
|
editedIndex: -1, |
||||
|
editedItem: { |
||||
|
text: '', |
||||
|
prefix_key: null, |
||||
|
suffix_key: null, |
||||
|
background_color: '#2196F3', |
||||
|
text_color: '#ffffff' |
||||
|
} as LabelDTO, |
||||
|
defaultItem: { |
||||
|
text: '', |
||||
|
prefix_key: null, |
||||
|
suffix_key: null, |
||||
|
background_color: '#2196F3', |
||||
|
text_color: '#ffffff' |
||||
|
} as LabelDTO, |
||||
|
isLoading: false, |
||||
|
items: [] as LabelDTO[], |
||||
|
selected: [] as LabelDTO[], |
||||
|
search: '' |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
canDelete(): boolean { |
||||
|
return this.selected.length > 0 |
||||
|
}, |
||||
|
projectId(): string { |
||||
|
return this.$route.params.id |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
created() { |
||||
|
this.list() |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
async list() { |
||||
|
this.isLoading = true |
||||
|
this.items = await this.$services.label.list(this.projectId) |
||||
|
this.isLoading = false |
||||
|
}, |
||||
|
|
||||
|
async create(item: LabelDTO) { |
||||
|
await this.$services.label.create(this.projectId, item) |
||||
|
this.list() |
||||
|
this.dialogCreate = false |
||||
|
}, |
||||
|
|
||||
|
async update(item: LabelDTO) { |
||||
|
await this.$services.label.update(this.projectId, item) |
||||
|
this.list() |
||||
|
this.dialogCreate = false |
||||
|
}, |
||||
|
|
||||
|
async remove() { |
||||
|
await this.$services.label.bulkDelete(this.projectId, this.selected) |
||||
|
this.list() |
||||
|
this.dialogDelete = false |
||||
|
this.selected = [] |
||||
|
}, |
||||
|
|
||||
|
async download() { |
||||
|
await this.$services.label.export(this.projectId) |
||||
|
}, |
||||
|
|
||||
|
async upload(file: File) { |
||||
|
await this.$services.label.upload(this.projectId, file) |
||||
|
this.list() |
||||
|
this.dialogUpload = false |
||||
|
}, |
||||
|
|
||||
|
editItem(item: LabelDTO) { |
||||
|
this.editedIndex = this.items.indexOf(item) |
||||
|
this.editedItem = Object.assign({}, item) |
||||
|
this.dialogCreate = true |
||||
|
}, |
||||
|
|
||||
|
close() { |
||||
|
this.dialogCreate = false |
||||
|
this.$nextTick(() => { |
||||
|
this.editedItem = Object.assign({}, this.defaultItem) |
||||
|
this.editedIndex = -1 |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
save() { |
||||
|
if (this.editedIndex > -1) { |
||||
|
this.update(this.editedItem) |
||||
|
} else { |
||||
|
this.create(this.editedItem) |
||||
|
} |
||||
|
this.close() |
||||
|
}, |
||||
|
|
||||
|
textColor(backgroundColor: string) { |
||||
|
return idealColor(backgroundColor) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
::v-deep .v-dialog { |
||||
|
width: 800px; |
||||
|
} |
||||
|
</style> |
@ -1,112 +0,0 @@ |
|||||
<template> |
|
||||
<base-card |
|
||||
:disabled="!valid" |
|
||||
:title="$t('labels.createLabel')" |
|
||||
:agree-text="$t('generic.create')" |
|
||||
:cancel-text="$t('generic.cancel')" |
|
||||
@agree="create" |
|
||||
@cancel="reset" |
|
||||
> |
|
||||
<template #content> |
|
||||
<v-form |
|
||||
ref="form" |
|
||||
v-model="valid" |
|
||||
> |
|
||||
<v-alert |
|
||||
v-show="showError" |
|
||||
v-model="showError" |
|
||||
type="error" |
|
||||
dismissible |
|
||||
> |
|
||||
{{ $t('errors.labelCannotCreate') }} |
|
||||
</v-alert> |
|
||||
<v-text-field |
|
||||
v-model="labelName" |
|
||||
:rules="labelNameRules($t('rules.labelNameRules'))" |
|
||||
:label="$t('labels.labelName')" |
|
||||
prepend-icon="label" |
|
||||
/> |
|
||||
<v-select |
|
||||
v-model="suffixKey" |
|
||||
:items="keys" |
|
||||
:label="$t('labels.key')" |
|
||||
prepend-icon="mdi-keyboard" |
|
||||
/> |
|
||||
<v-color-picker |
|
||||
v-model="color" |
|
||||
:rules="colorRules($t('rules.colorRules'))" |
|
||||
show-swatches |
|
||||
hide-mode-switch |
|
||||
width="800" |
|
||||
mode="hexa" |
|
||||
class="ma-2" |
|
||||
/> |
|
||||
</v-form> |
|
||||
</template> |
|
||||
</base-card> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import BaseCard from '@/components/molecules/BaseCard' |
|
||||
import { colorRules, labelNameRules } from '@/rules/index' |
|
||||
|
|
||||
export default { |
|
||||
components: { |
|
||||
BaseCard |
|
||||
}, |
|
||||
props: { |
|
||||
createLabel: { |
|
||||
type: Function, |
|
||||
default: () => {}, |
|
||||
required: true |
|
||||
}, |
|
||||
keys: { |
|
||||
type: Array, |
|
||||
default: () => [], |
|
||||
required: true |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
valid: false, |
|
||||
labelName: '', |
|
||||
suffixKey: '', |
|
||||
color: '', |
|
||||
labelNameRules, |
|
||||
colorRules, |
|
||||
showError: false |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
cancel() { |
|
||||
this.$emit('close') |
|
||||
}, |
|
||||
validate() { |
|
||||
return this.$refs.form.validate() |
|
||||
}, |
|
||||
reset() { |
|
||||
this.$refs.form.reset() |
|
||||
this.cancel('close') |
|
||||
}, |
|
||||
create() { |
|
||||
if (this.validate()) { |
|
||||
this.createLabel({ |
|
||||
projectId: this.$route.params.id, |
|
||||
text: this.labelName, |
|
||||
prefix_key: null, |
|
||||
suffix_key: this.suffixKey ? this.suffixKey : null, |
|
||||
background_color: this.color.slice(0, 7), // #12345678 -> #123456 |
|
||||
text_color: '#ffffff' |
|
||||
}) |
|
||||
.then(() => { |
|
||||
this.reset() |
|
||||
}) |
|
||||
.catch(() => { |
|
||||
this.showError = true |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
Write
Preview
Loading…
Cancel
Save