feat:库存总览页面
parent
b7890af647
commit
d44dbe3034
@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<div class="stock-overview">
|
||||
<ContentWrap>
|
||||
<el-form
|
||||
ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px stock-overview__query"
|
||||
label-width="auto">
|
||||
<el-form-item :label="t('ErpStock.Overview.materialCategory')" prop="categoryType">
|
||||
<el-select
|
||||
v-model="queryParams.categoryType" clearable :placeholder="t('common.selectText')"
|
||||
class="!w-220px">
|
||||
<el-option v-for="item in categoryTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('ErpStock.Stock.warehouse')" prop="warehouseId">
|
||||
<el-select
|
||||
v-model="queryParams.warehouseId" clearable filterable
|
||||
:placeholder="t('ErpStock.Stock.placeholderWarehouse')" class="!w-220px">
|
||||
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('ErpStock.Overview.location')" prop="areaId">
|
||||
<el-select
|
||||
v-model="queryParams.areaId" clearable filterable :placeholder="t('common.selectText')"
|
||||
class="!w-220px">
|
||||
<el-option v-for="item in areaOptions" :key="item.id" :label="item.areaName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('ErpStock.Overview.dateRange')" prop="dateRange">
|
||||
<el-date-picker
|
||||
v-model="queryParams.dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||||
:start-placeholder="t('ErpStock.Record.placeholderCreateTimeStart')"
|
||||
:end-placeholder="t('ErpStock.Record.placeholderCreateTimeEnd')"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-280px" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('ErpStock.Overview.keyword')" prop="keyword">
|
||||
<el-input
|
||||
v-model="queryParams.keyword" clearable :placeholder="t('ErpStock.Overview.placeholderKeyword')"
|
||||
class="!w-240px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">
|
||||
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<div class="stock-overview__cards">
|
||||
<ContentWrap
|
||||
v-for="item in summaryCards" :key="item.title" class="stock-overview__card-wrap"
|
||||
:body-style="{ padding: '22px 24px' }">
|
||||
<div class="stock-overview__card">
|
||||
<div class="stock-overview__card-main">
|
||||
<div class="stock-overview__card-title">{{ item.title }}</div>
|
||||
<div v-for="line in item.lines" :key="line" class="stock-overview__card-line">
|
||||
{{ line }}
|
||||
</div>
|
||||
</div>
|
||||
<Icon :icon="item.icon" :class="['stock-overview__card-icon', `is-${item.color}`]" :size="34" />
|
||||
</div>
|
||||
<div v-if="item.tip" class="stock-overview__card-tip">{{ item.tip }}</div>
|
||||
</ContentWrap>
|
||||
</div>
|
||||
|
||||
<div class="stock-overview__tables">
|
||||
<ContentWrap :title="t('ErpStock.Overview.stockDetail')" class="stock-overview__stock">
|
||||
<el-table
|
||||
v-loading="stockLoading" :data="stockList" :stripe="true" :show-overflow-tooltip="true" row-key="id"
|
||||
height="520">
|
||||
<el-table-column :label="t('ErpStock.Stock.code')" align="center" sortable prop="barCode" min-width="130" />
|
||||
<el-table-column :label="t('ErpStock.Stock.name')" align="center" sortable prop="name" min-width="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.name || row.productName || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="t('ErpStock.Overview.materialCategory')" align="center" prop="categoryType"
|
||||
min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getCategoryTagType(row.categoryType)">
|
||||
{{ getCategoryLabel(row.categoryType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="t('ErpStock.Stock.subCategory')" align="center" prop="categoryName"
|
||||
min-width="110" />
|
||||
<el-table-column :label="t('ErpStock.Stock.warehouse')" align="center" prop="warehouseName" min-width="110" />
|
||||
<el-table-column :label="t('ErpStock.Overview.location')" align="center" prop="areaName" min-width="110" />
|
||||
<el-table-column :label="t('ErpStock.Stock.stockDisplay')" align="center" prop="stockDisplay" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.stockDisplay" class="stock-overview__display">{{ row.stockDisplay }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ErpStock.Stock.count')" align="center" sortable prop="count" min-width="110">
|
||||
<template #default="{ row }">
|
||||
{{ formatNumber(row.count) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ErpStock.Stock.unit')" align="center" prop="unitName" min-width="80" />
|
||||
<el-table-column :label="t('ErpStock.Overview.latestChangeTime')" align="center" min-width="170">
|
||||
<template #default="{ row }">
|
||||
{{ formatStockTime(getLatestChangeTime(row)) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<Pagination
|
||||
:total="stockTotal" v-model:page="stockQuery.pageNo" v-model:limit="stockQuery.pageSize"
|
||||
@pagination="getStockList" />
|
||||
</ContentWrap>
|
||||
|
||||
<ContentWrap
|
||||
:title="t('ErpStock.Overview.recentRecord')" class="stock-overview__record"
|
||||
:body-style="{ padding: '10px 14px 16px' }">
|
||||
<template #header>
|
||||
<el-button link type="primary" class="stock-overview__more" @click="goRecordPage">
|
||||
{{ t('ErpStock.Overview.more') }}
|
||||
<Icon icon="ep:arrow-right" class="ml-2px" />
|
||||
</el-button>
|
||||
</template>
|
||||
<template #default>
|
||||
<el-table
|
||||
v-loading="recordLoading" :data="recordList" :stripe="true" :show-overflow-tooltip="true"
|
||||
row-key="id" height="562">
|
||||
<el-table-column :label="t('ErpStock.Overview.time')" align="center" min-width="160">
|
||||
<template #default="{ row }">
|
||||
{{ formatStockTime(row.recordTime || row.createTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ErpStock.Record.bizType')" align="center" prop="bizDirection" min-width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.bizDirection" :type="getDirectionTagType(row.bizDirection)">
|
||||
{{ formatDirection(row.bizDirection) }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ErpStock.Overview.material')" align="center" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<div class="stock-overview__material">
|
||||
<span>{{ row.productName || '-' }}</span>
|
||||
<span v-if="row.bizNo">{{ row.bizNo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ErpStock.Record.count')" align="center" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span :class="getDirectionClass(row.bizDirection)">
|
||||
{{ formatRecordCount(row) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="t('ErpStock.Record.creatorName')" align="center" prop="creatorName"
|
||||
min-width="90" />
|
||||
</el-table>
|
||||
</template>
|
||||
</ContentWrap>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getDictObj, getIntDictOptions } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import { StockApi, StockVO } from '@/api/erp/stock/stock'
|
||||
import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record'
|
||||
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
|
||||
import { useDictStoreWithOut } from '@/store/modules/dict'
|
||||
|
||||
defineOptions({ name: 'ErpStockOverview' })
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const dictStore = useDictStoreWithOut()
|
||||
|
||||
const queryFormRef = ref()
|
||||
const warehouseList = ref<WarehouseVO[]>([])
|
||||
const categoryTypeOptions = computed(() => getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE))
|
||||
const queryParams = reactive<{
|
||||
categoryType?: number
|
||||
warehouseId?: number
|
||||
areaId?: number
|
||||
dateRange: string[]
|
||||
keyword?: string
|
||||
}>({
|
||||
categoryType: undefined,
|
||||
warehouseId: undefined,
|
||||
areaId: undefined,
|
||||
dateRange: [],
|
||||
keyword: undefined
|
||||
})
|
||||
|
||||
const stockLoading = ref(false)
|
||||
const recordLoading = ref(false)
|
||||
const stockList = ref<StockVO[]>([])
|
||||
const recordList = ref<StockRecordVO[]>([])
|
||||
const stockTotal = ref(0)
|
||||
const stockQuery = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
const recordQuery = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 9
|
||||
})
|
||||
|
||||
const summaryCards = computed(() => [
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.finishedGoods.title'),
|
||||
icon: 'ep:box',
|
||||
color: 'blue',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.finishedGoods.line1'),
|
||||
t('ErpStock.Overview.cards.finishedGoods.line2'),
|
||||
t('ErpStock.Overview.cards.finishedGoods.line3')
|
||||
],
|
||||
tip: t('ErpStock.Overview.cards.finishedGoods.tip')
|
||||
},
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.rawMaterial.title'),
|
||||
icon: 'ep:collection',
|
||||
color: 'green',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.rawMaterial.line1'),
|
||||
t('ErpStock.Overview.cards.rawMaterial.line2'),
|
||||
t('ErpStock.Overview.cards.rawMaterial.line3'),
|
||||
t('ErpStock.Overview.cards.rawMaterial.line4')
|
||||
],
|
||||
tip: t('ErpStock.Overview.cards.rawMaterial.tip')
|
||||
},
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.sparePart.title'),
|
||||
icon: 'ep:setting',
|
||||
color: 'orange',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.sparePart.line1'),
|
||||
t('ErpStock.Overview.cards.sparePart.line2'),
|
||||
t('ErpStock.Overview.cards.sparePart.line3'),
|
||||
t('ErpStock.Overview.cards.sparePart.line4')
|
||||
],
|
||||
tip: t('ErpStock.Overview.cards.sparePart.tip')
|
||||
},
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.todayIn.title'),
|
||||
icon: 'ep:download',
|
||||
color: 'blue',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.todayIn.line1'),
|
||||
t('ErpStock.Overview.cards.todayIn.line2'),
|
||||
t('ErpStock.Overview.cards.todayIn.line3'),
|
||||
t('ErpStock.Overview.cards.todayIn.line4'),
|
||||
t('ErpStock.Overview.cards.todayIn.line5')
|
||||
]
|
||||
},
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.todayOut.title'),
|
||||
icon: 'ep:upload',
|
||||
color: 'green',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.todayOut.line1'),
|
||||
t('ErpStock.Overview.cards.todayOut.line2'),
|
||||
t('ErpStock.Overview.cards.todayOut.line3'),
|
||||
t('ErpStock.Overview.cards.todayOut.line4'),
|
||||
t('ErpStock.Overview.cards.todayOut.line5')
|
||||
]
|
||||
},
|
||||
{
|
||||
title: t('ErpStock.Overview.cards.warning.title'),
|
||||
icon: 'ep:warning-filled',
|
||||
color: 'red',
|
||||
lines: [
|
||||
t('ErpStock.Overview.cards.warning.line1'),
|
||||
t('ErpStock.Overview.cards.warning.line2'),
|
||||
t('ErpStock.Overview.cards.warning.line3'),
|
||||
t('ErpStock.Overview.cards.warning.line4')
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
const areaOptions = computed(() => {
|
||||
const areaMap = new Map<number, { id: number; areaName: string }>()
|
||||
warehouseList.value.forEach((warehouse) => {
|
||||
warehouse.areaList?.forEach((area) => {
|
||||
areaMap.set(area.id, {
|
||||
id: area.id,
|
||||
areaName: `${warehouse.name || ''}${warehouse.name ? ' / ' : ''}${area.areaName}`
|
||||
})
|
||||
})
|
||||
})
|
||||
return Array.from(areaMap.values())
|
||||
})
|
||||
|
||||
const filterEmptyParams = (params: Record<string, any>) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(params).filter(([, value]) => {
|
||||
if (Array.isArray(value)) return value.length > 0
|
||||
return value !== undefined && value !== null && value !== ''
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const buildBaseQueryParams = () => {
|
||||
const [beginTime, endTime] = queryParams.dateRange || []
|
||||
return filterEmptyParams({
|
||||
categoryType: queryParams.categoryType,
|
||||
warehouseId: queryParams.warehouseId,
|
||||
areaId: queryParams.areaId,
|
||||
keyword: queryParams.keyword,
|
||||
createTime: beginTime && endTime ? [beginTime, endTime] : undefined
|
||||
})
|
||||
}
|
||||
|
||||
const getStockList = async () => {
|
||||
stockLoading.value = true
|
||||
try {
|
||||
const data = await StockApi.getStockPage(
|
||||
filterEmptyParams({
|
||||
...buildBaseQueryParams(),
|
||||
pageNo: stockQuery.pageNo,
|
||||
pageSize: stockQuery.pageSize
|
||||
})
|
||||
)
|
||||
stockList.value = data.list || []
|
||||
stockTotal.value = data.total || 0
|
||||
} finally {
|
||||
stockLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getRecordList = async () => {
|
||||
recordLoading.value = true
|
||||
try {
|
||||
const data = await StockRecordApi.getStockRecordPage(
|
||||
filterEmptyParams({
|
||||
...buildBaseQueryParams(),
|
||||
pageNo: recordQuery.pageNo,
|
||||
pageSize: recordQuery.pageSize
|
||||
})
|
||||
)
|
||||
recordList.value = data.list || []
|
||||
} finally {
|
||||
recordLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
await Promise.all([getStockList(), getRecordList()])
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
stockQuery.pageNo = 1
|
||||
recordQuery.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const goRecordPage = () => {
|
||||
router.push({ path: '/warehouse/record' })
|
||||
}
|
||||
|
||||
const getCategoryLabel = (value?: number | string) => {
|
||||
return getDictObj(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE, value)?.label || '-'
|
||||
}
|
||||
|
||||
const getCategoryTagType = (value?: number | string) => {
|
||||
const dict = getDictObj(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE, value)
|
||||
const colorType = String(dict?.colorType || '')
|
||||
return ['success', 'info', 'warning', 'danger'].includes(colorType) ? colorType : 'primary'
|
||||
}
|
||||
|
||||
const formatNumber = (value: number | string | undefined) => {
|
||||
if (value === undefined || value === null || value === '') return '-'
|
||||
const num = Number(value)
|
||||
return Number.isFinite(num) ? num.toLocaleString() : String(value)
|
||||
}
|
||||
|
||||
const formatStockTime = (value: any) => {
|
||||
return value ? formatDate(value, 'YYYY-MM-DD HH:mm:ss') : '-'
|
||||
}
|
||||
|
||||
const getLatestChangeTime = (row: any) => {
|
||||
return (
|
||||
row.latestChangeTime ??
|
||||
row.latestInTime ??
|
||||
row.lastInTime ??
|
||||
row.recentInTime ??
|
||||
row.latestStockInTime ??
|
||||
row.lastStockInTime ??
|
||||
row.latestOutTime ??
|
||||
row.lastOutTime ??
|
||||
row.recentOutTime ??
|
||||
row.latestStockOutTime ??
|
||||
row.lastStockOutTime
|
||||
)
|
||||
}
|
||||
|
||||
const isStockIn = (direction?: string) => ['入库', 'Inbound'].includes(String(direction || ''))
|
||||
const isStockOut = (direction?: string) => ['出库', 'Outbound'].includes(String(direction || ''))
|
||||
|
||||
const formatDirection = (direction?: string) => {
|
||||
if (isStockIn(direction)) return t('ErpStock.Overview.stockIn')
|
||||
if (isStockOut(direction)) return t('ErpStock.Overview.stockOut')
|
||||
return direction || '-'
|
||||
}
|
||||
|
||||
const getDirectionClass = (direction?: string) => {
|
||||
if (isStockIn(direction)) return 'stock-overview__count-in'
|
||||
if (isStockOut(direction)) return 'stock-overview__count-out'
|
||||
return ''
|
||||
}
|
||||
|
||||
const getDirectionTagType = (direction?: string) => {
|
||||
if (isStockIn(direction)) return 'success'
|
||||
if (isStockOut(direction)) return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
const formatRecordCount = (row: StockRecordVO) => {
|
||||
const unit = row.unitName ? ` ${row.unitName}` : ''
|
||||
const num = Number(row.count)
|
||||
if (!Number.isFinite(num)) return `${row.count ?? '-'}${unit}`
|
||||
const value = Math.abs(num).toLocaleString()
|
||||
if (isStockIn(row.bizDirection)) return `+${value}${unit}`
|
||||
if (isStockOut(row.bizDirection)) return `-${value}${unit}`
|
||||
return `${num.toLocaleString()}${unit}`
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await dictStore.setDictMap()
|
||||
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
|
||||
await getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stock-overview {
|
||||
.stock-overview__query {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.stock-overview__cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.stock-overview__card-wrap {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.stock-overview__card {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
min-height: 174px;
|
||||
}
|
||||
|
||||
.stock-overview__card-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.stock-overview__card-title {
|
||||
margin-bottom: 16px;
|
||||
color: var(--el-text-color-primary);
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.stock-overview__card-line {
|
||||
margin-bottom: 13px;
|
||||
color: var(--el-text-color-regular);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.stock-overview__card-tip {
|
||||
color: var(--el-text-color-placeholder);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stock-overview__card-icon {
|
||||
flex: none;
|
||||
|
||||
&.is-blue {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.is-green {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
&.is-orange {
|
||||
color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
&.is-red {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
.stock-overview__tables {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.7fr) minmax(460px, 1fr);
|
||||
gap: 15px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.stock-overview__stock,
|
||||
.stock-overview__record {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.stock-overview__more {
|
||||
margin-left: auto;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stock-overview__display {
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stock-overview__material {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
line-height: 1.25;
|
||||
|
||||
span:last-child {
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-overview__count-in {
|
||||
color: var(--el-color-success);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.stock-overview__count-out {
|
||||
color: var(--el-color-danger);
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1600px) {
|
||||
.stock-overview {
|
||||
.stock-overview__cards {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.stock-overview {
|
||||
.stock-overview__tables {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.stock-overview {
|
||||
.stock-overview__query {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stock-overview__cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue