ваше сообщение коммита
This commit is contained in:
@@ -1,5 +1,21 @@
|
||||
<template>
|
||||
<td>
|
||||
<template v-if="column.type === 'tags'">
|
||||
<div v-if="!editing" @click="editing = true" class="tags-cell-view">
|
||||
<span v-if="selectedTagNames.length">{{ selectedTagNames.join(', ') }}</span>
|
||||
<span v-else style="color:#bbb">—</span>
|
||||
</div>
|
||||
<div v-else class="tags-cell-edit">
|
||||
<div class="tags-multiselect">
|
||||
<div v-for="tag in allTags" :key="tag.id" class="tag-option">
|
||||
<input type="checkbox" :id="'cell-tag-' + tag.id + '-' + rowId" :value="tag.id" v-model="editTagIds" />
|
||||
<label :for="'cell-tag-' + tag.id + '-' + rowId">{{ tag.name }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="save-btn" @click="saveTags">Сохранить</button>
|
||||
<button class="cancel-btn" @click="cancelTags">Отмена</button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<input
|
||||
v-model="localValue"
|
||||
@blur="save"
|
||||
@@ -7,26 +23,77 @@
|
||||
:placeholder="column.name"
|
||||
class="cell-input"
|
||||
/>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
const props = defineProps(['rowId', 'column', 'cellValues']);
|
||||
const emit = defineEmits(['update']);
|
||||
|
||||
const localValue = ref('');
|
||||
const editing = ref(false);
|
||||
const allTags = ref([]); // Все теги из /api/tags
|
||||
const editTagIds = ref([]); // id выбранных тегов в режиме редактирования
|
||||
|
||||
// Для отображения выбранных тегов
|
||||
const selectedTagNames = ref([]);
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.column.type === 'tags') {
|
||||
await loadTags();
|
||||
updateSelectedTagNames();
|
||||
}
|
||||
});
|
||||
|
||||
async function loadTags() {
|
||||
const res = await fetch('/api/tags');
|
||||
allTags.value = await res.json();
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.rowId, props.column.id, props.cellValues],
|
||||
() => {
|
||||
const cell = props.cellValues.find(
|
||||
c => c.row_id === props.rowId && c.column_id === props.column.id
|
||||
);
|
||||
localValue.value = cell ? cell.value : '';
|
||||
if (props.column.type === 'tags') {
|
||||
// Значение ячейки — строка с JSON-массивом id тегов
|
||||
const cell = props.cellValues.find(
|
||||
c => c.row_id === props.rowId && c.column_id === props.column.id
|
||||
);
|
||||
let ids = [];
|
||||
if (cell && cell.value) {
|
||||
try {
|
||||
ids = JSON.parse(cell.value);
|
||||
} catch {}
|
||||
}
|
||||
editTagIds.value = Array.isArray(ids) ? ids : [];
|
||||
updateSelectedTagNames();
|
||||
} else {
|
||||
const cell = props.cellValues.find(
|
||||
c => c.row_id === props.rowId && c.column_id === props.column.id
|
||||
);
|
||||
localValue.value = cell ? cell.value : '';
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function updateSelectedTagNames() {
|
||||
if (props.column.type === 'tags') {
|
||||
selectedTagNames.value = allTags.value
|
||||
.filter(tag => editTagIds.value.includes(tag.id))
|
||||
.map(tag => tag.name);
|
||||
}
|
||||
}
|
||||
|
||||
function saveTags() {
|
||||
emit('update', JSON.stringify(editTagIds.value));
|
||||
editing.value = false;
|
||||
}
|
||||
function cancelTags() {
|
||||
editing.value = false;
|
||||
updateSelectedTagNames();
|
||||
}
|
||||
|
||||
function save() {
|
||||
emit('update', localValue.value);
|
||||
}
|
||||
@@ -46,4 +113,52 @@ function save() {
|
||||
border: 1.5px solid #2ecc40;
|
||||
outline: none;
|
||||
}
|
||||
.tags-cell-view {
|
||||
min-height: 1.7em;
|
||||
cursor: pointer;
|
||||
padding: 0.2em 0.1em;
|
||||
}
|
||||
.tags-cell-edit {
|
||||
background: #f8f8f8;
|
||||
border-radius: 6px;
|
||||
padding: 0.3em 0.2em 0.5em 0.2em;
|
||||
}
|
||||
.tags-multiselect {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.2em;
|
||||
margin-bottom: 0.7em;
|
||||
}
|
||||
.tag-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
}
|
||||
.save-btn {
|
||||
background: #2ecc40;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 0.3em 1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
margin-right: 0.7em;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.save-btn:hover {
|
||||
background: #27ae38;
|
||||
}
|
||||
.cancel-btn {
|
||||
background: #eaeaea;
|
||||
color: #333;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 0.3em 1em;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.cancel-btn:hover {
|
||||
background: #d5d5d5;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user