Compare commits
2 Commits
283252c841
...
168aecfd5c
| Author | SHA1 | Date | |
|---|---|---|---|
| 168aecfd5c | |||
| 5a15159ff3 |
@@ -5,6 +5,10 @@ import type { TableInstance } from 'element-plus';
|
|||||||
import { useAdminLocale } from '../composables/useAdminLocale';
|
import { useAdminLocale } from '../composables/useAdminLocale';
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
import AdminTableEmpty from '../components/AdminTableEmpty.vue';
|
import AdminTableEmpty from '../components/AdminTableEmpty.vue';
|
||||||
|
import {
|
||||||
|
normalizeStartTimeForApi,
|
||||||
|
normalizeStartTimeForPicker,
|
||||||
|
} from './match-form';
|
||||||
|
|
||||||
const { t, localeTag } = useAdminLocale();
|
const { t, localeTag } = useAdminLocale();
|
||||||
|
|
||||||
@@ -126,6 +130,9 @@ const filterStatus = ref<ContentStatus | ''>('');
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const saving = ref(false);
|
const saving = ref(false);
|
||||||
const items = ref<ContentItem[]>([]);
|
const items = ref<ContentItem[]>([]);
|
||||||
|
const total = ref(0);
|
||||||
|
const page = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
const tableRef = ref<TableInstance>();
|
const tableRef = ref<TableInstance>();
|
||||||
const selectedRows = ref<ContentItem[]>([]);
|
const selectedRows = ref<ContentItem[]>([]);
|
||||||
|
|
||||||
@@ -202,9 +209,12 @@ async function load() {
|
|||||||
params: {
|
params: {
|
||||||
type: activeType.value,
|
type: activeType.value,
|
||||||
status: filterStatus.value || undefined,
|
status: filterStatus.value || undefined,
|
||||||
|
page: page.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
items.value = data.data ?? [];
|
items.value = data.data.items ?? [];
|
||||||
|
total.value = data.data.total ?? 0;
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
tableRef.value?.clearSelection();
|
tableRef.value?.clearSelection();
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
@@ -215,7 +225,19 @@ async function load() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onPageChange(p: number) {
|
||||||
|
page.value = p;
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSizeChange(size: number) {
|
||||||
|
pageSize.value = size;
|
||||||
|
page.value = 1;
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
watch([activeType, filterStatus], () => {
|
watch([activeType, filterStatus], () => {
|
||||||
|
page.value = 1;
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
tableRef.value?.clearSelection();
|
tableRef.value?.clearSelection();
|
||||||
void load();
|
void load();
|
||||||
@@ -286,7 +308,7 @@ function batchDelete() {
|
|||||||
|
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
form.value = {
|
form.value = {
|
||||||
sortOrder: items.value.length + 1,
|
sortOrder: total.value + 1,
|
||||||
status: 'DRAFT',
|
status: 'DRAFT',
|
||||||
linkType: '',
|
linkType: '',
|
||||||
linkTarget: '',
|
linkTarget: '',
|
||||||
@@ -311,8 +333,8 @@ function openEdit(row: ContentItem) {
|
|||||||
status: row.status,
|
status: row.status,
|
||||||
linkType: (row.linkType as '' | 'ROUTE' | 'URL') || '',
|
linkType: (row.linkType as '' | 'ROUTE' | 'URL') || '',
|
||||||
linkTarget: row.linkTarget ?? '',
|
linkTarget: row.linkTarget ?? '',
|
||||||
startTime: row.startTime ? row.startTime.slice(0, 19) : '',
|
startTime: normalizeStartTimeForPicker(row.startTime ?? undefined),
|
||||||
endTime: row.endTime ? row.endTime.slice(0, 19) : '',
|
endTime: normalizeStartTimeForPicker(row.endTime ?? undefined),
|
||||||
translations: LOCALES.map((locale) => {
|
translations: LOCALES.map((locale) => {
|
||||||
const tr = byLocale.get(locale);
|
const tr = byLocale.get(locale);
|
||||||
return {
|
return {
|
||||||
@@ -340,8 +362,8 @@ function buildPayload() {
|
|||||||
linkType: isBanner.value && form.value.linkType ? form.value.linkType : null,
|
linkType: isBanner.value && form.value.linkType ? form.value.linkType : null,
|
||||||
linkTarget:
|
linkTarget:
|
||||||
isBanner.value && form.value.linkType ? form.value.linkTarget.trim() : null,
|
isBanner.value && form.value.linkType ? form.value.linkTarget.trim() : null,
|
||||||
startTime: form.value.startTime || null,
|
startTime: form.value.startTime ? normalizeStartTimeForApi(form.value.startTime) : null,
|
||||||
endTime: form.value.endTime || null,
|
endTime: form.value.endTime ? normalizeStartTimeForApi(form.value.endTime) : null,
|
||||||
translations: form.value.translations.map((tr) => ({
|
translations: form.value.translations.map((tr) => ({
|
||||||
locale: tr.locale,
|
locale: tr.locale,
|
||||||
title: tr.title.trim() || undefined,
|
title: tr.title.trim() || undefined,
|
||||||
@@ -558,6 +580,18 @@ void load();
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pager">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="page"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:total="total"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next"
|
||||||
|
background
|
||||||
|
@current-change="onPageChange"
|
||||||
|
@size-change="onSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="640px" destroy-on-close>
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="640px" destroy-on-close>
|
||||||
|
|||||||
@@ -2249,9 +2249,13 @@ export class AdminController {
|
|||||||
async listContents(
|
async listContents(
|
||||||
@Query('type') type?: string,
|
@Query('type') type?: string,
|
||||||
@Query('status') status?: string,
|
@Query('status') status?: string,
|
||||||
|
@Query('page') page?: string,
|
||||||
|
@Query('pageSize') pageSize?: string,
|
||||||
) {
|
) {
|
||||||
const items = await this.content.listForAdmin(type, status);
|
const p = Math.max(1, page ? parseInt(page, 10) || 1 : 1);
|
||||||
return jsonResponse(items);
|
const size = Math.min(Math.max(1, pageSize ? parseInt(pageSize, 10) : 20), 100);
|
||||||
|
const result = await this.content.listForAdmin(type, status, p, size);
|
||||||
|
return jsonResponse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('contents/:id')
|
@Get('contents/:id')
|
||||||
|
|||||||
@@ -255,7 +255,12 @@ export class ContentService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async listForAdmin(contentType?: string, status?: string) {
|
async listForAdmin(
|
||||||
|
contentType?: string,
|
||||||
|
status?: string,
|
||||||
|
page = 1,
|
||||||
|
pageSize = 20,
|
||||||
|
) {
|
||||||
const typeWhere =
|
const typeWhere =
|
||||||
contentType === ANNOUNCEMENT_ADMIN_TYPE
|
contentType === ANNOUNCEMENT_ADMIN_TYPE
|
||||||
? { contentType: { in: [...ANNOUNCEMENT_TYPES] } }
|
? { contentType: { in: [...ANNOUNCEMENT_TYPES] } }
|
||||||
@@ -263,15 +268,28 @@ export class ContentService {
|
|||||||
? { contentType }
|
? { contentType }
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const items = await this.prisma.content.findMany({
|
const where = {
|
||||||
where: {
|
|
||||||
...typeWhere,
|
...typeWhere,
|
||||||
...(status ? { status } : {}),
|
...(status ? { status } : {}),
|
||||||
},
|
};
|
||||||
|
|
||||||
|
const [items, total] = await Promise.all([
|
||||||
|
this.prisma.content.findMany({
|
||||||
|
where,
|
||||||
include: { translations: true },
|
include: { translations: true },
|
||||||
orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }],
|
orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }],
|
||||||
});
|
skip: (page - 1) * pageSize,
|
||||||
return items.map((item) => this.mapAdminItem(item));
|
take: pageSize,
|
||||||
|
}),
|
||||||
|
this.prisma.content.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: items.map((item) => this.mapAdminItem(item)),
|
||||||
|
total,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getForAdmin(id: bigint) {
|
async getForAdmin(id: bigint) {
|
||||||
@@ -442,6 +460,7 @@ export class ContentService {
|
|||||||
|
|
||||||
/** @deprecated use listForAdmin */
|
/** @deprecated use listForAdmin */
|
||||||
async listAll(contentType?: string) {
|
async listAll(contentType?: string) {
|
||||||
return this.listForAdmin(contentType);
|
const result = await this.listForAdmin(contentType);
|
||||||
|
return result.items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user