generated from VLADIMIR/template_frontend
add background
This commit is contained in:
@@ -206,6 +206,7 @@ export type Scenario = {
|
||||
};
|
||||
|
||||
export type Story = {
|
||||
background: string | undefined;
|
||||
introduction: Introduction | undefined;
|
||||
places: Place[] | undefined;
|
||||
questions: Question[] | undefined;
|
||||
@@ -654,6 +655,15 @@ export type SetTeamAnswerScoreRsp = {
|
||||
error: string | undefined;
|
||||
};
|
||||
|
||||
export type UpdateScenarioBackgroundReq = {
|
||||
id: number | undefined;
|
||||
background: string | undefined;
|
||||
};
|
||||
|
||||
export type UpdateScenarioBackgroundRsp = {
|
||||
error: string | undefined;
|
||||
};
|
||||
|
||||
export interface EveningDetectiveServer {
|
||||
Ping(request: PingReq): Promise<PingRsp>;
|
||||
Echo(request: EchoReq): Promise<EchoRsp>;
|
||||
@@ -688,6 +698,8 @@ export interface EveningDetectiveServer {
|
||||
AddScenarioQuestion(request: AddScenarioQuestionReq): Promise<AddScenarioQuestionRsp>;
|
||||
UpdateScenarioQuestion(request: UpdateScenarioQuestionReq): Promise<UpdateScenarioQuestionRsp>;
|
||||
DeleteScenarioQuestion(request: DeleteScenarioQuestionReq): Promise<DeleteScenarioQuestionRsp>;
|
||||
// Загрузить файл через UploadFile, затем передать его имя; пустое имя удаляет фон дела.
|
||||
UpdateScenarioBackground(request: UpdateScenarioBackgroundReq): Promise<UpdateScenarioBackgroundRsp>;
|
||||
UpdateScenarioIntro(request: UpdateScenarioIntroReq): Promise<UpdateScenarioIntroRsp>;
|
||||
DownloadScenarioArchive(request: DownloadScenarioArchiveReq): Promise<googleapi_HttpBody>;
|
||||
UploadScenarioArchive(request: googleapi_HttpBody): Promise<UploadScenarioArchiveRsp>;
|
||||
@@ -1351,6 +1363,26 @@ export function createEveningDetectiveServerClient(
|
||||
method: "DeleteScenarioQuestion",
|
||||
}) as Promise<DeleteScenarioQuestionRsp>;
|
||||
},
|
||||
UpdateScenarioBackground(request) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
if (!request.id) {
|
||||
throw new Error("missing required field request.id");
|
||||
}
|
||||
const path = `api/scenarios/${request.id}/background`; // eslint-disable-line quotes
|
||||
const body = JSON.stringify(request);
|
||||
const queryParams: string[] = [];
|
||||
let uri = path;
|
||||
if (queryParams.length > 0) {
|
||||
uri += `?${queryParams.join("&")}`
|
||||
}
|
||||
return handler({
|
||||
path: uri,
|
||||
method: "PUT",
|
||||
body,
|
||||
}, {
|
||||
service: "EveningDetectiveServer",
|
||||
method: "UpdateScenarioBackground",
|
||||
}) as Promise<UpdateScenarioBackgroundRsp>;
|
||||
},
|
||||
UpdateScenarioIntro(request) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
if (!request.id) {
|
||||
throw new Error("missing required field request.id");
|
||||
|
||||
@@ -59,6 +59,9 @@ const scenario = ref<Scenario>({
|
||||
publishedAt: undefined,
|
||||
})
|
||||
|
||||
const backgroundFiles = ref<UploadFileInfo[]>([])
|
||||
const savingBackground = ref(false)
|
||||
|
||||
const intro = ref<EditableIntroduction>({ text: '', audio: '' })
|
||||
const introMode = ref('show-editor')
|
||||
|
||||
@@ -489,6 +492,38 @@ async function updateIntro() {
|
||||
await getScenario(Number(scenarioId))
|
||||
}
|
||||
|
||||
async function updateBackground(remove = false) {
|
||||
savingBackground.value = true
|
||||
try {
|
||||
let background = ''
|
||||
if (!remove) {
|
||||
const file = backgroundFiles.value[0]?.file
|
||||
if (!file) return
|
||||
const uploaded = await uploadFile(
|
||||
file,
|
||||
'scenarios_' + scenario.value.id + '_background_' + file.name,
|
||||
)
|
||||
if (!uploaded.filename) return
|
||||
if (uploaded.fileType !== 'image') {
|
||||
message.error('Фон дела должен быть изображением')
|
||||
return
|
||||
}
|
||||
background = uploaded.filename
|
||||
}
|
||||
const res = await client.UpdateScenarioBackground({ id: scenario.value.id, background })
|
||||
if (res.error) {
|
||||
message.error(res.error)
|
||||
return
|
||||
}
|
||||
await getScenario(Number(scenarioId))
|
||||
backgroundFiles.value = []
|
||||
} catch {
|
||||
message.error('Не удалось сохранить фон дела')
|
||||
} finally {
|
||||
savingBackground.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function cancelUpdateIntro() {
|
||||
await getScenario(Number(scenarioId))
|
||||
}
|
||||
@@ -545,6 +580,40 @@ function getRandomComplimentForNastya() {
|
||||
</n-button>
|
||||
</div>
|
||||
|
||||
<n-card title="Фон дела">
|
||||
<n-space vertical>
|
||||
<img
|
||||
v-if="scenario.story?.background"
|
||||
:src="scenario.story.background"
|
||||
alt="Фон дела"
|
||||
class="background-preview"
|
||||
/>
|
||||
<n-upload
|
||||
v-model:file-list="backgroundFiles"
|
||||
accept=".jpg,.jpeg,.png,.gif,.webp"
|
||||
:max="1"
|
||||
:default-upload="false"
|
||||
:disabled="savingBackground"
|
||||
>
|
||||
<n-button :disabled="savingBackground">Выбрать фон</n-button>
|
||||
</n-upload>
|
||||
<n-flex>
|
||||
<n-button
|
||||
:loading="savingBackground"
|
||||
:disabled="!backgroundFiles.length || savingBackground"
|
||||
@click="updateBackground()"
|
||||
>Сохранить фон</n-button
|
||||
>
|
||||
<n-button
|
||||
v-if="scenario.story?.background"
|
||||
:disabled="savingBackground"
|
||||
@click="updateBackground(true)"
|
||||
>Удалить фон</n-button
|
||||
>
|
||||
</n-flex>
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<IntroBlock :introduction="intro" v-model:mode="introMode">
|
||||
<n-flex justify="end">
|
||||
<n-button @click="cancelUpdateIntro()">Отмена</n-button>
|
||||
@@ -748,6 +817,12 @@ function getRandomComplimentForNastya() {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.background-preview {
|
||||
max-height: 200px;
|
||||
max-width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.settings-block {
|
||||
height: 40px;
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ async function getStory() {
|
||||
const oldCount = story.value.places.length
|
||||
|
||||
story.value = {
|
||||
background: res.story!.background,
|
||||
introduction: res.story!.introduction,
|
||||
places:
|
||||
res.story!.places?.map((item, i) => {
|
||||
@@ -127,6 +128,7 @@ async function addAction(newCode: string) {
|
||||
}
|
||||
|
||||
type AdvancedStory = {
|
||||
background?: string
|
||||
introduction?: Introduction
|
||||
places: AdvancedPlace[]
|
||||
questions: Question[]
|
||||
@@ -225,6 +227,12 @@ useSimplePolling(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="story.background"
|
||||
class="case-background"
|
||||
:style="{ backgroundImage: `url(${JSON.stringify(story.background)})` }"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div class="center-block-custom bottom-margin smooth-scroll" ref="scrollContainer">
|
||||
<div class="width700">
|
||||
<GameInputForm
|
||||
@@ -309,6 +317,15 @@ useSimplePolling(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.case-background {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
inset: 70px 0 0;
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bottom-margin {
|
||||
height: calc(100dvh - 70px - 76px);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user