update editor

This commit is contained in:
2026-07-21 00:32:31 +07:00
parent db558c87d1
commit 16114bb134
2 changed files with 189 additions and 105 deletions
+149 -63
View File
@@ -1,7 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { NDynamicInput, NInput, NInputGroup, NSpace, NSwitch } from 'naive-ui' import { NDynamicInput, NInput, NInputGroup, NSpace, NSwitch } from 'naive-ui'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { LockOutlined } from '@vicons/material'
import { Icon } from '@vicons/utils'
import { Key24Regular } from '@vicons/fluent'
import type { Application, Door, Key, Place } from '@/api/generated/crabs/evening_detective_server' import type { Application, Door, Key, Place } from '@/api/generated/crabs/evening_detective_server'
const props = defineProps({ const props = defineProps({
@@ -44,57 +46,66 @@ function onCreateKey(): Key {
</script> </script>
<template> <template>
<div <div v-if="mode == 'mini-add'" class="place-block-hover show-editor-block" @click="updateMode('add')">
v-if="mode == 'mini-add'"
class="place-block-plus show-editor-block"
@click="updateMode('edit')"
>
<p class="place-image-plus">+</p> <p class="place-image-plus">+</p>
</div> </div>
<div <div v-if="mode == 'add'" class="place-block">
v-if="mode == 'show-editor'" <n-space vertical>
class="place-block show-editor-block" <n-input-group>
@click="updateMode('edit')" <n-input :style="{ width: '20%' }" v-model:value="props.place.code" type="text" placeholder="Ы-1" />
> <n-input :style="{ width: '80%' }" v-model:value="props.place.name" type="text" placeholder="Дом №Ы" />
</n-input-group>
<slot></slot>
</n-space>
</div>
<div v-if="mode == 'show-editor'" class="place-block-hover show-editor-block" @click="updateMode('edit')">
<p>[{{ props.place.code }}] - {{ props.place.name }}</p> <p>[{{ props.place.code }}] - {{ props.place.name }}</p>
<div class="message-content">{{ props.place.text }}</div> <div class="message-content">{{ props.place.text }}</div>
<p v-for="application in props.place.applications" v-bind:key="application.name">
{{ application.name }} <div v-for="door in props.place.doors" v-bind:key="door.code" class="door-block">
{{ door.name }} <span v-for="key in door.keys" class="key-block">
<Icon class="lock-icon">
<LockOutlined />
</Icon> {{ key.name }}
</span>
</div>
<div v-for="application in props.place.applications" v-bind:key="application.name" class="application-block">
Приложение: {{ application.name }}
</div>
<p class="gray-block">
<span v-if="place.hidden">
Скрытая точка
</span>
<span v-for="key in place.keys" class="key-block">
<Icon class="lock-icon">
<Key24Regular />
</Icon> {{ key.name }}
</span>
</p> </p>
</div> </div>
<div v-if="mode == 'edit'" class="place-block"> <div v-if="mode == 'edit'" class="place-block">
<n-space vertical> <n-space vertical>
<n-input-group> <n-input-group>
<n-input <n-input :style="{ width: '20%' }" v-model:value="props.place.code" type="text" placeholder="Ы-1" />
:style="{ width: '20%' }" <n-input :style="{ width: '80%' }" v-model:value="props.place.name" type="text" placeholder="Дом №Ы" />
v-model:value="props.place.code"
type="text"
placeholder="Ы-1"
/>
<n-input
:style="{ width: '80%' }"
v-model:value="props.place.name"
type="text"
placeholder="Дом №Ы"
/>
</n-input-group> </n-input-group>
<n-input <n-input v-model:value="props.place.text" type="textarea" :autosize="{ minRows: 3 }"
v-model:value="props.place.text" placeholder="В начале было слово..." />
type="textarea" <n-switch v-model:value="props.place.hidden">
:autosize="{ minRows: 3 }" <template #checked>
placeholder="В начале было слово..." Скрытая точка
/> </template>
<!-- <n-upload multiple directory-dnd :max="1" v-model:file-list="newPlaceFileList"> <template #unchecked>
<n-upload-dragger> Обычная точка
<n-text style="font-size: 16px"> </template>
Щелкните или перетащите файл в эту область для загрузки </n-switch>
</n-text>
</n-upload-dragger>
</n-upload> -->
<n-switch v-model:value="props.place.hidden" />
Улики
<n-dynamic-input v-model:value="props.place.applications" :on-create="onCreateApplication"> <n-dynamic-input v-model:value="props.place.applications" :on-create="onCreateApplication">
<template #create-button-default> Добавить улику </template> <template #create-button-default> Добавить улику </template>
<template #default="{ value }"> <template #default="{ value }">
@@ -104,25 +115,42 @@ function onCreateKey(): Key {
</template> </template>
</n-dynamic-input> </n-dynamic-input>
Действия
<n-dynamic-input v-model:value="props.place.doors" :on-create="onCreateDoor"> <n-dynamic-input v-model:value="props.place.doors" :on-create="onCreateDoor">
<template #create-button-default> Добавить действие </template> <template #create-button-default> Добавить действие </template>
<template #action="{ index, create, remove }">
<div style="display: flex; flex-direction: column;">
<n-button @click="() => create(index)" class="plus-minus-buttons">+</n-button>
<n-button disabled @click="() => remove(index)" class="plus-minus-buttons">-</n-button>
</div>
</template>
<template #default="{ value: door }"> <template #default="{ value: door }">
<div style="display: flex; align-items: center; width: 100%"> <div style="display: flex; flex-direction: column; width: 100%">
<n-input v-model:value="door.code" type="text" placeholder="Код" />
<n-input v-model:value="door.name" type="text" placeholder="Название" /> <div class="door-add-block">
<n-input-group>
<n-input :style="{ width: '30%' }" v-model:value="door.code" type="text" placeholder="Код" />
<n-input :style="{ width: '70%' }" v-model:value="door.name" type="text" placeholder="Название" />
</n-input-group>
<p class="need-keys-text">Требуемые ключи</p>
<div class="door-field">
<n-dynamic-input v-model:value="door.keys" :on-create="onCreateKey">
<template #create-button-default> Добавить ключ </template>
<template #default="{ value: key }">
<div style="display: flex; align-items: center; width: 100%">
<n-input v-model:value="key.name" type="text" placeholder="Название" />
</div>
</template>
</n-dynamic-input>
</div>
</div>
<n-dynamic-input v-model:value="door.keys" :on-create="onCreateKey">
<template #create-button-default> Добавить ключ </template>
<template #default="{ value: key }">
<div style="display: flex; align-items: center; width: 100%">
<n-input v-model:value="key.name" type="text" placeholder="Название" />
</div>
</template>
</n-dynamic-input>
</div> </div>
</template> </template>
</n-dynamic-input> </n-dynamic-input>
Получаемые ключи
<n-dynamic-input v-model:value="props.place.keys" :on-create="onCreateKey"> <n-dynamic-input v-model:value="props.place.keys" :on-create="onCreateKey">
<template #create-button-default> Добавить ключ </template> <template #create-button-default> Добавить ключ </template>
<template #default="{ value: key }"> <template #default="{ value: key }">
@@ -132,30 +160,23 @@ function onCreateKey(): Key {
</template> </template>
</n-dynamic-input> </n-dynamic-input>
<slot></slot> <div class="slot-block">
<slot></slot>
</div>
</n-space> </n-space>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.place-block-hover,
.place-block { .place-block {
margin: 20px; margin: 10px 5px;
padding: 20px; padding: 20px;
border-radius: 10px; border-radius: 10px;
border: 1px solid #444; border: 1px solid #444;
} }
.place-block:hover { .place-block-hover:hover {
color: #63e2b7;
}
.place-block-plus {
margin: 20px;
border-radius: 10px;
border: 1px solid #444;
}
.place-block-plus:hover {
color: #63e2b7; color: #63e2b7;
} }
@@ -173,4 +194,69 @@ function onCreateKey(): Key {
.message-content { .message-content {
white-space: pre-wrap; white-space: pre-wrap;
} }
.gray-block {
margin-top: 5px;
color: #777;
}
.application-block {
margin-right: 5px;
color: burlywood;
}
.door-block {
display: inline-block;
margin: 10px 5px 10px 0;
padding: 5px 10px;
border-radius: 5px;
background-color: #222;
color: #eee;
}
.door-add-block {
padding: 10px;
border-radius: 5px;
background-color: #222;
color: #eee;
}
.key-block {
color: gold;
margin-left: 10px;
}
.lock-icon {
position: relative;
top: 2px;
}
.door-field {
margin-top: 10px;
}
.need-keys-text {
color: gold;
margin: 15px 0 0 0;
padding: 0;
}
.slot-block {
margin-top: 10px;
}
.plus-minus-buttons {
border: 1px solid #444;
padding: 0 13px;
margin: 0 0 10px 5px;
text-align: center;
color: #eee;
font-size: 25px;
border-radius: 40px;
}
.plus-minus-buttons:hover {
cursor: pointer;
color: #63e2b7;
}
</style> </style>
+40 -42
View File
@@ -126,9 +126,37 @@ async function addPlace() {
applications: undefined, applications: undefined,
doors: undefined, doors: undefined,
keys: undefined, keys: undefined,
mode: 'add'
} }
} }
async function addNotFoundDoors(scenario: Scenario, place: Place) {
place.doors?.forEach(async (door) => {
let place = scenario.story?.places?.find((place) => {
return place.code == door.code
})
if (place == undefined) {
const res = await client.AddScenarioPlace({
id: scenario.id,
place: {
code: door.code,
name: door.name,
text: undefined,
image: undefined,
hidden: undefined,
applications: undefined,
doors: undefined,
keys: undefined
},
})
if (res.error != '') {
message.error(res.error!)
return
}
}
})
}
async function collapseAddPlace(place: Place) { async function collapseAddPlace(place: Place) {
place.mode = 'mini-add' place.mode = 'mini-add'
} }
@@ -140,6 +168,7 @@ async function cancelUpdatePlace(place: Place) {
} }
async function updatePlace(place: Place) { async function updatePlace(place: Place) {
await addNotFoundDoors(scenario.value, place)
const res = await client.UpdateScenarioPlace({ const res = await client.UpdateScenarioPlace({
id: scenario.value.id, id: scenario.value.id,
code: place.oldCode, code: place.oldCode,
@@ -188,12 +217,8 @@ async function deletePlace(place: Place) {
</n-flex> </n-flex>
</PlaceBlock> </PlaceBlock>
<PlaceBlock <PlaceBlock :place="place" v-model:mode="place.mode" v-for="place in scenario.story?.places"
:place="place" v-bind:key="place.code">
v-model:mode="place.mode"
v-for="place in scenario.story?.places"
v-bind:key="place.code"
>
<n-flex justify="end"> <n-flex justify="end">
<n-button @click="deletePlace(place)" type="error" ghost>Удалить</n-button> <n-button @click="deletePlace(place)" type="error" ghost>Удалить</n-button>
<n-button @click="cancelUpdatePlace(place)">Отмена</n-button> <n-button @click="cancelUpdatePlace(place)">Отмена</n-button>
@@ -205,39 +230,20 @@ async function deletePlace(place: Place) {
<!-- Окно настроек сценария --> <!-- Окно настроек сценария -->
<n-modal v-model:show="showSettingsScenarioModal"> <n-modal v-model:show="showSettingsScenarioModal">
<n-card <n-card style="width: 600px" title="Настройки сценария" :bordered="false" size="huge" role="dialog"
style="width: 600px" aria-modal="true">
title="Настройки сценария"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<template #header-extra> <template #header-extra>
<n-button @click="showSettingsScenarioModal = false"> x </n-button> <n-button @click="showSettingsScenarioModal = false"> x </n-button>
</template> </template>
<n-space vertical> <n-space vertical>
<p>Название</p> <p>Название</p>
<n-input <n-input v-model:value="scenario.name" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
v-model:value="scenario.name"
type="text"
placeholder='Дело №0 "Следствие ведут овечки"'
/>
<p class="settings-header">Описание</p> <p class="settings-header">Описание</p>
<n-input <n-input v-model:value="scenario.description" type="textarea" placeholder="Убийство пастуха..." />
v-model:value="scenario.description"
type="textarea"
placeholder="Убийство пастуха..."
/>
<p class="settings-header">Картинка</p> <p class="settings-header">Картинка</p>
<n-input <n-input v-model:value="scenario.image" type="text" placeholder="default_scenario.png" disabled />
v-model:value="scenario.image"
type="text"
placeholder="default_scenario.png"
disabled
/>
<n-upload multiple directory-dnd :max="1" v-model:file-list="fileList"> <n-upload multiple directory-dnd :max="1" v-model:file-list="fileList">
<n-upload-dragger> <n-upload-dragger>
<n-text style="font-size: 16px"> <n-text style="font-size: 16px">
@@ -254,17 +260,9 @@ async function deletePlace(place: Place) {
Введите название сценария Введите название сценария
<n-text class="name-text" strong>{{ scenario.name }}</n-text> чтобы удалить его <n-text class="name-text" strong>{{ scenario.name }}</n-text> чтобы удалить его
</p> </p>
<n-input <n-input v-model:value="deletedScenarioName" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
v-model:value="deletedScenarioName" <n-button @click="deleteScenario(scenario.id!)" type="error" ghost
type="text" :disabled="deletedScenarioName != scenario.name">
placeholder='Дело №0 "Следствие ведут овечки"'
/>
<n-button
@click="deleteScenario(scenario.id!)"
type="error"
ghost
:disabled="deletedScenarioName != scenario.name"
>
Удалить сценарий Удалить сценарий
</n-button> </n-button>
</n-space> </n-space>
@@ -312,7 +310,7 @@ async function deletePlace(place: Place) {
/* border: 1px solid red; */ /* border: 1px solid red; */
} }
@media (width >= 1024px) { @media (width >=1024px) {
.places-container { .places-container {
padding: 20px 250px; padding: 20px 250px;
height: calc(100vh - 70px); height: calc(100vh - 70px);