Improve ad

This commit is contained in:
syuilo 2021-05-07 14:22:13 +09:00
parent 3d7c3c39ff
commit b60f9fbc00
9 changed files with 72 additions and 18 deletions

View file

@ -756,6 +756,7 @@ high: "高"
middle: "中" middle: "中"
low: "低" low: "低"
emailNotConfiguredWarning: "メールアドレスの設定がされていません。" emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
ratio: "比率"
_forgotPassword: _forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。" enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"

View file

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class ad21620364649428 implements MigrationInterface {
name = 'ad21620364649428'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "ad" ADD "ratio" integer NOT NULL DEFAULT '1'`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "ratio"`);
}
}

View file

@ -19,7 +19,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref } from 'vue'; import { defineComponent, ref } from 'vue';
import { instance } from '@client/instance'; import { Instance, instance } from '@client/instance';
import { host } from '@client/config'; import { host } from '@client/config';
import MkButton from '@client/components/ui/button.vue'; import MkButton from '@client/components/ui/button.vue';
@ -45,32 +45,45 @@ export default defineComponent({
showMenu.value = !showMenu.value; showMenu.value = !showMenu.value;
}; };
let ad = null; const choseAd = (): Instance['ads'][number] | null => {
if (props.specify) { if (props.specify) {
ad = props.specify; return props.specify as Instance['ads'][number];
} else { }
let ads = instance.ads.filter(ad => props.prefer.includes(ad.place)); let ads = instance.ads.filter(ad => props.prefer.includes(ad.place));
if (ads.length === 0) { if (ads.length === 0) {
ads = instance.ads.filter(ad => ad.place === 'square'); ads = instance.ads.filter(ad => ad.place === 'square');
} }
const high = ads.filter(ad => ad.priority === 'high'); const lowPriorityAds = ads.filter(ad => ad.ratio === 0);
const middle = ads.filter(ad => ad.priority === 'middle'); ads = ads.filter(ad => ad.ratio !== 0);
const low = ads.filter(ad => ad.priority === 'low');
if (high.length > 0) { if (ads.length === 0) {
ad = high[Math.floor(Math.random() * high.length)]; if (lowPriorityAds.length !== 0) {
} else if (middle.length > 0) { return lowPriorityAds[Math.floor(Math.random() * lowPriorityAds.length)];
ad = middle[Math.floor(Math.random() * middle.length)]; } else {
} else if (low.length > 0) { return null;
ad = low[Math.floor(Math.random() * low.length)];
} }
} }
const totalFactor = ads.reduce((a, b) => a + b.ratio, 0);
const r = Math.random() * totalFactor;
let stackedFactor = 0;
for (const ad of ads) {
if (r >= stackedFactor && r <= stackedFactor + ad.ratio) {
return ad;
} else {
stackedFactor += ad.ratio;
}
}
return null;
};
return { return {
ad, ad: choseAd(),
showMenu, showMenu,
toggleMenu, toggleMenu,
host, host,

View file

@ -3,10 +3,16 @@ import { api } from './os';
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
type Instance = { export type Instance = {
emojis: { emojis: {
category: string; category: string;
}[]; }[];
ads: {
ratio: number;
place: string;
url: string;
imageUrl: string;
}[];
}; };
const data = localStorage.getItem('instance'); const data = localStorage.getItem('instance');

View file

@ -15,12 +15,17 @@
<MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio> <MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio>
<MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio> <MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio>
</div> </div>
<!--
<div style="margin: 32px 0;"> <div style="margin: 32px 0;">
{{ $ts.priority }} {{ $ts.priority }}
<MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio> <MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
<MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio> <MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio> <MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
</div> </div>
-->
<MkInput v-model:value="ad.ratio" type="number">
<span>{{ $ts.ratio }}</span>
</MkInput>
<MkInput v-model:value="ad.expiresAt" type="date"> <MkInput v-model:value="ad.expiresAt" type="date">
<span>{{ $ts.expiration }}</span> <span>{{ $ts.expiration }}</span>
</MkInput> </MkInput>
@ -82,6 +87,7 @@ export default defineComponent({
memo: '', memo: '',
place: 'square', place: 'square',
priority: 'middle', priority: 'middle',
ratio: 1,
url: '', url: '',
imageUrl: null, imageUrl: null,
expiresAt: null, expiresAt: null,

View file

@ -23,11 +23,17 @@ export class Ad {
}) })
public place: string; public place: string;
// 今は使われていないが将来的に活用される可能性はある
@Column('varchar', { @Column('varchar', {
length: 32, nullable: false length: 32, nullable: false
}) })
public priority: string; public priority: string;
@Column('integer', {
default: 1, nullable: false
})
public ratio: number;
@Column('varchar', { @Column('varchar', {
length: 1024, nullable: false length: 1024, nullable: false
}) })

View file

@ -22,6 +22,9 @@ export const meta = {
priority: { priority: {
validator: $.str validator: $.str
}, },
ratio: {
validator: $.num.int().min(0)
},
expiresAt: { expiresAt: {
validator: $.num.int() validator: $.num.int()
}, },
@ -39,6 +42,7 @@ export default define(meta, async (ps) => {
url: ps.url, url: ps.url,
imageUrl: ps.imageUrl, imageUrl: ps.imageUrl,
priority: ps.priority, priority: ps.priority,
ratio: ps.ratio,
place: ps.place, place: ps.place,
memo: ps.memo, memo: ps.memo,
}); });

View file

@ -29,6 +29,9 @@ export const meta = {
priority: { priority: {
validator: $.str validator: $.str
}, },
ratio: {
validator: $.num.int().min(0)
},
expiresAt: { expiresAt: {
validator: $.num.int() validator: $.num.int()
}, },
@ -52,6 +55,7 @@ export default define(meta, async (ps, me) => {
url: ps.url, url: ps.url,
place: ps.place, place: ps.place,
priority: ps.priority, priority: ps.priority,
ratio: ps.ratio,
memo: ps.memo, memo: ps.memo,
imageUrl: ps.imageUrl, imageUrl: ps.imageUrl,
expiresAt: new Date(ps.expiresAt), expiresAt: new Date(ps.expiresAt),

View file

@ -511,7 +511,7 @@ export default define(meta, async (ps, me) => {
ads: ads.map(ad => ({ ads: ads.map(ad => ({
url: ad.url, url: ad.url,
place: ad.place, place: ad.place,
priority: ad.priority, ratio: ad.ratio,
imageUrl: ad.imageUrl, imageUrl: ad.imageUrl,
})), })),
enableEmail: instance.enableEmail, enableEmail: instance.enableEmail,