优化
This commit is contained in:
@@ -90,7 +90,7 @@ describe('InboundFeeDetailManager', () => {
|
||||
})
|
||||
|
||||
it('keeps currency fixed to CNY in the form and write payload', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit'])
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit', 'firstleg:fee-item:view'])
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().includes('新增费用'))?.trigger('click')
|
||||
await flushPromises()
|
||||
@@ -105,4 +105,40 @@ describe('InboundFeeDetailManager', () => {
|
||||
expect(wrapper.find('.fee-table-shell').exists()).toBe(true)
|
||||
expect(wrapper.find('.detail-table-wrap').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('loads RECEIVABLE fee items without requesting counterparties', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit', 'firstleg:fee-item:view'])
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().includes('新增费用'))?.trigger('click')
|
||||
await flushPromises()
|
||||
expect(listInboundFeeItemOptions).toHaveBeenCalledTimes(1)
|
||||
expect(listInboundFeePartnerOptions).not.toHaveBeenCalled()
|
||||
expect(document.body.textContent).toContain('缺少往来单位查看权限')
|
||||
expect(document.body.textContent).toContain('应收费用不受影响')
|
||||
})
|
||||
|
||||
it('does not expose the editor without fee-item view permission', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit'])
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('button').some((button) => button.text().includes('新增费用'))).toBe(false)
|
||||
expect(listInboundFeeItemOptions).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps fee items usable when the independent counterparty request fails', async () => {
|
||||
vi.mocked(listInboundFeeDetails).mockResolvedValue([{ ...pending, direction: 'PAYABLE', partnerId: '41', partnerName: '测试往来单位' }])
|
||||
vi.mocked(listInboundFeePartnerOptions).mockRejectedValue(new ApiResponseError('往来单位不可用', 'A0403', 403, null, 'request-partner', 'trace-partner'))
|
||||
const wrapper = mountManager([
|
||||
'firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit',
|
||||
'firstleg:fee-item:view', 'platform:counterparty:list',
|
||||
])
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().includes('编辑'))?.trigger('click')
|
||||
await flushPromises()
|
||||
expect(listInboundFeeItemOptions).toHaveBeenCalledTimes(1)
|
||||
expect(listInboundFeePartnerOptions).toHaveBeenCalledTimes(1)
|
||||
expect(document.body.textContent).toContain('往来单位不可用')
|
||||
expect(document.body.textContent).toContain('request-partner')
|
||||
expect(document.body.textContent).toContain('trace-partner')
|
||||
expect(document.querySelector('.fee-form .el-select')?.classList.contains('is-disabled')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,6 +24,11 @@ const access = useAccessPreviewStore()
|
||||
const rows = ref<InboundFeeDetail[]>([])
|
||||
const feeItems = ref<InboundFeeItemOption[]>([])
|
||||
const partners = ref<InboundFeePartnerOption[]>([])
|
||||
const feeItemsLoading = ref(false)
|
||||
const partnersLoading = ref(false)
|
||||
const feeItemsError = ref<ApiErrorDetails | null>(null)
|
||||
const partnersError = ref<ApiErrorDetails | null>(null)
|
||||
const partnersLoadAttempted = ref(false)
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const loadError = ref<ApiErrorDetails | null>(null)
|
||||
@@ -49,6 +54,12 @@ const rules: FormRules = {
|
||||
currency: [{ required: true, pattern: /^[A-Z]{3}$/, message: '货币须为三个大写字母', trigger: 'blur' }],
|
||||
}
|
||||
const canView = computed(() => access.can('firstleg:inbound:fee-detail:view'))
|
||||
const canViewFeeItems = computed(() => access.can('firstleg:fee-item:view'))
|
||||
const canViewPartners = computed(() => access.can('platform:counterparty:list'))
|
||||
const directionOptions = computed(() => [
|
||||
{ label: '应收', value: 'RECEIVABLE' },
|
||||
{ label: '应付', value: 'PAYABLE', disabled: !canViewPartners.value },
|
||||
])
|
||||
const applicableItems = computed(() => feeItems.value.filter((item) => form.direction === 'RECEIVABLE' ? item.warehouseReceivable : item.warehousePayable))
|
||||
|
||||
function canEdit(row: InboundFeeDetail) { return access.can('firstleg:inbound:fee-detail:edit') && row.reviewStatus !== 'APPROVED' }
|
||||
@@ -67,9 +78,21 @@ async function load() {
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
try { [feeItems.value, partners.value] = await Promise.all([listInboundFeeItemOptions(), listInboundFeePartnerOptions()]) }
|
||||
catch (error) { actionError.value = getApiErrorDetails(error, '费用维护选项加载失败') }
|
||||
async function loadFeeItems() {
|
||||
if (!canViewFeeItems.value || feeItemsLoading.value) return
|
||||
feeItemsLoading.value = true; feeItemsError.value = null
|
||||
try { feeItems.value = await listInboundFeeItemOptions() }
|
||||
catch (error) { feeItemsError.value = getApiErrorDetails(error, '费用项目加载失败') }
|
||||
finally { feeItemsLoading.value = false }
|
||||
}
|
||||
|
||||
async function loadPartners() {
|
||||
if (!canViewPartners.value || partnersLoading.value || partners.value.length || partnersLoadAttempted.value) return
|
||||
partnersLoadAttempted.value = true
|
||||
partnersLoading.value = true; partnersError.value = null
|
||||
try { partners.value = await listInboundFeePartnerOptions() }
|
||||
catch (error) { partnersError.value = getApiErrorDetails(error, '往来单位加载失败') }
|
||||
finally { partnersLoading.value = false }
|
||||
}
|
||||
|
||||
function assignForm(row?: InboundFeeDetail) {
|
||||
@@ -82,9 +105,12 @@ function assignForm(row?: InboundFeeDetail) {
|
||||
}
|
||||
|
||||
async function openEditor(mode: 'create' | 'edit' | 'adjust', row?: InboundFeeDetail) {
|
||||
partnersLoadAttempted.value = false
|
||||
editorMode.value = mode; target.value = row || null; assignForm(row); actionError.value = null
|
||||
feeItemsError.value = null; partnersError.value = null
|
||||
editorOpen.value = true
|
||||
if (!feeItems.value.length) await loadOptions()
|
||||
if (!feeItems.value.length) await loadFeeItems()
|
||||
if (form.direction === 'PAYABLE') await loadPartners()
|
||||
}
|
||||
|
||||
function normalizePayload(): SaveInboundFeeDetailRequest {
|
||||
@@ -100,6 +126,8 @@ async function finishAction(message: string) {
|
||||
|
||||
async function save() {
|
||||
if (!await formRef.value?.validate()) return
|
||||
if (!canViewFeeItems.value) { actionError.value = { message: '当前账号缺少费用项目查看权限,无法保存费用' }; return }
|
||||
if (form.direction === 'PAYABLE' && !canViewPartners.value) { actionError.value = { message: '当前账号缺少往来单位查看权限,无法维护应付费用' }; return }
|
||||
if (form.direction === 'PAYABLE' && !form.partnerId) { actionError.value = { message: '应付费用必须选择往来单位' }; return }
|
||||
saving.value = true; actionError.value = null
|
||||
try {
|
||||
@@ -142,7 +170,10 @@ async function voidRow(row: InboundFeeDetail) {
|
||||
}
|
||||
|
||||
watch(() => [props.accountId, props.inboundId], () => void load())
|
||||
watch(() => form.direction, () => { if (form.direction === 'RECEIVABLE') { form.partnerId = null; form.partnerName = null } })
|
||||
watch(() => form.direction, (direction) => {
|
||||
if (direction === 'RECEIVABLE') { form.partnerId = null; form.partnerName = null; partnersError.value = null }
|
||||
else void loadPartners()
|
||||
})
|
||||
onMounted(() => void load())
|
||||
</script>
|
||||
|
||||
@@ -152,7 +183,7 @@ onMounted(() => void load())
|
||||
<span>共 {{ rows.length }} 条应收应付费用明细</span>
|
||||
<div>
|
||||
<el-tooltip content="刷新费用明细" placement="top"><el-button circle aria-label="刷新费用明细" :loading="loading" @click="load"><RefreshCw :size="16" /></el-button></el-tooltip>
|
||||
<el-button v-if="access.can('firstleg:inbound:fee-detail:edit')" type="primary" @click="openEditor('create')"><Plus :size="16" />新增费用</el-button>
|
||||
<el-button v-if="access.can('firstleg:inbound:fee-detail:edit') && canViewFeeItems" type="primary" @click="openEditor('create')"><Plus :size="16" />新增费用</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-alert v-if="!canView" title="当前账号没有查看费用明细的权限" type="warning" :closable="false" show-icon />
|
||||
@@ -195,11 +226,15 @@ onMounted(() => void load())
|
||||
|
||||
<AppDialog v-model="editorOpen" :title="editorMode === 'create' ? '新增费用' : editorMode === 'adjust' ? '调整已审核费用' : '编辑费用'" width="min(680px, calc(100vw - 28px))" :confirm-loading="saving" confirm-text="保存" @confirm="save">
|
||||
<el-alert v-if="editorMode === 'adjust'" title="调整将生成新版本并重新进入待审核状态" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-if="!canViewFeeItems" title="当前账号缺少费用项目查看权限,无法新增或修改费用" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-if="!canViewPartners" title="当前账号缺少往来单位查看权限,应付费用不可维护;应收费用不受影响" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-if="feeItemsError" type="error" :closable="true" @close="feeItemsError = null"><template #title>{{ feeItemsError.message }}</template><ApiErrorMeta :details="feeItemsError" /></el-alert>
|
||||
<el-alert v-if="partnersError" type="error" :closable="true" @close="partnersError = null"><template #title>{{ partnersError.message }}</template><ApiErrorMeta :details="partnersError" /></el-alert>
|
||||
<el-alert v-if="actionError" type="error" :closable="true" @close="actionError = null"><template #title>{{ actionError.message }}</template><ApiErrorMeta :details="actionError" /></el-alert>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="fee-form">
|
||||
<el-form-item label="应收/应付" prop="direction"><el-segmented v-model="form.direction" :options="[{ label: '应收', value: 'RECEIVABLE' }, { label: '应付', value: 'PAYABLE' }]" /></el-form-item>
|
||||
<el-form-item label="费用项目" prop="feeItemId"><el-select v-model="form.feeItemId" filterable><el-option v-for="item in applicableItems" :key="item.id" :label="item.feeTypeName" :value="item.id" /></el-select></el-form-item>
|
||||
<el-form-item v-if="form.direction === 'PAYABLE'" label="往来单位" required><el-select v-model="form.partnerId" filterable><el-option v-for="partner in partners" :key="partner.id" :label="partner.partnerName" :value="partner.id" /></el-select></el-form-item>
|
||||
<el-form-item label="应收/应付" prop="direction"><el-segmented v-model="form.direction" :options="directionOptions" /></el-form-item>
|
||||
<el-form-item label="费用项目" prop="feeItemId"><el-select v-model="form.feeItemId" filterable :loading="feeItemsLoading" :disabled="!canViewFeeItems"><el-option v-for="item in applicableItems" :key="item.id" :label="item.feeTypeName" :value="item.id" /></el-select></el-form-item>
|
||||
<el-form-item v-if="form.direction === 'PAYABLE'" label="往来单位" required><el-select v-model="form.partnerId" filterable :loading="partnersLoading" :disabled="!canViewPartners"><el-option v-for="partner in partners" :key="partner.id" :label="partner.partnerName" :value="partner.id" /></el-select></el-form-item>
|
||||
<el-form-item label="业务发生日" prop="businessDate"><el-date-picker v-model="form.businessDate" type="date" value-format="YYYY-MM-DD" /></el-form-item>
|
||||
<el-form-item label="货币" prop="currency"><el-input model-value="CNY" readonly aria-label="货币 CNY" /></el-form-item>
|
||||
<el-form-item label="单价" prop="unitPrice"><el-input-number v-model="form.unitPrice" :min="0" :precision="4" /></el-form-item>
|
||||
|
||||
@@ -209,7 +209,7 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(source).toContain('子单 · 第 ${row.relation.splitSequence} 次')
|
||||
expect(source).toContain('title="父子订单关联"')
|
||||
expect(source).toContain('@click="openOrderRelation(row as UnifiedOrderResource)"')
|
||||
expect(source).toContain("{ key: 'fulfillment', label: '拆分履约', icon: ListChecks }")
|
||||
expect(source).toContain("{ key: 'fulfillment', label: '拆分履约', icon: OrderFulfillmentIcon }")
|
||||
expect(source).toContain("activeDetailTab === 'fulfillment'")
|
||||
expect(source).toContain('根单、已完成分片与当前余量')
|
||||
})
|
||||
@@ -251,10 +251,17 @@ describe('UnifiedOrdersView contract', () => {
|
||||
|
||||
it('mounts downstream progress inside the existing order detail without opening unsafe writes', () => {
|
||||
expect(source).toContain('UnifiedOrderWorkflowPanel')
|
||||
expect(source).toContain("{ key: 'workflow', label: '后半程作业'")
|
||||
expect(source).toContain("{ key: 'workflow', label: '后半程作业', icon: OrderFulfillmentIcon }")
|
||||
expect(source).toContain(':order-id="String(detail.summary.orderId)"')
|
||||
expect(source).not.toContain(':show-delivery=')
|
||||
expect(source).toContain("detail.value?.summary.inboundId")
|
||||
expect(routeSource).not.toContain('unified-order-workflow')
|
||||
})
|
||||
|
||||
it('keeps detail tabs compact on one horizontally scrollable row', () => {
|
||||
expect(source).toContain('.detail-tabs { display: flex; overflow-x: auto; overflow-y: hidden;')
|
||||
expect(source).toContain('min-width: max-content; min-height: 56px; flex: 0 0 auto;')
|
||||
expect(source).not.toContain('grid-template-columns: repeat(6, minmax(124px, 1fr))')
|
||||
expect(source).not.toContain('.detail-tabs { grid-template-columns: repeat(6, 132px); }')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch, type Component } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Box, ChevronDown, ChevronUp, CircleCheck, Eye, GitBranch, History, ListChecks, MoreHorizontal, PackageOpen, Ruler, SlidersHorizontal, StickyNote, WalletCards } from '@lucide/vue'
|
||||
import { ArrowLeft, Box, ChevronDown, ChevronUp, CircleCheck, Eye, GitBranch, History, MoreHorizontal, PackageOpen, Ruler, SlidersHorizontal, StickyNote, WalletCards } from '@lucide/vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
getPlatformUnifiedOrder,
|
||||
@@ -51,6 +51,15 @@ import {
|
||||
getInboundMeasurement,
|
||||
type InboundMeasurementDetail,
|
||||
} from '@/modules/inbounds'
|
||||
import {
|
||||
OrderBasicInfoIcon,
|
||||
OrderCargoInfoIcon,
|
||||
OrderFeeInfoIcon,
|
||||
OrderFulfillmentIcon,
|
||||
OrderHistoryIcon,
|
||||
OrderMeasurementIcon,
|
||||
OrderOtherIcon,
|
||||
} from '@/core/navigation/prototypeMenuIcons'
|
||||
|
||||
type FilterModel = QueryModel & {
|
||||
tenantId: string
|
||||
@@ -115,17 +124,17 @@ const detailTenantId = computed(() => typeof route.query.tenantId === 'string' ?
|
||||
const detailRouteKey = computed(() => orderId.value ? `${detailTenantId.value}:${orderId.value}` : '')
|
||||
|
||||
const detailTabs = [
|
||||
{ key: 'basic', label: '基本信息', icon: Box },
|
||||
{ key: 'cargo', label: '货品信息', icon: PackageOpen },
|
||||
{ key: 'fees', label: '费用信息', icon: WalletCards },
|
||||
{ key: 'history', label: '状态历史', icon: History },
|
||||
{ key: 'measurement', label: '测量数据', icon: Ruler },
|
||||
{ key: 'other', label: '其他', icon: StickyNote },
|
||||
{ key: 'fulfillment', label: '拆分履约', icon: ListChecks },
|
||||
{ key: 'basic', label: '基本信息', icon: OrderBasicInfoIcon },
|
||||
{ key: 'cargo', label: '货品信息', icon: OrderCargoInfoIcon },
|
||||
{ key: 'fees', label: '费用信息', icon: OrderFeeInfoIcon },
|
||||
{ key: 'history', label: '状态历史', icon: OrderHistoryIcon },
|
||||
{ key: 'measurement', label: '测量数据', icon: OrderMeasurementIcon },
|
||||
{ key: 'other', label: '其他', icon: OrderOtherIcon },
|
||||
{ key: 'fulfillment', label: '拆分履约', icon: OrderFulfillmentIcon },
|
||||
]
|
||||
|
||||
const detailTabOptions = computed(() => detail.value?.summary.inboundId
|
||||
? [...detailTabs, { key: 'workflow', label: '后半程作业', icon: ListChecks }]
|
||||
? [...detailTabs, { key: 'workflow', label: '后半程作业', icon: OrderFulfillmentIcon }]
|
||||
: detailTabs)
|
||||
|
||||
const customerMeasurementColumns = [
|
||||
@@ -1090,8 +1099,8 @@ onMounted(() => {
|
||||
.detail-overview article > span, .detail-overview article > small { display: block; overflow: hidden; color: var(--cc-muted); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.detail-overview strong { display: block; margin: 7px 0 5px; overflow: hidden; color: #172033; font-size: 20px; line-height: 1.2; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.detail-overview strong small { margin-left: 5px; color: #475467; font-size: 11px; }
|
||||
.detail-tabs { display: grid; grid-template-columns: repeat(6, minmax(124px, 1fr)); overflow-x: auto; border: 1px solid var(--cc-border); border-bottom: 0; border-radius: 8px 8px 0 0; background: #fff; }
|
||||
.detail-tabs button { position: relative; display: flex; min-height: 56px; align-items: center; justify-content: center; gap: 7px; padding: 0 14px; border: 0; border-right: 1px solid #edf0f4; background: transparent; color: #667085; font-weight: 650; cursor: pointer; }
|
||||
.detail-tabs { display: flex; overflow-x: auto; overflow-y: hidden; border: 1px solid var(--cc-border); border-bottom: 0; border-radius: 8px 8px 0 0; background: #fff; scrollbar-width: thin; }
|
||||
.detail-tabs button { position: relative; display: inline-flex; min-width: max-content; min-height: 56px; flex: 0 0 auto; align-items: center; justify-content: center; gap: 7px; padding: 0 22px; border: 0; border-right: 1px solid #edf0f4; background: transparent; color: #667085; font-weight: 650; cursor: pointer; }
|
||||
.detail-tabs button:last-child { border-right: 0; }
|
||||
.detail-tabs button::after { position: absolute; right: 14px; bottom: 0; left: 14px; height: 3px; background: transparent; content: ''; }
|
||||
.detail-tabs button:hover { background: #fafbff; color: #344054; }
|
||||
@@ -1140,6 +1149,6 @@ onMounted(() => {
|
||||
.notes-list li > p { margin: 0; color: var(--cc-text); font-size: 13px; }
|
||||
.notes-list span { display: block; margin-top: 5px; color: var(--cc-muted); font-size: 12px; }
|
||||
@media (max-width: 960px) { .detail-overview { grid-template-columns: repeat(2, minmax(0, 1fr)); } .detail-overview article:nth-child(2) { border-right: 0; } .detail-overview article:nth-child(-n+2) { border-bottom: 1px solid var(--cc-border); } .order-info-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .measurement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
||||
@media (max-width: 720px) { .page-intro { align-items: stretch; flex-direction: column; } .page-intro :deep(.el-button) { width: 100%; min-height: 44px; } .status-tab { min-height: 46px; padding: 0 14px; } .table-actions :deep(.el-button) { width: 100%; min-height: 40px; } .row-actions { flex-wrap: wrap; } .order-detail-header { align-items: stretch; flex-direction: column; } .order-detail-heading { display: grid; grid-template-columns: auto 36px minmax(0, 1fr) auto; } .detail-header-actions { display: grid; grid-template-columns: 1fr; } .detail-header-actions :deep(.el-button) { min-height: 40px; } .detail-overview, .order-info-grid, .measurement-grid { grid-template-columns: 1fr; } .detail-overview article { border-right: 0; border-bottom: 1px solid var(--cc-border); } .detail-overview article:last-child { border-bottom: 0; } .order-info-grid > div.wide { grid-column: auto; } .detail-tabs { grid-template-columns: repeat(6, 132px); } .detail-panel { padding: 16px; } .measurement-section-title { align-items: flex-start; flex-wrap: wrap; padding: 12px; } .measurement-section-summary { width: 100%; flex-basis: calc(100% - 34px); flex-wrap: wrap; justify-content: flex-start; gap: 6px 16px; white-space: normal; } .measurement-section-title > svg { margin-left: auto; } .measurement-total { flex-wrap: wrap; justify-content: flex-start; gap: 6px 16px; } .measurement-total strong { width: 100%; } }
|
||||
@media (max-width: 720px) { .page-intro { align-items: stretch; flex-direction: column; } .page-intro :deep(.el-button) { width: 100%; min-height: 44px; } .status-tab { min-height: 46px; padding: 0 14px; } .table-actions :deep(.el-button) { width: 100%; min-height: 40px; } .row-actions { flex-wrap: wrap; } .order-detail-header { align-items: stretch; flex-direction: column; } .order-detail-heading { display: grid; grid-template-columns: auto 36px minmax(0, 1fr) auto; } .detail-header-actions { display: grid; grid-template-columns: 1fr; } .detail-header-actions :deep(.el-button) { min-height: 40px; } .detail-overview, .order-info-grid, .measurement-grid { grid-template-columns: 1fr; } .detail-overview article { border-right: 0; border-bottom: 1px solid var(--cc-border); } .detail-overview article:last-child { border-bottom: 0; } .order-info-grid > div.wide { grid-column: auto; } .detail-tabs button { padding: 0 18px; } .detail-panel { padding: 16px; } .measurement-section-title { align-items: flex-start; flex-wrap: wrap; padding: 12px; } .measurement-section-summary { width: 100%; flex-basis: calc(100% - 34px); flex-wrap: wrap; justify-content: flex-start; gap: 6px 16px; white-space: normal; } .measurement-section-title > svg { margin-left: auto; } .measurement-total { flex-wrap: wrap; justify-content: flex-start; gap: 6px 16px; } .measurement-total strong { width: 100%; } }
|
||||
@media (max-width: 420px) { .order-detail-heading { grid-template-columns: auto minmax(0, 1fr) auto; } .order-mark { display: none; } }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user