hippofish/packages/frontend/src/pages/admin/ads.vue

256 lines
7 KiB
Vue
Raw Normal View History

<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header>
2023-10-29 08:09:20 +01:00
<XHeader :actions="headerActions" :tabs="headerTabs"/>
</template>
2023-05-19 13:52:15 +02:00
<MkSpacer :contentMax="900">
<MkSwitch :modelValue="publishing" @update:modelValue="onChangePublishing">
{{ i18n.ts.publishing }}
</MkSwitch>
2023-05-19 13:52:15 +02:00
<div>
<div v-for="ad in ads" class="_panel _gaps_m" :class="$style.ad">
2023-10-29 08:09:20 +01:00
<MkAd v-if="ad.url" :specify="ad"/>
2023-01-05 13:04:56 +01:00
<MkInput v-model="ad.url" type="url">
<template #label>URL</template>
</MkInput>
<MkInput v-model="ad.imageUrl" type="url">
<template #label>{{ i18n.ts.imageUrl }}</template>
</MkInput>
2023-01-07 07:09:46 +01:00
<MkRadios v-model="ad.place">
<template #label>Form</template>
<option value="square">square</option>
<option value="horizontal">horizontal</option>
<option value="horizontal-big">horizontal-big</option>
2023-01-07 07:09:46 +01:00
</MkRadios>
<!--
2021-10-23 21:03:07 +02:00
<div style="margin: 32px 0;">
{{ i18n.ts.priority }}
<MkRadio v-model="ad.priority" value="high">{{ i18n.ts.high }}</MkRadio>
<MkRadio v-model="ad.priority" value="middle">{{ i18n.ts.middle }}</MkRadio>
<MkRadio v-model="ad.priority" value="low">{{ i18n.ts.low }}</MkRadio>
2021-10-23 21:03:07 +02:00
</div>
-->
<FormSplit>
<MkInput v-model="ad.ratio" type="number">
<template #label>{{ i18n.ts.ratio }}</template>
</MkInput>
2023-02-15 06:31:59 +01:00
<MkInput v-model="ad.startsAt" type="datetime-local">
<template #label>{{ i18n.ts.startingperiod }}</template>
</MkInput>
<MkInput v-model="ad.expiresAt" type="datetime-local">
<template #label>{{ i18n.ts.expiration }}</template>
</MkInput>
</FormSplit>
<MkFolder>
<template #label>{{ i18n.ts.advancedSettings }}</template>
<span>
{{ i18n.ts._ad.timezoneinfo }}
<div v-for="(day, index) in daysOfWeek" :key="index">
2023-10-29 08:09:20 +01:00
<input
:id="`ad${ad.id}-${index}`" type="checkbox" :checked="(ad.dayOfWeek & (1 << index)) !== 0"
@change="toggleDayOfWeek(ad, index)"
>
<label :for="`ad${ad.id}-${index}`">{{ day }}</label>
</div>
</span>
</MkFolder>
2023-01-05 13:04:56 +01:00
<MkTextarea v-model="ad.memo">
<template #label>{{ i18n.ts.memo }}</template>
</MkTextarea>
2023-01-05 13:04:56 +01:00
<div class="buttons">
2023-10-29 08:09:20 +01:00
<MkButton class="button" inline primary style="margin-right: 12px;" @click="save(ad)">
<i
2023-10-31 19:33:24 +01:00
class="ph-floppy-disk ph-bold pg-lg"
2023-10-29 08:09:20 +01:00
></i> {{ i18n.ts.save }}
</MkButton>
<MkButton class="button" inline danger @click="remove(ad)">
2023-10-31 19:33:24 +01:00
<i class="ph-trash ph-bold ph-lg"></i> {{ i18n.ts.remove }}
</MkButton>
</div>
2021-10-23 21:03:07 +02:00
</div>
<MkButton class="button" @click="more()">
2023-09-30 21:53:52 +02:00
<i class="ph-arrow-clockwise ph-bold ph-lg"></i>{{ i18n.ts.more }}
</MkButton>
2023-02-21 02:41:09 +01:00
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { } from 'vue';
import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue';
2023-01-07 07:09:46 +01:00
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from '@/components/MkSwitch.vue';
2021-12-30 13:47:48 +01:00
import FormSplit from '@/components/form/split.vue';
2023-09-19 09:37:43 +02:00
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let ads: any[] = $ref([]);
// ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化
const localTime = new Date();
const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000;
const daysOfWeek: string[] = [i18n.ts._weekday.sunday, i18n.ts._weekday.monday, i18n.ts._weekday.tuesday, i18n.ts._weekday.wednesday, i18n.ts._weekday.thursday, i18n.ts._weekday.friday, i18n.ts._weekday.saturday];
let publishing = false;
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
ads = adsResponse.map(r => {
const exdate = new Date(r.expiresAt);
2023-02-15 06:31:59 +01:00
const stdate = new Date(r.startsAt);
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
stdate.setMilliseconds(stdate.getMilliseconds() - localTimeDiff);
return {
...r,
expiresAt: exdate.toISOString().slice(0, 16),
2023-02-15 06:31:59 +01:00
startsAt: stdate.toISOString().slice(0, 16),
};
});
});
const onChangePublishing = (v) => {
publishing = v;
refresh();
};
2023-10-29 08:09:20 +01:00
// 選択された曜日(index)のビットフラグを操作する
function toggleDayOfWeek(ad, index) {
ad.dayOfWeek ^= 1 << index;
}
function add() {
ads.unshift({
id: null,
memo: '',
place: 'square',
priority: 'middle',
ratio: 1,
url: '',
imageUrl: null,
expiresAt: null,
2023-02-15 06:31:59 +01:00
startsAt: null,
dayOfWeek: 0,
});
}
function remove(ad) {
os.confirm({
type: 'warning',
text: i18n.t('removeAreYouSure', { x: ad.url }),
}).then(({ canceled }) => {
if (canceled) return;
ads = ads.filter(x => x !== ad);
if (ad.id == null) return;
os.apiWithDialog('admin/ad/delete', {
id: ad.id,
}).then(() => {
refresh();
});
});
}
function save(ad) {
if (ad.id == null) {
os.api('admin/ad/create', {
...ad,
expiresAt: new Date(ad.expiresAt).getTime(),
2023-02-15 06:31:59 +01:00
startsAt: new Date(ad.startsAt).getTime(),
}).then(() => {
os.alert({
type: 'success',
text: i18n.ts.saved,
});
refresh();
}).catch(err => {
os.alert({
type: 'error',
text: err,
});
});
} else {
os.api('admin/ad/update', {
...ad,
expiresAt: new Date(ad.expiresAt).getTime(),
2023-02-15 06:31:59 +01:00
startsAt: new Date(ad.startsAt).getTime(),
}).then(() => {
os.alert({
type: 'success',
text: i18n.ts.saved,
});
}).catch(err => {
os.alert({
type: 'error',
text: err,
});
});
}
}
2023-10-29 08:09:20 +01:00
function more() {
os.api('admin/ad/list', { untilId: ads.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => {
2023-02-21 02:41:09 +01:00
ads = ads.concat(adsResponse.map(r => {
const exdate = new Date(r.expiresAt);
const stdate = new Date(r.startsAt);
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
stdate.setMilliseconds(stdate.getMilliseconds() - localTimeDiff);
return {
...r,
expiresAt: exdate.toISOString().slice(0, 16),
startsAt: stdate.toISOString().slice(0, 16),
};
}));
});
}
function refresh() {
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
ads = adsResponse.map(r => {
const exdate = new Date(r.expiresAt);
const stdate = new Date(r.startsAt);
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
stdate.setMilliseconds(stdate.getMilliseconds() - localTimeDiff);
return {
...r,
expiresAt: exdate.toISOString().slice(0, 16),
startsAt: stdate.toISOString().slice(0, 16),
};
});
});
}
refresh();
const headerActions = $computed(() => [{
asFullButton: true,
2023-09-30 21:53:52 +02:00
icon: 'ph-plus ph-bold ph-lg',
text: i18n.ts.add,
handler: add,
}]);
const headerTabs = $computed(() => []);
definePageMetadata({
title: i18n.ts.ads,
2023-10-01 00:46:42 +02:00
icon: 'ph-flag ph-bold ph-lg',
});
</script>
2023-05-19 13:52:15 +02:00
<style lang="scss" module>
.ad {
padding: 32px;
2021-12-10 07:33:01 +01:00
2023-05-19 13:52:15 +02:00
&:not(:last-child) {
margin-bottom: var(--margin);
2021-12-10 07:33:01 +01:00
}
}
</style>