add event option
This commit is contained in:
+116
-278
@@ -28,6 +28,14 @@
|
||||
:label="verificationFilterLabel"
|
||||
:options="verificationOptions"
|
||||
/>
|
||||
<t-dropdown-item
|
||||
v-if="optionFilterOptions.length"
|
||||
v-model="optionFilter"
|
||||
:label="optionFilterLabel"
|
||||
options-columns="2"
|
||||
:options="optionFilterOptions"
|
||||
multiple
|
||||
/>
|
||||
</t-dropdown-menu>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,86 +60,36 @@
|
||||
@click="openEndTime"
|
||||
/>
|
||||
<t-cell title="事件" :note="eventFilterLabel" />
|
||||
<t-cell v-if="optionFilterLabel !== '全部选项'" title="选项" :note="optionFilterLabel" />
|
||||
<t-cell title="数据量" :note="`共 ${pageResult.total} 条记录`" />
|
||||
<t-cell v-if="summaryNumberValueText" title="数值合计" :note="summaryNumberValueText" />
|
||||
</t-cell-group>
|
||||
<t-cell-group v-if="hasSelectedOption && optionStatList.length" title="选项统计" class="option-stat" theme="card">
|
||||
<t-cell
|
||||
v-for="item in optionStatList"
|
||||
:key="`${item.groupId}-${item.optionId}`"
|
||||
:title="`${item.groupName || '选项组'}:${item.optionLabel || '未命名选项'}`"
|
||||
:note="`${item.recordCount || 0} 条`"
|
||||
/>
|
||||
</t-cell-group>
|
||||
<t-cell-group
|
||||
v-if="pageResult.list.length"
|
||||
class="record-list"
|
||||
theme="card"
|
||||
>
|
||||
<t-swipe-cell
|
||||
v-entrance-transition="index * 30"
|
||||
v-for="(item, index) in pageResult.list"
|
||||
:key="item.id"
|
||||
class="item"
|
||||
>
|
||||
<t-cell
|
||||
class="cell"
|
||||
:title="getRecordEventName(item)"
|
||||
:note="getRecordRegisteredAt(item)"
|
||||
arrow
|
||||
hover
|
||||
@click="toDetail(item.id || '')"
|
||||
>
|
||||
<template #description>
|
||||
<div class="description-line">
|
||||
<t-tag
|
||||
v-if="item.verificationStatus && item.verificationStatus !== 'NOT_REQUIRED'"
|
||||
:theme="getVerificationTag(item).theme"
|
||||
variant="light-outline"
|
||||
:content="getVerificationTag(item).text"
|
||||
/>
|
||||
<span v-text="getRecordCustomerName(item)" />
|
||||
</div>
|
||||
</template>
|
||||
<template #leftIcon>
|
||||
<t-image
|
||||
v-if="getRecordPhotoURL(item)"
|
||||
:src="getRecordPhotoURL(item)"
|
||||
:alt="getRecordEventName(item)"
|
||||
fit="cover"
|
||||
class="avatar"
|
||||
/>
|
||||
<div v-else class="avatar fallback" v-text="getRecordCustomerInitial(item)" />
|
||||
</template>
|
||||
</t-cell>
|
||||
<template v-if="canVerifyRecord || canDeleteRecord" #right>
|
||||
<div class="actions">
|
||||
<t-button
|
||||
v-if="canVerifyRecord && item.verificationStatus === 'PENDING'"
|
||||
class="action verify bg-orange white"
|
||||
variant="text"
|
||||
:loading="(isVerifying && verifyingId === item.id) || (isLoadingVerifyRecord && verifyLoadingId === item.id)"
|
||||
@click.stop="confirmVerifyRecord(item)"
|
||||
>
|
||||
核销
|
||||
</t-button>
|
||||
<t-button
|
||||
v-if="canDeleteRecord"
|
||||
class="action delete"
|
||||
theme="danger"
|
||||
:loading="isDeleting && deletingId === item.id"
|
||||
@click.stop="confirmRemoveRecord(item)"
|
||||
>
|
||||
删除
|
||||
</t-button>
|
||||
</div>
|
||||
</template>
|
||||
</t-swipe-cell>
|
||||
<event-record-cell
|
||||
v-entrance-transition="index * 30"
|
||||
v-for="(item, index) in pageResult.list"
|
||||
:key="item.id"
|
||||
:record="item"
|
||||
@updated="reloadRecords"
|
||||
/>
|
||||
</t-cell-group>
|
||||
<div v-else class="load-state" v-text="isLoading ? '正在加载登记事件记录' : '暂无登记事件记录'" />
|
||||
<div v-if="pageResult.list.length" class="load-state" v-text="loadStateText" />
|
||||
</div>
|
||||
</t-pull-down-refresh>
|
||||
</div>
|
||||
<event-record-verify-dialog
|
||||
v-model:visible="verifyDialogVisible"
|
||||
:record="verifyTarget"
|
||||
:can-update="canUpdateRecord"
|
||||
:submit="submitVerifyRecord"
|
||||
@verified="handleVerifySuccess"
|
||||
/>
|
||||
<nav-bar-action-menu v-if="canShowActionMenu" :actions="actionList" />
|
||||
<t-popup v-model="startVisible" placement="bottom">
|
||||
<t-date-time-picker
|
||||
@@ -160,23 +118,21 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DialogPlugin, type DropdownValue } from "tdesign-mobile-vue";
|
||||
import type { DropdownValue } from "tdesign-mobile-vue";
|
||||
import { Time, WebToolkit } from "timi-web";
|
||||
import { useUserStore, type Attachment } from "timi-web-api";
|
||||
import { useUserStore } from "timi-web-api";
|
||||
import EventAPI from "@/api/EventAPI";
|
||||
import EventRecordAPI from "@/api/EventRecordAPI";
|
||||
import EventRecordVerifyDialog from "@/components/EventRecordVerifyDialog.vue";
|
||||
import EventRecordCell from "@/pages/event/component/EventRecordCell.vue";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { EventItem } from "@/types/EventItem";
|
||||
import type { EventRecord, EventRecordListItemView, EventRecordPage, EventRecordPageResult, VerificationStatus } from "@/types/EventRecord";
|
||||
import type { EventOptionStat, EventRecordPage, EventRecordPageResult, VerificationStatus } from "@/types/EventRecord";
|
||||
import type { NavBarAction } from "@/types/NavBarAction";
|
||||
import { getCustomerPhotoURL } from "@/utils/customer";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { formatEventNumberValue } from "@/utils/eventValue";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
import { Message } from "@/utils/message.ts";
|
||||
|
||||
type DateFilterType = "today" | "yesterday" | "beforeYesterday" | "lastWeek" | "all" | "custom";
|
||||
type DateFilterType = "today" | "yesterday" | "lastWeek" | "thisMonth" | "lastMonth" | "all" | "custom";
|
||||
type VerificationFilter = "ALL" | VerificationStatus;
|
||||
|
||||
defineOptions({
|
||||
@@ -191,8 +147,9 @@ const userStore = useUserStore();
|
||||
const dateOptions: Array<{ label: string; value: DateFilterType }> = [
|
||||
{ label: "今天", value: "today" },
|
||||
{ label: "昨天", value: "yesterday" },
|
||||
{ label: "前天", value: "beforeYesterday" },
|
||||
{ label: "上周", value: "lastWeek" },
|
||||
{ label: "本月", value: "thisMonth" },
|
||||
{ label: "上个月", value: "lastMonth" },
|
||||
{ label: "全部", value: "all" },
|
||||
{ label: "自定义范围", value: "custom" }
|
||||
];
|
||||
@@ -206,6 +163,7 @@ const dateRange = ref(parseDateRange(dateFilterType.value));
|
||||
const startDraft = ref("");
|
||||
const endDraft = ref("");
|
||||
const actionFilter = ref<string[]>([]);
|
||||
const optionFilter = ref<string[]>([]);
|
||||
const verificationOptions: Array<{ label: string; value: VerificationFilter }> = [
|
||||
{ label: "全部核销状态", value: "ALL" },
|
||||
{ label: "待核销", value: "PENDING" },
|
||||
@@ -219,6 +177,7 @@ const endVisible = ref(false);
|
||||
let keywordTimer: number | undefined;
|
||||
let initialized = false;
|
||||
const isExporting = ref(false);
|
||||
let suppressOptionFilterReload = false;
|
||||
|
||||
const canCreateRecord = computed(() => userStore.hasPermissions(permissionCodes.eventRecord.create));
|
||||
const dateFilterLabel = computed(() => dateOptions.find(item => item.value === dateFilterType.value)?.label || "今天");
|
||||
@@ -236,6 +195,34 @@ const eventFilterLabel = computed(() => {
|
||||
.map(item => item.name || "未命名事件")
|
||||
.join("、");
|
||||
});
|
||||
const selectedOptionEvent = computed(() => {
|
||||
if (actionFilter.value.length !== 1) {
|
||||
return undefined;
|
||||
}
|
||||
const event = eventList.value.find(item => item.id === actionFilter.value[0]);
|
||||
return event?.optionGroupList?.some(group => group.optionList?.some(option => option.id)) ? event : undefined;
|
||||
});
|
||||
const optionFilterOptions = computed(() => {
|
||||
const event = selectedOptionEvent.value;
|
||||
if (!event) {
|
||||
return [];
|
||||
}
|
||||
return (event.optionGroupList || []).flatMap(group => (group.optionList || [])
|
||||
.filter(option => option.id)
|
||||
.map(option => ({
|
||||
label: `${group.name}:${option.label}`,
|
||||
value: String(option.id)
|
||||
})));
|
||||
});
|
||||
const optionFilterLabel = computed(() => {
|
||||
if (!optionFilter.value.length) {
|
||||
return "全部选项";
|
||||
}
|
||||
return optionFilterOptions.value
|
||||
.filter(item => optionFilter.value.includes(item.value))
|
||||
.map(item => item.label)
|
||||
.join("、") || "全部选项";
|
||||
});
|
||||
const verificationFilterLabel = computed(() => verificationOptions.find(item => item.value === verificationFilter.value)?.label || "全部核销状态");
|
||||
const selectedNumberEvent = computed(() => {
|
||||
if (actionFilter.value.length !== 1) {
|
||||
@@ -244,10 +231,8 @@ const selectedNumberEvent = computed(() => {
|
||||
const event = eventList.value.find(item => item.id === actionFilter.value[0]);
|
||||
return event?.valueType === "NUMBER" ? event : undefined;
|
||||
});
|
||||
const hasSelectedOption = computed(() => !!selectedOptionEvent.value);
|
||||
const canExportRecord = computed(() => userStore.hasPermissions(permissionCodes.eventRecord.export));
|
||||
const canDeleteRecord = computed(() => userStore.hasPermissions(permissionCodes.eventRecord.delete));
|
||||
const canVerifyRecord = computed(() => userStore.hasPermissions(permissionCodes.eventRecord.verify));
|
||||
const canUpdateRecord = computed(() => userStore.hasPermissions(permissionCodes.eventRecord.update));
|
||||
const canShowActionMenu = computed(() => canCreateRecord.value || canExportRecord.value);
|
||||
|
||||
const actionList = computed<NavBarAction[]>(() => {
|
||||
@@ -288,6 +273,24 @@ watch(actionFilter, async () => {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
const optionIdSet = new Set(optionFilterOptions.value.map(item => item.value));
|
||||
const nextOptionFilter = optionFilter.value.filter(optionId => optionIdSet.has(optionId));
|
||||
if (nextOptionFilter.length !== optionFilter.value.length) {
|
||||
suppressOptionFilterReload = true;
|
||||
optionFilter.value = nextOptionFilter;
|
||||
}
|
||||
await replaceFilterQuery();
|
||||
await reloadRecords();
|
||||
});
|
||||
|
||||
watch(optionFilter, async () => {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
if (suppressOptionFilterReload) {
|
||||
suppressOptionFilterReload = false;
|
||||
return;
|
||||
}
|
||||
await replaceFilterQuery();
|
||||
await reloadRecords();
|
||||
});
|
||||
@@ -328,6 +331,7 @@ const pageResult = reactive<EventRecordPageResult>({
|
||||
list: [],
|
||||
numberValueTotal: null
|
||||
});
|
||||
const optionStatList = ref<EventOptionStat[]>([]);
|
||||
let loadToken = 0;
|
||||
|
||||
const summaryNumberValueText = computed(() => {
|
||||
@@ -350,8 +354,9 @@ async function reloadRecords(): Promise<void> {
|
||||
pageResult.total = 0;
|
||||
pageResult.list = [];
|
||||
pageResult.numberValueTotal = null;
|
||||
optionStatList.value = [];
|
||||
isNoMore.value = false;
|
||||
await loadRecords();
|
||||
await Promise.all([loadRecords(), loadOptionStats()]);
|
||||
} finally {
|
||||
isRefreshing.value = false;
|
||||
}
|
||||
@@ -387,21 +392,14 @@ async function loadRecords(): Promise<void> {
|
||||
|
||||
// ---------- 操作 ----------
|
||||
|
||||
const isDeleting = ref(false);
|
||||
const deletingId = ref("");
|
||||
const isVerifying = ref(false);
|
||||
const verifyingId = ref("");
|
||||
const isLoadingVerifyRecord = ref(false);
|
||||
const verifyLoadingId = ref("");
|
||||
const verifyDialogVisible = ref(false);
|
||||
const verifyTarget = ref<EventRecord>();
|
||||
|
||||
async function loadActions(): Promise<void> {
|
||||
eventList.value = await EventAPI.listValid();
|
||||
const eventIdList = parseEventIdList(route.query.eventIds);
|
||||
actionFilter.value = eventIdList.length
|
||||
? eventIdList
|
||||
: eventList.value.map(item => item.id).filter((item): item is string => Boolean(item));
|
||||
const validEventIdList = eventList.value.map(item => item.id).filter((item): item is string => Boolean(item));
|
||||
const validEventIdSet = new Set(validEventIdList);
|
||||
const eventIdList = parseEventIdList(route.query.eventIds).filter(eventId => validEventIdSet.has(eventId));
|
||||
actionFilter.value = eventIdList.length ? eventIdList : validEventIdList;
|
||||
const optionIdSet = new Set(optionFilterOptions.value.map(item => item.value));
|
||||
optionFilter.value = parseEventIdList(route.query.optionIds).filter(optionId => optionIdSet.has(optionId));
|
||||
}
|
||||
|
||||
async function selectDateFilter(type: DropdownValue): Promise<void> {
|
||||
@@ -479,68 +477,23 @@ async function exportExcel(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmVerifyRecord(record: EventRecordListItemView): Promise<void> {
|
||||
if (!record.id || record.verificationStatus !== "PENDING" || isVerifying.value || isLoadingVerifyRecord.value) {
|
||||
async function loadOptionStats(): Promise<void> {
|
||||
if (!hasSelectedOption.value) {
|
||||
optionStatList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const recordId = record.id;
|
||||
isLoadingVerifyRecord.value = true;
|
||||
verifyLoadingId.value = recordId;
|
||||
try {
|
||||
verifyTarget.value = await EventRecordAPI.detail(recordId);
|
||||
verifyDialogVisible.value = true;
|
||||
optionStatList.value = await EventRecordAPI.optionStat({
|
||||
index: 0,
|
||||
size: 1,
|
||||
...buildRangeReq()
|
||||
});
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "登记记录加载失败"));
|
||||
} finally {
|
||||
isLoadingVerifyRecord.value = false;
|
||||
verifyLoadingId.value = "";
|
||||
optionStatList.value = [];
|
||||
console.warn("登记选项统计加载失败", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitVerifyRecord(record: EventRecord, attachmentList: Attachment[]): Promise<void> {
|
||||
const id = record.id;
|
||||
if (!id) {
|
||||
throw new Error("登记事件记录不存在");
|
||||
}
|
||||
|
||||
isVerifying.value = true;
|
||||
verifyingId.value = id;
|
||||
try {
|
||||
if (canUpdateRecord.value) {
|
||||
await EventRecordAPI.update({
|
||||
id,
|
||||
remark: record.remark || "",
|
||||
attachmentList
|
||||
});
|
||||
}
|
||||
await EventRecordAPI.verify(id);
|
||||
} finally {
|
||||
isVerifying.value = false;
|
||||
verifyingId.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
async function handleVerifySuccess(): Promise<void> {
|
||||
verifyDialogVisible.value = false;
|
||||
verifyTarget.value = undefined;
|
||||
try {
|
||||
await reloadRecords();
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "登记记录刷新失败"));
|
||||
}
|
||||
}
|
||||
|
||||
async function toDetail(id: string): Promise<void> {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
await router.push({
|
||||
path: `/management/registration-event-records/${id}`,
|
||||
query: buildFilterQuery(String(getCurrentRouteDepth() + 1))
|
||||
});
|
||||
}
|
||||
|
||||
async function toCreate(): Promise<void> {
|
||||
await router.push({
|
||||
path: "/management/registration-event-records/create",
|
||||
@@ -550,85 +503,6 @@ async function toCreate(): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
async function confirmRemoveRecord(record: EventRecordListItemView): Promise<void> {
|
||||
if (!record.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordId = record.id;
|
||||
const dialog = DialogPlugin.confirm({
|
||||
title: "删除登记记录",
|
||||
content: `确定删除 ${getRecordCustomerName(record)} 的 ${getRecordEventName(record)} 记录吗?删除后无法恢复。`,
|
||||
cancelBtn: "取消",
|
||||
confirmBtn: "删除",
|
||||
onCancel() {
|
||||
dialog.destroy();
|
||||
},
|
||||
async onConfirm() {
|
||||
dialog.destroy();
|
||||
await removeRecord(recordId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function removeRecord(id: string): Promise<void> {
|
||||
if (isDeleting.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
isDeleting.value = true;
|
||||
deletingId.value = id;
|
||||
try {
|
||||
await EventRecordAPI.remove(id);
|
||||
await reloadRecords();
|
||||
Message.success("登记记录已删除");
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error, "登记记录删除失败");
|
||||
if (message.includes("积分余额不足") || message.includes("余额不足")) {
|
||||
Message.warning("积分余额不足,请先人工调整积分后再删除登记记录");
|
||||
return;
|
||||
}
|
||||
Message.error(message);
|
||||
} finally {
|
||||
isDeleting.value = false;
|
||||
deletingId.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 格式化 ----------
|
||||
|
||||
function getRecordEventName(record: EventRecordListItemView): string {
|
||||
return record.event?.name || "未知事件";
|
||||
}
|
||||
|
||||
function getRecordCustomerName(record: EventRecordListItemView): string {
|
||||
return record.customer?.name || "未知客户";
|
||||
}
|
||||
|
||||
function getRecordPhotoURL(record: EventRecordListItemView): string {
|
||||
return getCustomerPhotoURL(record.customer, 64);
|
||||
}
|
||||
|
||||
function getRecordCustomerInitial(record: EventRecordListItemView): string {
|
||||
return getRecordCustomerName(record).slice(0, 1);
|
||||
}
|
||||
|
||||
function getVerificationTag(record: EventRecordListItemView): { text: string; theme: "warning" | "success" } {
|
||||
return record.verificationStatus === "VERIFIED"
|
||||
? { text: "已核销", theme: "success" }
|
||||
: { text: "待核销", theme: "warning" };
|
||||
}
|
||||
|
||||
function getRecordRegisteredAt(record: EventRecordListItemView): string {
|
||||
if (!record.registeredAt) {
|
||||
return "-";
|
||||
}
|
||||
if (["today", "yesterday", "beforeYesterday"].includes(dateFilterType.value)) {
|
||||
return Time.toTime(record.registeredAt);
|
||||
}
|
||||
return Time.toDateTime(record.registeredAt);
|
||||
}
|
||||
|
||||
function buildRangeReq(): Omit<EventRecordPage, "index" | "size"> {
|
||||
const [beginAt, endAt] = buildUnixRange();
|
||||
const selectedAllEvent = !actionFilter.value.length || actionFilter.value.length === eventList.value.length;
|
||||
@@ -638,6 +512,7 @@ function buildRangeReq(): Omit<EventRecordPage, "index" | "size"> {
|
||||
customerId: customerId.value || undefined,
|
||||
keyword: keyword.value.trim() || undefined,
|
||||
eventIdList: actionFilter.value.length === 1 ? actionFilter.value : selectedAllEvent ? undefined : actionFilter.value,
|
||||
optionIdList: optionFilter.value.length ? optionFilter.value : undefined,
|
||||
verificationStatus: verificationFilter.value === "ALL" ? undefined : verificationFilter.value
|
||||
};
|
||||
}
|
||||
@@ -681,6 +556,7 @@ function buildFilterQuery(transitionDepth = getQueryText("transitionDepth")): Re
|
||||
customerId: customerId.value,
|
||||
customerName: getQueryText("customerName"),
|
||||
eventIds: actionFilter.value.join(","),
|
||||
optionIds: optionFilter.value.join(","),
|
||||
verificationStatus: verificationFilter.value === "ALL" ? "" : verificationFilter.value
|
||||
};
|
||||
if (isValidTransitionDepth(transitionDepth)) {
|
||||
@@ -733,11 +609,21 @@ function buildPresetRange(type: Exclude<DateFilterType, "custom">): [string, str
|
||||
lastWeekSunday.setDate(thisWeekMonday.getDate() - 1);
|
||||
return [`${Time.formatDate(lastWeekMonday)} 00:00`, `${Time.formatDate(lastWeekSunday)} 23:59`];
|
||||
}
|
||||
if (type === "thisMonth") {
|
||||
const current = new Date();
|
||||
const begin = new Date(current.getFullYear(), current.getMonth(), 1);
|
||||
return [`${Time.formatDate(begin)} 00:00`, `${Time.formatDate(current)} 23:59`];
|
||||
}
|
||||
if (type === "lastMonth") {
|
||||
const current = new Date();
|
||||
const begin = new Date(current.getFullYear(), current.getMonth() - 1, 1);
|
||||
const end = new Date(current.getFullYear(), current.getMonth(), 0);
|
||||
return [`${Time.formatDate(begin)} 00:00`, `${Time.formatDate(end)} 23:59`];
|
||||
}
|
||||
|
||||
const offsetMap: Record<Exclude<DateFilterType, "all" | "custom" | "lastWeek">, number> = {
|
||||
const offsetMap: Record<Exclude<DateFilterType, "all" | "custom" | "lastWeek" | "thisMonth" | "lastMonth">, number> = {
|
||||
today: 0,
|
||||
yesterday: 1,
|
||||
beforeYesterday: 2
|
||||
yesterday: 1
|
||||
};
|
||||
const date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
@@ -860,56 +746,8 @@ onUnmounted(() => {
|
||||
|
||||
.record-list {
|
||||
|
||||
.item {
|
||||
|
||||
&:last-child {
|
||||
|
||||
:deep(.t-cell:after) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cell {
|
||||
padding: .5rem;
|
||||
|
||||
:deep(.t-cell__title) {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.t-cell__title-text) {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.t-cell__note) {
|
||||
flex: 0 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.description-line {
|
||||
gap: .5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.action {
|
||||
height: 100%;
|
||||
padding: 0 1rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
:deep(.item:last-child .cell:after) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user