feat(admin-panel): responsive branches, workshops, products and orders
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -124,9 +124,31 @@
|
||||
<div v-if="cardMode" class="x-table__cards">
|
||||
<a-spin :spinning="loading">
|
||||
<a-empty v-if="!data.length && !loading" :description="locale.emptyText" />
|
||||
<div v-for="record in data" :key="String(record.id)" class="x-card">
|
||||
<a-checkbox
|
||||
v-if="hasSelection && data.length"
|
||||
class="x-table__select-all"
|
||||
:checked="allOnPageSelected"
|
||||
:indeterminate="someOnPageSelected && !allOnPageSelected"
|
||||
@change="(e: any) => selectPage(e.target.checked)"
|
||||
>
|
||||
انتخاب همه در این صفحه
|
||||
</a-checkbox>
|
||||
<div
|
||||
v-for="record in data"
|
||||
:key="String(record.id)"
|
||||
class="x-card"
|
||||
:class="{ 'x-card--selected': hasSelection && isSelected(record) }"
|
||||
>
|
||||
<div class="x-card__head">
|
||||
<div class="x-card__title">
|
||||
<a-checkbox
|
||||
v-if="hasSelection"
|
||||
:checked="isSelected(record)"
|
||||
@change="(e: any) => toggleRow(record, e.target.checked)"
|
||||
/>
|
||||
<span v-if="cardMediaCol" class="x-card__media">
|
||||
<slot :name="cardMediaCol.slot" :text="cellValue(record, cardMediaCol)" :record="record" />
|
||||
</span>
|
||||
<span v-if="cardIdCol" class="x-card__id">#{{ cellValue(record, cardIdCol) }}</span>
|
||||
<span class="x-card__name">
|
||||
<template v-for="col in cardTitleCols" :key="col.key">
|
||||
@@ -216,8 +238,7 @@ const props = withDefaults(
|
||||
);
|
||||
|
||||
const layout = useLayoutStore();
|
||||
// row selection needs the table's checkbox column, so it always keeps the table
|
||||
const cardMode = computed(() => props.mobileCards && !props.hasSelection && layout.isMobile);
|
||||
const cardMode = computed(() => props.mobileCards && layout.isMobile);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'query', q: unknown): void;
|
||||
@@ -321,8 +342,11 @@ const cardCols = computed<CardCol[]>(() =>
|
||||
);
|
||||
const cardActionCol = computed(() => cardCols.value.find((c) => ACTION_KEYS.includes(c.key) && c.slot));
|
||||
const cardIdCol = computed(() => cardCols.value.find((c) => c.key === 'id'));
|
||||
const cardMediaCol = computed(() => cardCols.value.find((c) => c.slot === 'image'));
|
||||
const cardTitleCols = computed<CardCol[]>(() => {
|
||||
const rest = cardCols.value.filter((c) => c !== cardActionCol.value && c !== cardIdCol.value);
|
||||
const rest = cardCols.value.filter(
|
||||
(c) => c !== cardActionCol.value && c !== cardIdCol.value && c !== cardMediaCol.value,
|
||||
);
|
||||
const named = rest.find((c) => c.key === 'name' || c.key === 'title');
|
||||
if (named) return [named];
|
||||
const fname = rest.find((c) => c.key === 'fname');
|
||||
@@ -331,10 +355,30 @@ const cardTitleCols = computed<CardCol[]>(() => {
|
||||
});
|
||||
const cardBodyCols = computed(() =>
|
||||
cardCols.value.filter(
|
||||
(c) => c !== cardActionCol.value && c !== cardIdCol.value && !cardTitleCols.value.includes(c),
|
||||
(c) =>
|
||||
c !== cardActionCol.value &&
|
||||
c !== cardIdCol.value &&
|
||||
c !== cardMediaCol.value &&
|
||||
!cardTitleCols.value.includes(c),
|
||||
),
|
||||
);
|
||||
|
||||
// card-mode selection, same v-model contract as the table's rowSelection
|
||||
function isSelected(record: Record<string, unknown>) {
|
||||
return props.modelValue.some((r) => r.id === record.id);
|
||||
}
|
||||
function toggleRow(record: Record<string, unknown>, checked: boolean) {
|
||||
const rest = props.modelValue.filter((r) => r.id !== record.id);
|
||||
emit('update:modelValue', checked ? [...rest, record] : rest);
|
||||
}
|
||||
const allOnPageSelected = computed(() => data.value.length > 0 && data.value.every(isSelected));
|
||||
const someOnPageSelected = computed(() => data.value.some(isSelected));
|
||||
function selectPage(checked: boolean) {
|
||||
const pageIds = new Set(data.value.map((r) => r.id));
|
||||
const rest = props.modelValue.filter((r) => !pageIds.has(r.id));
|
||||
emit('update:modelValue', checked ? [...rest, ...data.value] : rest);
|
||||
}
|
||||
|
||||
function cellValue(record: Record<string, unknown>, col: CardCol): unknown {
|
||||
return col.path.reduce<unknown>(
|
||||
(v, k) => (v && typeof v === 'object' ? (v as Record<string, unknown>)[k] : undefined),
|
||||
@@ -604,6 +648,26 @@ defineExpose({ fetch });
|
||||
flex-shrink: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.x-card--selected {
|
||||
border-color: #91caff;
|
||||
}
|
||||
.x-card--selected .x-card__head {
|
||||
background: #f0f7ff;
|
||||
}
|
||||
.x-card__media {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
}
|
||||
.x-card__media :deep(img) {
|
||||
width: 44px !important;
|
||||
height: 44px !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.x-table__select-all {
|
||||
font-size: 12px;
|
||||
color: #8a909c;
|
||||
}
|
||||
.x-card__body {
|
||||
margin: 0;
|
||||
padding: 4px 12px;
|
||||
|
||||
Reference in New Issue
Block a user