数据分析ui补充完善,接入数据库
This commit is contained in:
@@ -93,298 +93,305 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
<script setup lang="uts">
|
||||
import { computed, onLoad, onShow, reactive, ref } from 'vue'
|
||||
|
||||
import AnalyticsSidebarMenu from '@/components/analytics/AnalyticsSidebarMenu.uvue'
|
||||
import AnalyticsTopBar from '@/components/analytics/AnalyticsTopBar.uvue'
|
||||
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
||||
|
||||
import { fetchMarketTrends } from '@/services/analytics/marketTrendsService.uts'
|
||||
import { mapAnalyticsError } from '@/services/analytics/errorMapper.uts'
|
||||
|
||||
type TimePeriod = { value: string; label: string }
|
||||
import type { TimePeriod } from '@/types/analytics/common.uts'
|
||||
import type { MarketTrendsResponse } from '@/types/analytics/market.uts'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AnalyticsSidebarMenu,
|
||||
AnalyticsTopBar,
|
||||
EChartsView
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lastUpdateTime: '',
|
||||
selectedPeriod: '7d',
|
||||
showMoreMenu: false,
|
||||
showSidebarMenu: false,
|
||||
currentPath: '/pages/mall/analytics/market-trends',
|
||||
timePeriods: [
|
||||
{ value: '7d', label: '7天' },
|
||||
{ value: '30d', label: '30天' },
|
||||
{ value: '90d', label: '90天' },
|
||||
{ value: '1y', label: '1年' }
|
||||
] as Array<TimePeriod>,
|
||||
const lastUpdateTime = ref('')
|
||||
const selectedPeriod = ref('7d')
|
||||
const showMoreMenu = ref(false)
|
||||
const showSidebarMenu = ref(false)
|
||||
const currentPath = ref('/pages/mall/analytics/market-trends')
|
||||
|
||||
marketTrendOption: {} as any,
|
||||
industryCompareOption: {} as any,
|
||||
seasonalTrendOption: {} as any,
|
||||
priceTrendOption: {} as any,
|
||||
competitionOption: {} as any
|
||||
}
|
||||
},
|
||||
const timePeriods = ref<Array<TimePeriod>>([
|
||||
{ value: '7d', label: '7天' },
|
||||
{ value: '30d', label: '30天' },
|
||||
{ value: '90d', label: '90天' },
|
||||
{ value: '1y', label: '1年' }
|
||||
])
|
||||
|
||||
computed: {
|
||||
selectedPeriodText(): string {
|
||||
const p = this.timePeriods.find((t) => t.value === this.selectedPeriod)
|
||||
return p ? p.label : '7天'
|
||||
}
|
||||
},
|
||||
const marketTrendOption = ref<any>({})
|
||||
const industryCompareOption = ref<any>({})
|
||||
const seasonalTrendOption = ref<any>({})
|
||||
const priceTrendOption = ref<any>({})
|
||||
const competitionOption = ref<any>({})
|
||||
|
||||
onLoad() {
|
||||
this.currentPath = '/pages/mall/analytics/market-trends'
|
||||
this.updateTime()
|
||||
this.loadMarketData()
|
||||
},
|
||||
const _marketTrendRows = ref<any>(null)
|
||||
const _industryRows = ref<any>(null)
|
||||
const _seasonalRows = ref<any>(null)
|
||||
const _priceRows = ref<any>(null)
|
||||
const _competitionRows = ref<any>(null)
|
||||
|
||||
onShow() {
|
||||
this.currentPath = '/pages/mall/analytics/market-trends'
|
||||
},
|
||||
const selectedPeriodText = computed((): string => {
|
||||
const p = timePeriods.value.find((t) => t.value === selectedPeriod.value)
|
||||
return p ? p.label : '7天'
|
||||
})
|
||||
|
||||
methods: {
|
||||
async loadMarketData() {
|
||||
try {
|
||||
const data = await fetchMarketTrends(this.selectedPeriod)
|
||||
onLoad(() => {
|
||||
currentPath.value = '/pages/mall/analytics/market-trends'
|
||||
updateTime()
|
||||
loadMarketData()
|
||||
})
|
||||
|
||||
;(this as any)._marketTrendRows = data.trendRows
|
||||
;(this as any)._industryRows = data.categoryRows
|
||||
;(this as any)._seasonalRows = data.seasonalRows
|
||||
;(this as any)._priceRows = data.priceRows
|
||||
;(this as any)._competitionRows = data.competitionRows
|
||||
onShow(() => {
|
||||
currentPath.value = '/pages/mall/analytics/market-trends'
|
||||
})
|
||||
|
||||
this.updateTime()
|
||||
this.buildChartOptions()
|
||||
} catch (e) {
|
||||
console.error('loadMarketData failed:', e)
|
||||
this.updateTime()
|
||||
this.buildChartOptions()
|
||||
uni.showToast({ title: mapAnalyticsError(e, { fallbackMessage: '市场趋势数据加载失败' }), icon: 'none' })
|
||||
}
|
||||
},
|
||||
async function loadMarketData() {
|
||||
try {
|
||||
const data = (await fetchMarketTrends(selectedPeriod.value)) as MarketTrendsResponse
|
||||
|
||||
selectPeriod(p: string) {
|
||||
this.selectedPeriod = p
|
||||
this.loadMarketData()
|
||||
},
|
||||
_marketTrendRows.value = data.trendRows
|
||||
_industryRows.value = data.categoryRows
|
||||
_seasonalRows.value = data.seasonalRows
|
||||
_priceRows.value = data.priceRows
|
||||
_competitionRows.value = data.competitionRows
|
||||
|
||||
refreshData() {
|
||||
this.loadMarketData()
|
||||
uni.showToast({ title: '已刷新', icon: 'success' })
|
||||
},
|
||||
|
||||
exportReport() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['导出Excel', '导出PDF', '导出图片'],
|
||||
success: () => uni.showToast({ title: '导出成功', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
updateTime() {
|
||||
const now = new Date()
|
||||
const hh = now.getHours().toString().padStart(2, '0')
|
||||
const mm = now.getMinutes().toString().padStart(2, '0')
|
||||
this.lastUpdateTime = `${hh}:${mm}`
|
||||
},
|
||||
|
||||
buildChartOptions() {
|
||||
const trendAny = (this as any)._marketTrendRows as any
|
||||
const industryAny = (this as any)._industryRows as any
|
||||
const seasonalAny = (this as any)._seasonalRows as any
|
||||
const priceAny = (this as any)._priceRows as any
|
||||
const compAny = (this as any)._competitionRows as any
|
||||
|
||||
const trendRows = Array.isArray(trendAny) ? trendAny as Array<UTSJSONObject> : []
|
||||
const industryRows = Array.isArray(industryAny) ? industryAny as Array<UTSJSONObject> : []
|
||||
const seasonalRows = Array.isArray(seasonalAny) ? seasonalAny as Array<UTSJSONObject> : []
|
||||
const priceRows = Array.isArray(priceAny) ? priceAny as Array<UTSJSONObject> : []
|
||||
const compRows = Array.isArray(compAny) ? compAny as Array<UTSJSONObject> : []
|
||||
|
||||
// 1) 市场整体趋势:GMV / 订单数 / 用户数
|
||||
const mtDays: string[] = []
|
||||
const mtGmv: number[] = []
|
||||
const mtOrders: number[] = []
|
||||
const mtUsers: number[] = []
|
||||
|
||||
for (let i = 0; i < trendRows.length; i++) {
|
||||
const r = trendRows[i]
|
||||
const dayStr = r.getString('day') ?? ''
|
||||
mtDays.push(dayStr.length >= 10 ? dayStr.substring(5, 10) : dayStr)
|
||||
mtGmv.push(r.getNumber('gmv') ?? 0)
|
||||
mtOrders.push(r.getNumber('orders') ?? 0)
|
||||
mtUsers.push(r.getNumber('users') ?? 0)
|
||||
}
|
||||
|
||||
this.marketTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
data: ['GMV', '订单数', '用户数'],
|
||||
top: 'bottom'
|
||||
},
|
||||
grid: { left: 50, right: 60, top: 40, bottom: 60 },
|
||||
xAxis: { type: 'category', data: mtDays },
|
||||
yAxis: [
|
||||
{ type: 'value', name: 'GMV', splitLine: { lineStyle: { color: '#e5e7eb' } } },
|
||||
{ type: 'value', name: '数量', position: 'right', splitLine: { show: false } }
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: mtGmv,
|
||||
barMaxWidth: 26,
|
||||
itemStyle: { color: '#3b82f6' }
|
||||
},
|
||||
{
|
||||
name: '订单数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtOrders
|
||||
},
|
||||
{
|
||||
name: '用户数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtUsers
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 2) 行业对比:分类 GMV
|
||||
const catNames: string[] = []
|
||||
const catSales: number[] = []
|
||||
for (let i = 0; i < industryRows.length; i++) {
|
||||
const r = industryRows[i]
|
||||
catNames.push(r.getString('category_name') ?? '未分类')
|
||||
catSales.push(r.getNumber('total_sales') ?? 0)
|
||||
}
|
||||
this.industryCompareOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 80, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'value' },
|
||||
yAxis: { type: 'category', data: catNames },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: catSales
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 3) 季节性趋势:按月 GMV
|
||||
const seaMonths: string[] = []
|
||||
const seaGmv: number[] = []
|
||||
for (let i = 0; i < seasonalRows.length; i++) {
|
||||
const r = seasonalRows[i]
|
||||
seaMonths.push(r.getString('month') ?? '')
|
||||
seaGmv.push(r.getNumber('total_gmv') ?? 0)
|
||||
}
|
||||
this.seasonalTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: seaMonths },
|
||||
yAxis: { type: 'value', name: 'GMV' },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seaGmv
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 4) 价格趋势:按天平均价格
|
||||
const priceDays: string[] = []
|
||||
const avgPrices: number[] = []
|
||||
for (let i = 0; i < priceRows.length; i++) {
|
||||
const r = priceRows[i]
|
||||
const d = r.getString('day') ?? ''
|
||||
priceDays.push(d.length >= 10 ? d.substring(5, 10) : d)
|
||||
avgPrices.push(r.getNumber('avg_price') ?? 0)
|
||||
}
|
||||
this.priceTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: priceDays },
|
||||
yAxis: { type: 'value', name: '平均价格' },
|
||||
series: [
|
||||
{
|
||||
name: '平均价格',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: avgPrices
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 5) 竞争分析:商家 GMV 对比
|
||||
const merchantNames: string[] = []
|
||||
const merchantGmv: number[] = []
|
||||
for (let i = 0; i < compRows.length; i++) {
|
||||
const r = compRows[i]
|
||||
merchantNames.push(r.getString('merchant_name') ?? '未知商家')
|
||||
merchantGmv.push(r.getNumber('gmv') ?? 0)
|
||||
}
|
||||
this.competitionOption = {
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { top: 'bottom' },
|
||||
series: [
|
||||
{
|
||||
name: '商家GMV',
|
||||
type: 'pie',
|
||||
radius: ['35%', '65%'],
|
||||
center: ['50%', '50%'],
|
||||
data: merchantNames.map((n, idx) => {
|
||||
return { name: n, value: merchantGmv[idx] }
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
handleMenu() {
|
||||
this.showSidebarMenu = true
|
||||
},
|
||||
handleSidebarUpdate(visible: boolean) {
|
||||
this.showSidebarMenu = visible
|
||||
},
|
||||
|
||||
toggleMoreMenu() {
|
||||
this.showMoreMenu = !this.showMoreMenu
|
||||
},
|
||||
|
||||
closeMoreMenu() {
|
||||
this.showMoreMenu = false
|
||||
},
|
||||
handleSearch() {
|
||||
uni.showToast({ title: '搜索', icon: 'none' })
|
||||
},
|
||||
handleNotification() {
|
||||
uni.showToast({ title: '通知', icon: 'none' })
|
||||
},
|
||||
handleFullscreen() {
|
||||
uni.showToast({ title: '全屏', icon: 'none' })
|
||||
},
|
||||
handleMobile() {
|
||||
uni.showToast({ title: '移动端', icon: 'none' })
|
||||
},
|
||||
handleDropdown() {
|
||||
uni.showToast({ title: '下拉菜单', icon: 'none' })
|
||||
},
|
||||
handleSettings() {
|
||||
uni.showToast({ title: '设置', icon: 'none' })
|
||||
}
|
||||
updateTime()
|
||||
buildChartOptions()
|
||||
} catch (e) {
|
||||
console.error('loadMarketData failed:', e)
|
||||
updateTime()
|
||||
buildChartOptions()
|
||||
uni.showToast({ title: mapAnalyticsError(e, { fallbackMessage: '市场趋势数据加载失败' }), icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
function selectPeriod(p: string) {
|
||||
selectedPeriod.value = p
|
||||
loadMarketData()
|
||||
}
|
||||
|
||||
function refreshData() {
|
||||
loadMarketData()
|
||||
uni.showToast({ title: '已刷新', icon: 'success' })
|
||||
}
|
||||
|
||||
function exportReport() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['导出Excel', '导出PDF', '导出图片'],
|
||||
success: () => uni.showToast({ title: '导出成功', icon: 'success' })
|
||||
})
|
||||
}
|
||||
|
||||
function updateTime() {
|
||||
const now = new Date()
|
||||
const hh = now.getHours().toString().padStart(2, '0')
|
||||
const mm = now.getMinutes().toString().padStart(2, '0')
|
||||
lastUpdateTime.value = `${hh}:${mm}`
|
||||
}
|
||||
|
||||
function buildChartOptions() {
|
||||
const trendAny = _marketTrendRows.value
|
||||
const industryAny = _industryRows.value
|
||||
const seasonalAny = _seasonalRows.value
|
||||
const priceAny = _priceRows.value
|
||||
const compAny = _competitionRows.value
|
||||
|
||||
const trendRows = Array.isArray(trendAny) ? (trendAny as Array<UTSJSONObject>) : []
|
||||
const industryRows = Array.isArray(industryAny) ? (industryAny as Array<UTSJSONObject>) : []
|
||||
const seasonalRows = Array.isArray(seasonalAny) ? (seasonalAny as Array<UTSJSONObject>) : []
|
||||
const priceRows = Array.isArray(priceAny) ? (priceAny as Array<UTSJSONObject>) : []
|
||||
const compRows = Array.isArray(compAny) ? (compAny as Array<UTSJSONObject>) : []
|
||||
|
||||
// 1) 市场整体趋势:GMV / 订单数 / 用户数
|
||||
const mtDays: string[] = []
|
||||
const mtGmv: number[] = []
|
||||
const mtOrders: number[] = []
|
||||
const mtUsers: number[] = []
|
||||
|
||||
for (let i = 0; i < trendRows.length; i++) {
|
||||
const r = trendRows[i]
|
||||
const dayStr = r.getString('day') ?? ''
|
||||
mtDays.push(dayStr.length >= 10 ? dayStr.substring(5, 10) : dayStr)
|
||||
mtGmv.push(r.getNumber('gmv') ?? 0)
|
||||
mtOrders.push(r.getNumber('orders') ?? 0)
|
||||
mtUsers.push(r.getNumber('users') ?? 0)
|
||||
}
|
||||
|
||||
marketTrendOption.value = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
data: ['GMV', '订单数', '用户数'],
|
||||
top: 'bottom'
|
||||
},
|
||||
grid: { left: 50, right: 60, top: 40, bottom: 60 },
|
||||
xAxis: { type: 'category', data: mtDays },
|
||||
yAxis: [
|
||||
{ type: 'value', name: 'GMV', splitLine: { lineStyle: { color: '#e5e7eb' } } },
|
||||
{ type: 'value', name: '数量', position: 'right', splitLine: { show: false } }
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: mtGmv,
|
||||
barMaxWidth: 26,
|
||||
itemStyle: { color: '#3b82f6' }
|
||||
},
|
||||
{
|
||||
name: '订单数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtOrders
|
||||
},
|
||||
{
|
||||
name: '用户数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtUsers
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 2) 行业对比:分类 GMV
|
||||
const catNames: string[] = []
|
||||
const catSales: number[] = []
|
||||
for (let i = 0; i < industryRows.length; i++) {
|
||||
const r = industryRows[i]
|
||||
catNames.push(r.getString('category_name') ?? '未分类')
|
||||
catSales.push(r.getNumber('total_sales') ?? 0)
|
||||
}
|
||||
|
||||
industryCompareOption.value = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 80, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'value' },
|
||||
yAxis: { type: 'category', data: catNames },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: catSales
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 3) 季节性趋势:按月 GMV
|
||||
const seaMonths: string[] = []
|
||||
const seaGmv: number[] = []
|
||||
for (let i = 0; i < seasonalRows.length; i++) {
|
||||
const r = seasonalRows[i]
|
||||
seaMonths.push(r.getString('month') ?? '')
|
||||
seaGmv.push(r.getNumber('total_gmv') ?? 0)
|
||||
}
|
||||
|
||||
seasonalTrendOption.value = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: seaMonths },
|
||||
yAxis: { type: 'value', name: 'GMV' },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seaGmv
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 4) 价格趋势:按天平均价格
|
||||
const priceDays: string[] = []
|
||||
const avgPrices: number[] = []
|
||||
for (let i = 0; i < priceRows.length; i++) {
|
||||
const r = priceRows[i]
|
||||
const d = r.getString('day') ?? ''
|
||||
priceDays.push(d.length >= 10 ? d.substring(5, 10) : d)
|
||||
avgPrices.push(r.getNumber('avg_price') ?? 0)
|
||||
}
|
||||
|
||||
priceTrendOption.value = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: priceDays },
|
||||
yAxis: { type: 'value', name: '平均价格' },
|
||||
series: [
|
||||
{
|
||||
name: '平均价格',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: avgPrices
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 5) 竞争分析:商家 GMV 对比
|
||||
const merchantNames: string[] = []
|
||||
const merchantGmv: number[] = []
|
||||
for (let i = 0; i < compRows.length; i++) {
|
||||
const r = compRows[i]
|
||||
merchantNames.push(r.getString('merchant_name') ?? '未知商家')
|
||||
merchantGmv.push(r.getNumber('gmv') ?? 0)
|
||||
}
|
||||
|
||||
competitionOption.value = {
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { top: 'bottom' },
|
||||
series: [
|
||||
{
|
||||
name: '商家GMV',
|
||||
type: 'pie',
|
||||
radius: ['35%', '65%'],
|
||||
center: ['50%', '50%'],
|
||||
data: merchantNames.map((n, idx) => {
|
||||
return { name: n, value: merchantGmv[idx] }
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function handleMenu() {
|
||||
showSidebarMenu.value = true
|
||||
}
|
||||
|
||||
function handleSidebarUpdate(visible: boolean) {
|
||||
showSidebarMenu.value = visible
|
||||
}
|
||||
|
||||
function toggleMoreMenu() {
|
||||
showMoreMenu.value = !showMoreMenu.value
|
||||
}
|
||||
|
||||
function closeMoreMenu() {
|
||||
showMoreMenu.value = false
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
uni.showToast({ title: '搜索', icon: 'none' })
|
||||
}
|
||||
|
||||
function handleNotification() {
|
||||
uni.showToast({ title: '通知', icon: 'none' })
|
||||
}
|
||||
|
||||
function handleFullscreen() {
|
||||
uni.showToast({ title: '全屏', icon: 'none' })
|
||||
}
|
||||
|
||||
function handleMobile() {
|
||||
uni.showToast({ title: '移动端', icon: 'none' })
|
||||
}
|
||||
|
||||
function handleDropdown() {
|
||||
uni.showToast({ title: '下拉菜单', icon: 'none' })
|
||||
}
|
||||
|
||||
function handleSettings() {
|
||||
uni.showToast({ title: '设置', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -618,18 +625,6 @@ export default {
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
/* 响应式:窄屏时全屏显示 */
|
||||
@media screen and (max-width: 959px) {
|
||||
.page-layout {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media screen and (max-width: 960px) {
|
||||
.title,
|
||||
.subtitle {
|
||||
@@ -644,4 +639,15 @@ export default {
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式:窄屏时全屏显示 */
|
||||
@media screen and (max-width: 959px) {
|
||||
.page-layout {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user