mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-23 05:13:07 +02:00
広告の曜日を設定できるように (#10095)
* 曜日選択できるように * ラベル選択でもチェックが変更されるように * adを参照しないといけないかも * smallint -> integer * 異物混入だったので取りだし * タイムゾーン指定(Date2つ使うのなんか違和感 * 未テスト * これにすると出てこないかも * UIチョット変更 * UI変更 fix bug * 畳むように修正 * dayofweek->dayOfWeek * マイグレ時にnot null,default設定してるのでnullable:falseでよさそう * コメントの記載 * Update packages/backend/src/server/api/endpoints/meta.ts Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> --------- Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
This commit is contained in:
parent
1f181536ae
commit
3c6175d959
7 changed files with 51 additions and 11 deletions
|
@ -1451,6 +1451,7 @@ _ad:
|
||||||
back: "戻る"
|
back: "戻る"
|
||||||
reduceFrequencyOfThisAd: "この広告の表示頻度を下げる"
|
reduceFrequencyOfThisAd: "この広告の表示頻度を下げる"
|
||||||
hide: "表示しない"
|
hide: "表示しない"
|
||||||
|
timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されます。"
|
||||||
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
|
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
|
||||||
|
|
9
packages/backend/migration/1677054292210-ad4.js
Normal file
9
packages/backend/migration/1677054292210-ad4.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export class ad1677054292210 {
|
||||||
|
name = 'ad1677054292210';
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "ad" ADD "dayOfWeek" integer NOT NULL Default 0`);
|
||||||
|
}
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "dayOfWeek"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,7 +55,10 @@ export class Ad {
|
||||||
length: 8192, nullable: false,
|
length: 8192, nullable: false,
|
||||||
})
|
})
|
||||||
public memo: string;
|
public memo: string;
|
||||||
|
@Column('integer', {
|
||||||
|
default: 0, nullable: false,
|
||||||
|
})
|
||||||
|
public dayOfWeek: number;
|
||||||
constructor(data: Partial<Ad>) {
|
constructor(data: Partial<Ad>) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,9 @@ export const paramDef = {
|
||||||
expiresAt: { type: 'integer' },
|
expiresAt: { type: 'integer' },
|
||||||
startsAt: { type: 'integer' },
|
startsAt: { type: 'integer' },
|
||||||
imageUrl: { type: 'string', minLength: 1 },
|
imageUrl: { type: 'string', minLength: 1 },
|
||||||
|
dayOfWeek: { type: 'integer' },
|
||||||
},
|
},
|
||||||
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl'],
|
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl', 'dayOfWeek'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
@ -41,6 +42,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
expiresAt: new Date(ps.expiresAt),
|
expiresAt: new Date(ps.expiresAt),
|
||||||
startsAt: new Date(ps.startsAt),
|
startsAt: new Date(ps.startsAt),
|
||||||
|
dayOfWeek: ps.dayOfWeek,
|
||||||
url: ps.url,
|
url: ps.url,
|
||||||
imageUrl: ps.imageUrl,
|
imageUrl: ps.imageUrl,
|
||||||
priority: ps.priority,
|
priority: ps.priority,
|
||||||
|
|
|
@ -31,8 +31,9 @@ export const paramDef = {
|
||||||
ratio: { type: 'integer' },
|
ratio: { type: 'integer' },
|
||||||
expiresAt: { type: 'integer' },
|
expiresAt: { type: 'integer' },
|
||||||
startsAt: { type: 'integer' },
|
startsAt: { type: 'integer' },
|
||||||
|
dayOfWeek: { type: 'integer' },
|
||||||
},
|
},
|
||||||
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt'],
|
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
@ -56,6 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
imageUrl: ps.imageUrl,
|
imageUrl: ps.imageUrl,
|
||||||
expiresAt: new Date(ps.expiresAt),
|
expiresAt: new Date(ps.expiresAt),
|
||||||
startsAt: new Date(ps.startsAt),
|
startsAt: new Date(ps.startsAt),
|
||||||
|
dayOfWeek: ps.dayOfWeek,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm';
|
import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import type { AdsRepository, UsersRepository } from '@/models/index.js';
|
import type { AdsRepository, UsersRepository } from '@/models/index.js';
|
||||||
|
@ -263,13 +263,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const instance = await this.metaService.fetch(true);
|
const instance = await this.metaService.fetch(true);
|
||||||
|
|
||||||
const ads = await this.adsRepository.find({
|
const ads = await this.adsRepository.createQueryBuilder("ads")
|
||||||
where: {
|
.where('ads.expiresAt > :now', { now: new Date() })
|
||||||
expiresAt: MoreThan(new Date()),
|
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
||||||
startsAt: LessThanOrEqual(new Date()),
|
.andWhere(new Brackets(qb => {
|
||||||
},
|
// 曜日のビットフラグを確認する
|
||||||
});
|
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
||||||
|
.orWhere('ads.dayOfWeek = 0');
|
||||||
|
}))
|
||||||
|
.getMany();
|
||||||
|
|
||||||
const response: any = {
|
const response: any = {
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instance.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
@ -311,6 +314,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
place: ad.place,
|
place: ad.place,
|
||||||
ratio: ad.ratio,
|
ratio: ad.ratio,
|
||||||
imageUrl: ad.imageUrl,
|
imageUrl: ad.imageUrl,
|
||||||
|
dayOfWeek: ad.dayOfWeek,
|
||||||
})),
|
})),
|
||||||
enableEmail: instance.enableEmail,
|
enableEmail: instance.enableEmail,
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
|
|
|
@ -36,6 +36,16 @@
|
||||||
<template #label>{{ i18n.ts.expiration }}</template>
|
<template #label>{{ i18n.ts.expiration }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</FormSplit>
|
</FormSplit>
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts.advancedSettings }}</template>
|
||||||
|
<span>
|
||||||
|
{{ i18n.ts._ad.timezoneinfo }}
|
||||||
|
<div v-for="(day, index) in daysOfWeek" :key="index">
|
||||||
|
<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>
|
||||||
<MkTextarea v-model="ad.memo">
|
<MkTextarea v-model="ad.memo">
|
||||||
<template #label>{{ i18n.ts.memo }}</template>
|
<template #label>{{ i18n.ts.memo }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
|
@ -59,6 +69,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import FormSplit from '@/components/form/split.vue';
|
import FormSplit from '@/components/form/split.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
@ -69,6 +80,7 @@ let ads: any[] = $ref([]);
|
||||||
// ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化
|
// ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化
|
||||||
const localTime = new Date();
|
const localTime = new Date();
|
||||||
const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000;
|
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];
|
||||||
|
|
||||||
os.api('admin/ad/list').then(adsResponse => {
|
os.api('admin/ad/list').then(adsResponse => {
|
||||||
ads = adsResponse.map(r => {
|
ads = adsResponse.map(r => {
|
||||||
|
@ -84,6 +96,11 @@ os.api('admin/ad/list').then(adsResponse => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 選択された曜日(index)のビットフラグを操作する
|
||||||
|
function toggleDayOfWeek(ad, index) {
|
||||||
|
ad.dayOfWeek ^= 1 << index;
|
||||||
|
}
|
||||||
|
|
||||||
function add() {
|
function add() {
|
||||||
ads.unshift({
|
ads.unshift({
|
||||||
id: null,
|
id: null,
|
||||||
|
@ -95,6 +112,7 @@ function add() {
|
||||||
imageUrl: null,
|
imageUrl: null,
|
||||||
expiresAt: null,
|
expiresAt: null,
|
||||||
startsAt: null,
|
startsAt: null,
|
||||||
|
dayOfWeek: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +123,7 @@ function remove(ad) {
|
||||||
}).then(({ canceled }) => {
|
}).then(({ canceled }) => {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
ads = ads.filter(x => x !== ad);
|
ads = ads.filter(x => x !== ad);
|
||||||
|
if (ad.id == null) return;
|
||||||
os.apiWithDialog('admin/ad/delete', {
|
os.apiWithDialog('admin/ad/delete', {
|
||||||
id: ad.id,
|
id: ad.id,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue