20260506
This commit is contained in:
parent
d572493115
commit
06551ac2c7
@ -24,13 +24,12 @@ const DASHBOARD: AppRouteRecordRaw = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'monitor',
|
path: 'monitor',
|
||||||
alias: 'MonitoringPanel',
|
|
||||||
name: 'Monitor',
|
name: 'Monitor',
|
||||||
component: () => import('@/views/home/monitor/index.vue'),
|
component: () => import('@/views/home/monitor/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
locale: 'menu.home.monitor',
|
locale: 'menu.home.monitor',
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
roles: ['admin'],
|
permission: 'Home.Monitor',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -16,6 +16,8 @@ const routeNameMap: Record<string, string> = {
|
|||||||
// 首页相关
|
// 首页相关
|
||||||
'home_workplace': 'Workplace',
|
'home_workplace': 'Workplace',
|
||||||
'/home/workplace': 'Workplace',
|
'/home/workplace': 'Workplace',
|
||||||
|
'home_monitor': 'Monitor',
|
||||||
|
'/home/monitor': 'Monitor',
|
||||||
'home': 'Home',
|
'home': 'Home',
|
||||||
'/home': 'Home',
|
'/home': 'Home',
|
||||||
|
|
||||||
|
|||||||
@ -1,94 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="['chat-item', itemData.isCollect ? 'chat-item-collected' : '']">
|
|
||||||
<a-space :size="4" direction="vertical" fill>
|
|
||||||
<a-typography-text type="warning">
|
|
||||||
{{ itemData.username }}
|
|
||||||
</a-typography-text>
|
|
||||||
<a-typography-text>{{ itemData.content }}</a-typography-text>
|
|
||||||
<div class="chat-item-footer">
|
|
||||||
<div class="chat-item-time">
|
|
||||||
<a-typography-text type="secondary">
|
|
||||||
{{ itemData.time }}
|
|
||||||
</a-typography-text>
|
|
||||||
</div>
|
|
||||||
<div class="chat-item-actions">
|
|
||||||
<div class="chat-item-actions-item">
|
|
||||||
<icon-command />
|
|
||||||
</div>
|
|
||||||
<div class="chat-item-actions-item chat-item-actions-collect">
|
|
||||||
<icon-star />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { PropType } from 'vue';
|
|
||||||
import { ChatRecord } from '@/api/message';
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
itemData: {
|
|
||||||
type: Object as PropType<ChatRecord>,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.chat-item {
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 20px;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
&-footer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-actions {
|
|
||||||
display: flex;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-right: 4px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 14px;
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--gray-3));
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-collected {
|
|
||||||
.chat-item-actions-collect {
|
|
||||||
color: rgb(var(--gold-6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--gray-2));
|
|
||||||
|
|
||||||
.chat-item-actions {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="chat-list">
|
|
||||||
<ChatItem v-for="item in renderList" :key="item.id" :item-data="item" />
|
|
||||||
<a-result v-if="!renderList.length" status="404" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { PropType } from 'vue';
|
|
||||||
import { ChatRecord } from '@/api/message';
|
|
||||||
import ChatItem from './chat-item.vue';
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
renderList: {
|
|
||||||
type: Array as PropType<ChatRecord[]>,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.chat-item {
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 20px;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
&-footer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-actions {
|
|
||||||
display: flex;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-right: 4px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--gray-3));
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-collected {
|
|
||||||
.message-item-actions-collect {
|
|
||||||
color: rgb(var(--gold-6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--gray-2));
|
|
||||||
|
|
||||||
.message-item-actions {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card
|
|
||||||
class="general-card chat-panel"
|
|
||||||
:title="$t('monitor.title.chatPanel')"
|
|
||||||
:bordered="false"
|
|
||||||
:header-style="{ paddingBottom: '0' }"
|
|
||||||
:body-style="{
|
|
||||||
height: '100%',
|
|
||||||
paddingTop: '16px',
|
|
||||||
display: 'flex',
|
|
||||||
flexFlow: 'column',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-select style="width: 86px" default-value="all">
|
|
||||||
<a-option value="all">
|
|
||||||
{{ $t('monitor.chat.options.all') }}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-input-search
|
|
||||||
:placeholder="$t('monitor.chat.placeholder.searchCategory')"
|
|
||||||
/>
|
|
||||||
<a-button type="text">
|
|
||||||
<icon-download />
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
<div class="chat-panel-content">
|
|
||||||
<a-spin :loading="loading" style="width: 100%">
|
|
||||||
<ChatList :render-list="chatData" />
|
|
||||||
</a-spin>
|
|
||||||
</div>
|
|
||||||
<div class="chat-panel-footer">
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-Input>
|
|
||||||
<template #suffix>
|
|
||||||
<icon-face-smile-fill />
|
|
||||||
</template>
|
|
||||||
</a-Input>
|
|
||||||
<a-button type="primary">{{ $t('monitor.chat.update') }}</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { queryChatList, ChatRecord } from '@/api/message';
|
|
||||||
import useLoading from '@/hooks/loading';
|
|
||||||
import ChatList from './chat-list.vue';
|
|
||||||
|
|
||||||
const { loading, setLoading } = useLoading(true);
|
|
||||||
const chatData = ref<ChatRecord[]>([]);
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await queryChatList();
|
|
||||||
chatData.value = data;
|
|
||||||
} catch (err) {
|
|
||||||
// you can report use errorHandler or other
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.chat-panel {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
// padding: 20px;
|
|
||||||
background-color: var(--color-bg-2);
|
|
||||||
|
|
||||||
&-content {
|
|
||||||
flex: 1;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<a-table
|
|
||||||
:columns="columns"
|
|
||||||
:data="data"
|
|
||||||
row-key="id"
|
|
||||||
:row-selection="{
|
|
||||||
type: 'checkbox',
|
|
||||||
showCheckedAll: true,
|
|
||||||
}"
|
|
||||||
:border="false"
|
|
||||||
:pagination="false"
|
|
||||||
/>
|
|
||||||
<a-typography-text type="secondary" class="data-statistic-list-tip">
|
|
||||||
{{ $t('monitor.list.tip.rotations') }} {{ data.length }}
|
|
||||||
{{ $t('monitor.list.tip.rest') }}
|
|
||||||
</a-typography-text>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, h, compile } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import type {
|
|
||||||
TableColumnData,
|
|
||||||
TableData,
|
|
||||||
} from '@arco-design/web-vue/es/table/interface.d';
|
|
||||||
|
|
||||||
interface PreviewRecord {
|
|
||||||
cover: string;
|
|
||||||
name: string;
|
|
||||||
duration: string;
|
|
||||||
id: string;
|
|
||||||
status: number;
|
|
||||||
}
|
|
||||||
const { t } = useI18n();
|
|
||||||
const data: PreviewRecord[] = [
|
|
||||||
{
|
|
||||||
cover:
|
|
||||||
'http://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/c788fc704d32cf3b1136c7d45afc2669.png~tplv-uwbnlip3yd-webp.webp',
|
|
||||||
name: '视频直播',
|
|
||||||
duration: '00:05:19',
|
|
||||||
id: '54e23ade',
|
|
||||||
status: -1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const renderTag = (status: number) => {
|
|
||||||
if (status === -1) {
|
|
||||||
return `<a-tag color="red" class='data-statistic-list-cover-tag'>
|
|
||||||
${t('monitor.list.tag.auditFailed')}
|
|
||||||
</a-tag>`;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
// Using the Render function is more flexible than using templates.
|
|
||||||
// But, cannot bind context and local scopes are also lost
|
|
||||||
|
|
||||||
const columns = computed(() => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: t('monitor.list.title.order'),
|
|
||||||
render({
|
|
||||||
rowIndex,
|
|
||||||
}: {
|
|
||||||
record: TableData;
|
|
||||||
column: TableColumnData;
|
|
||||||
rowIndex: number;
|
|
||||||
}) {
|
|
||||||
const tmp = `<span>${rowIndex + 1}</span>`;
|
|
||||||
return h(compile(tmp));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('monitor.list.title.cover'),
|
|
||||||
render({
|
|
||||||
record,
|
|
||||||
}: {
|
|
||||||
record: TableData;
|
|
||||||
column: TableColumnData;
|
|
||||||
rowIndex: number;
|
|
||||||
}) {
|
|
||||||
const tmp = `<div class='data-statistic-list-cover-wrapper'>
|
|
||||||
<img src=${record.cover} />
|
|
||||||
${renderTag(record.status)}
|
|
||||||
</div>`;
|
|
||||||
return h(compile(tmp));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('monitor.list.title.name'),
|
|
||||||
dataIndex: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'duration',
|
|
||||||
title: t('monitor.list.title.duration'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'id',
|
|
||||||
title: t('monitor.list.title.id'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
// Warning: Here is the global style
|
|
||||||
.data-statistic {
|
|
||||||
&-list {
|
|
||||||
&-cover {
|
|
||||||
&-wrapper {
|
|
||||||
position: relative;
|
|
||||||
height: 68px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-tag {
|
|
||||||
position: absolute;
|
|
||||||
top: 6px;
|
|
||||||
left: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-tip {
|
|
||||||
display: block;
|
|
||||||
margin-top: 16px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card class="data-statistic" :bordered="false" :body-style="{ padding: '16px' }">
|
|
||||||
<a-tabs default-active-tab="liveMethod">
|
|
||||||
<a-tab-pane
|
|
||||||
key="liveMethod"
|
|
||||||
:title="$t('monitor.tab.title.liveMethod')"
|
|
||||||
/>
|
|
||||||
<a-tab-pane
|
|
||||||
key="onlinePopulation"
|
|
||||||
:title="$t('monitor.tab.title.onlinePopulation')"
|
|
||||||
/>
|
|
||||||
</a-tabs>
|
|
||||||
<div class="data-statistic__content">
|
|
||||||
<a-radio-group :default-value="3" type="button">
|
|
||||||
<a-radio :value="1">{{ $t('monitor.liveMethod.normal') }}</a-radio>
|
|
||||||
<a-radio :value="2">{{ $t('monitor.liveMethod.flowControl') }}</a-radio>
|
|
||||||
<a-radio :value="3">{{ $t('monitor.liveMethod.video') }}</a-radio>
|
|
||||||
<a-radio :value="4">{{ $t('monitor.liveMethod.web') }}</a-radio>
|
|
||||||
</a-radio-group>
|
|
||||||
|
|
||||||
<div class="data-statistic__list">
|
|
||||||
<div class="table-toolbar data-statistic__toolbar">
|
|
||||||
<div class="toolbar-left" />
|
|
||||||
<div class="toolbar-right">
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-button type="text">{{ $t('monitor.editCarousel') }}</a-button>
|
|
||||||
<a-button disabled>{{ $t('monitor.startCarousel') }}</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="data-statistic__list-body">
|
|
||||||
<DataStatisticList />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import DataStatisticList from './data-statistic-list.vue';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
/* 工具栏与 docs/前端页面设计规范 table-toolbar 一致;列表操作靠右上角 */
|
|
||||||
.data-statistic {
|
|
||||||
&__content {
|
|
||||||
padding: 16px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__list {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 0 0 16px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__toolbar .toolbar-right {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__list-body {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card class="general-card" :title="$t('monitor.title.quickOperation')">
|
|
||||||
<a-space direction="vertical" fill :size="10">
|
|
||||||
<a-button long>
|
|
||||||
{{ $t('monitor.quickOperation.changeClarity') }}
|
|
||||||
<template #icon>
|
|
||||||
<IconTags />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button long>
|
|
||||||
{{ $t('monitor.quickOperation.switchStream') }}
|
|
||||||
<template #icon>
|
|
||||||
<IconSwap />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button long>
|
|
||||||
{{ $t('monitor.quickOperation.removeClarity') }}
|
|
||||||
<template #icon>
|
|
||||||
<IconStop />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button long>
|
|
||||||
{{ $t('monitor.quickOperation.pushFlowGasket') }}
|
|
||||||
<template #icon>
|
|
||||||
<IconArrowRight />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup></script>
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card class="general-card" :title="$t('monitor.title.studioInfo')">
|
|
||||||
<a-form :model="{}" layout="vertical">
|
|
||||||
<a-form-item :label="$t('monitor.studioInfo.label.studioTitle')" required>
|
|
||||||
<a-input
|
|
||||||
:placeholder="`admin${$t(
|
|
||||||
'monitor.studioInfo.placeholder.studioTitle'
|
|
||||||
)}`"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
:label="$t('monitor.studioInfo.label.onlineNotification')"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<a-textarea />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
:label="$t('monitor.studioInfo.label.studioCategory')"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<a-input-search />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
:label="$t('monitor.studioInfo.label.studioCategory')"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<a-input-search />
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
<a-button type="primary">{{ $t('monitor.studioInfo.btn.fresh') }}</a-button>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup></script>
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card
|
|
||||||
class="general-card"
|
|
||||||
:title="$t('monitor.studioStatus.title.studioStatus')"
|
|
||||||
>
|
|
||||||
<template #extra>
|
|
||||||
<a-tag color="green">{{ $t('monitor.studioStatus.smooth') }}</a-tag>
|
|
||||||
</template>
|
|
||||||
<a-descriptions layout="horizontal" :data="dataStatus" :column="2">
|
|
||||||
<template #label="{ label }">
|
|
||||||
<span
|
|
||||||
v-if="['mainstream', 'hotStandby', 'coldStandby'].includes(label)"
|
|
||||||
>
|
|
||||||
<a-typography-text style="padding-right: 8px">
|
|
||||||
{{ $t(`monitor.studioStatus.${label}`) }}
|
|
||||||
</a-typography-text>
|
|
||||||
{{ $t('monitor.studioStatus.bitRate') }}
|
|
||||||
</span>
|
|
||||||
<span v-else>{{ label }}</span>
|
|
||||||
</template>
|
|
||||||
</a-descriptions>
|
|
||||||
<a-typography-title style="margin-bottom: 16px" :heading="6">
|
|
||||||
{{ $t('monitor.studioStatus.title.pictureInfo') }}
|
|
||||||
</a-typography-title>
|
|
||||||
<a-descriptions layout="horizontal" :data="dataPicture" :column="2" />
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const dataStatus = computed(() => [
|
|
||||||
{
|
|
||||||
label: 'mainstream',
|
|
||||||
value: '6 Mbps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.frameRate'),
|
|
||||||
value: '60',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'hotStandby',
|
|
||||||
value: '6 Mbps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.frameRate'),
|
|
||||||
value: '60',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'coldStandby',
|
|
||||||
value: '6 Mbps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.frameRate'),
|
|
||||||
value: '60',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const dataPicture = computed(() => [
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.line'),
|
|
||||||
value: '热备',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'CDN',
|
|
||||||
value: 'KS',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.play'),
|
|
||||||
value: 'FLV',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('monitor.studioStatus.pictureQuality'),
|
|
||||||
value: '原画',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
:deep(.arco-descriptions-item-label) {
|
|
||||||
padding-right: 6px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card class="general-card" :title="$t('monitor.title.studioPreview')">
|
|
||||||
<template #extra>
|
|
||||||
<icon-more />
|
|
||||||
</template>
|
|
||||||
<div class="studio-wrapper">
|
|
||||||
<img
|
|
||||||
src="http://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/c788fc704d32cf3b1136c7d45afc2669.png~tplv-uwbnlip3yd-webp.webp"
|
|
||||||
class="studio-preview"
|
|
||||||
/>
|
|
||||||
<div class="studio-bar">
|
|
||||||
<div v-if="userInfo">
|
|
||||||
<a-space :size="12">
|
|
||||||
<a-avatar :size="24">
|
|
||||||
<img :src="userInfo.avatar" />
|
|
||||||
</a-avatar>
|
|
||||||
<a-typography-text>
|
|
||||||
{{ userInfo.name }} {{ $t('monitor.studioPreview.studio') }}
|
|
||||||
</a-typography-text>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
<a-typography-text type="secondary">
|
|
||||||
36,000 {{ $t('monitor.studioPreview.watching') }}
|
|
||||||
</a-typography-text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { useUserStore } from '@/store';
|
|
||||||
|
|
||||||
const userInfo = useUserStore();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.studio {
|
|
||||||
&-preview {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-bar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,63 @@
|
|||||||
export default {
|
export default {
|
||||||
'menu.home.monitor': 'Real-time Monitor',
|
'menu.home.monitor': 'Real-time Monitor',
|
||||||
'monitor.title.chatPanel': 'Chat Window',
|
'monitor.logistics.pageTitle': 'Real-time monitoring center',
|
||||||
'monitor.title.quickOperation': 'Quick Operation',
|
'monitor.logistics.stat.todayOrders': 'Forecast orders today',
|
||||||
'monitor.title.studioInfo': 'Studio Information',
|
'monitor.logistics.stat.historicalOrders': 'All-time orders',
|
||||||
'monitor.title.studioPreview': 'Studio Preview',
|
'monitor.logistics.stat.pendingPayment': 'Pending payment',
|
||||||
'monitor.chat.options.all': 'All',
|
'monitor.logistics.stat.pendingOnline': 'Pending carrier scan',
|
||||||
'monitor.chat.placeholder.searchCategory': 'Search Category',
|
'monitor.logistics.stat.pendingSign': 'Pending delivery',
|
||||||
'monitor.chat.update': 'Update',
|
'monitor.logistics.stat.orderExceptions': 'Order exceptions',
|
||||||
'monitor.list.title.order': 'Order',
|
'monitor.logistics.stat.todayRevenue': 'Revenue today',
|
||||||
'monitor.list.title.cover': 'Cover',
|
'monitor.logistics.stat.totalCustomers': 'Total customers',
|
||||||
'monitor.list.title.name': 'Name',
|
'monitor.logistics.stat.newCustomers': 'New customers',
|
||||||
'monitor.list.title.duration': 'Duration',
|
'monitor.logistics.stat.onlineCustomers': 'Online customers',
|
||||||
'monitor.list.title.id': 'ID',
|
'monitor.logistics.stat.inactiveLogin7d': 'No login 7+ days',
|
||||||
'monitor.list.tip.rotations': 'Rotations ',
|
'monitor.logistics.vsYesterday': 'vs yesterday',
|
||||||
'monitor.list.tip.rest': ', The program list is not visible to viewers',
|
'monitor.logistics.vsLastMonth': 'vs last month',
|
||||||
'monitor.list.tag.auditFailed': 'Audit Failed',
|
'monitor.logistics.hint.newCustomersToday': 'New sign-ups today',
|
||||||
'monitor.tab.title.liveMethod': 'Live Method',
|
'monitor.logistics.hint.onlineRealtime': 'Active sessions (live)',
|
||||||
'monitor.tab.title.onlinePopulation': 'Online Population',
|
'monitor.logistics.hint.inactiveLogin7d': 'Customers with no login in 7+ days',
|
||||||
'monitor.liveMethod.normal': 'Normal Live',
|
'monitor.logistics.hint.inactiveLogin7dCompare': '+5 vs last week',
|
||||||
'monitor.liveMethod.flowControl': 'Flow Control Live',
|
'monitor.logistics.chart.orders7d': 'Order volume (last 7 days)',
|
||||||
'monitor.liveMethod.video': 'Video Live',
|
'monitor.logistics.chart.revenueGross7d': 'Revenue & gross profit (last 7 days)',
|
||||||
'monitor.liveMethod.web': 'Web Live',
|
'monitor.logistics.chart.customerTrendsSection': 'By lane · week / month trends',
|
||||||
'monitor.editCarousel': 'Edit',
|
'monitor.logistics.chart.customerOrdersByLine': 'Order volume trend',
|
||||||
'monitor.startCarousel': 'Start',
|
'monitor.logistics.chart.customerReceivableByLine': 'Accounts receivable trend',
|
||||||
'monitor.quickOperation.changeClarity': 'Change the Clarity',
|
'monitor.logistics.axis.weekIndex': 'W{n}',
|
||||||
'monitor.quickOperation.switchStream': 'Switch Stream',
|
'monitor.logistics.axis.monthIndex': 'M{n}',
|
||||||
'monitor.quickOperation.removeClarity': 'Remove the Clarity',
|
'monitor.logistics.chart.signRateByLine': 'On-time sign-off rate by lane',
|
||||||
'monitor.quickOperation.pushFlowGasket': 'Push Flow Gasket',
|
'monitor.logistics.axis.complianceRate': 'Compliance rate',
|
||||||
'monitor.studioInfo.label.studioTitle': 'Studio Title',
|
'monitor.logistics.series.signRate': 'Sign-off compliance',
|
||||||
'monitor.studioInfo.label.onlineNotification': 'Online Notification',
|
'monitor.logistics.filter.line': 'Lane',
|
||||||
'monitor.studioInfo.label.studioCategory': 'Studio Category',
|
'monitor.logistics.filter.signDays': 'Sign-off days',
|
||||||
'monitor.studioInfo.placeholder.studioTitle': "'s Studio",
|
'monitor.logistics.filter.allLines': 'All lanes',
|
||||||
'monitor.studioInfo.btn.fresh': 'Fresh',
|
'monitor.logistics.filter.signDaysOption': '{n} days',
|
||||||
'monitor.studioStatus.title.studioStatus': 'Studio Status',
|
'monitor.logistics.line.us': 'US lane',
|
||||||
'monitor.studioStatus.title.pictureInfo': 'Picture Information',
|
'monitor.logistics.line.eu': 'EU lane',
|
||||||
'monitor.studioStatus.smooth': 'Smooth',
|
'monitor.logistics.line.sea': 'SEA lane',
|
||||||
'monitor.studioStatus.frameRate': 'Frame',
|
'monitor.logistics.line.au': 'AU lane',
|
||||||
'monitor.studioStatus.bitRate': 'Bit',
|
'monitor.logistics.line.jp': 'JP lane',
|
||||||
'monitor.studioStatus.mainstream': 'Main',
|
'monitor.logistics.line.uk': 'UK lane',
|
||||||
'monitor.studioStatus.hotStandby': 'Hot',
|
'monitor.logistics.series.orders': 'Orders',
|
||||||
'monitor.studioStatus.coldStandby': 'Cold',
|
'monitor.logistics.series.revenue': 'Revenue',
|
||||||
'monitor.studioStatus.line': 'Line',
|
'monitor.logistics.series.grossProfit': 'Gross profit',
|
||||||
'monitor.studioStatus.play': 'Format',
|
'monitor.logistics.axis.d1': 'Day 1',
|
||||||
'monitor.studioStatus.pictureQuality': 'Quality',
|
'monitor.logistics.axis.d2': 'Day 2',
|
||||||
'monitor.studioPreview.studio': 'Studio',
|
'monitor.logistics.axis.d3': 'Day 3',
|
||||||
'monitor.studioPreview.watching': 'watching',
|
'monitor.logistics.axis.d4': 'Day 4',
|
||||||
|
'monitor.logistics.axis.d5': 'Day 5',
|
||||||
|
'monitor.logistics.axis.d6': 'Day 6',
|
||||||
|
'monitor.logistics.axis.today': 'Today',
|
||||||
|
'monitor.logistics.filter.statPeriod': 'Period',
|
||||||
|
'monitor.logistics.filter.periodWeek': 'Week',
|
||||||
|
'monitor.logistics.filter.periodMonth': 'Month',
|
||||||
|
'monitor.logistics.pie.sectionTitle': 'Track & OTD (by lane / period)',
|
||||||
|
'monitor.logistics.pie.trackComplete': 'Track completeness',
|
||||||
|
'monitor.logistics.pie.trackTimely': 'Track timeliness',
|
||||||
|
'monitor.logistics.pie.otd': 'OTD compliance',
|
||||||
|
'monitor.logistics.pie.pass': 'Met',
|
||||||
|
'monitor.logistics.pie.fail': 'Not met',
|
||||||
|
'monitor.logistics.tab.customer': 'Customers',
|
||||||
|
'monitor.logistics.tab.order': 'Orders',
|
||||||
|
'monitor.logistics.tab.track': 'Tracking',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,48 +1,63 @@
|
|||||||
export default {
|
export default {
|
||||||
'menu.home.monitor': '实时监控',
|
'menu.home.monitor': '实时监控',
|
||||||
'monitor.title.chatPanel': '聊天窗口',
|
'monitor.logistics.pageTitle': '实时监控中心',
|
||||||
'monitor.title.quickOperation': '快捷操作',
|
'monitor.logistics.stat.todayOrders': '今日预报订单',
|
||||||
'monitor.title.studioInfo': '直播信息',
|
'monitor.logistics.stat.historicalOrders': '历史总订单',
|
||||||
'monitor.title.studioPreview': '直播预览',
|
'monitor.logistics.stat.pendingPayment': '待支付订单',
|
||||||
'monitor.chat.options.all': '全部',
|
'monitor.logistics.stat.pendingOnline': '待上网订单',
|
||||||
'monitor.chat.placeholder.searchCategory': '搜索类目',
|
'monitor.logistics.stat.pendingSign': '待签收订单',
|
||||||
'monitor.chat.update': '更新',
|
'monitor.logistics.stat.orderExceptions': '订单异常',
|
||||||
'monitor.list.title.order': '序号',
|
'monitor.logistics.stat.todayRevenue': '今日总营收',
|
||||||
'monitor.list.title.cover': '封面',
|
'monitor.logistics.stat.totalCustomers': '客户总数',
|
||||||
'monitor.list.title.name': '名称',
|
'monitor.logistics.stat.newCustomers': '新增客户数',
|
||||||
'monitor.list.title.duration': '视频时长',
|
'monitor.logistics.stat.onlineCustomers': '在线客户数',
|
||||||
'monitor.list.title.id': '视频Id',
|
'monitor.logistics.stat.inactiveLogin7d': '超7天未登录',
|
||||||
'monitor.list.tip.rotations': '轮播次数',
|
'monitor.logistics.vsYesterday': '较昨日',
|
||||||
'monitor.list.tip.rest': ',节目单观众不可见',
|
'monitor.logistics.vsLastMonth': '较上月',
|
||||||
'monitor.list.tag.auditFailed': '审核未通过',
|
'monitor.logistics.hint.newCustomersToday': '统计口径:今日新注册',
|
||||||
'monitor.tab.title.liveMethod': '直播方式',
|
'monitor.logistics.hint.onlineRealtime': '当前在线会话数(实时)',
|
||||||
'monitor.tab.title.onlinePopulation': '在线人数',
|
'monitor.logistics.hint.inactiveLogin7d': '超7天未产生登录行为的客户',
|
||||||
'monitor.liveMethod.normal': '普通直播',
|
'monitor.logistics.hint.inactiveLogin7dCompare': '较上周 +5 人',
|
||||||
'monitor.liveMethod.flowControl': '控流直播',
|
'monitor.logistics.chart.orders7d': '近7日订单数趋势',
|
||||||
'monitor.liveMethod.video': '视频直播',
|
'monitor.logistics.chart.revenueGross7d': '近7日营收 & 毛利趋势',
|
||||||
'monitor.liveMethod.web': '网页开播',
|
'monitor.logistics.chart.customerTrendsSection': '按线路 · 周/月趋势',
|
||||||
'monitor.editCarousel': '编辑轮播',
|
'monitor.logistics.chart.customerOrdersByLine': '单量趋势',
|
||||||
'monitor.startCarousel': '开始轮播',
|
'monitor.logistics.chart.customerReceivableByLine': '应收趋势',
|
||||||
'monitor.quickOperation.changeClarity': '切换清晰度',
|
'monitor.logistics.axis.weekIndex': '第{n}周',
|
||||||
'monitor.quickOperation.switchStream': '主备流切换',
|
'monitor.logistics.axis.monthIndex': '{n}月',
|
||||||
'monitor.quickOperation.removeClarity': '摘除清晰度',
|
'monitor.logistics.chart.signRateByLine': '各线路签收达标率',
|
||||||
'monitor.quickOperation.pushFlowGasket': '推流垫片',
|
'monitor.logistics.axis.complianceRate': '达标率',
|
||||||
'monitor.studioInfo.label.studioTitle': '直播标题',
|
'monitor.logistics.series.signRate': '签收达标率',
|
||||||
'monitor.studioInfo.label.onlineNotification': '上线通知',
|
'monitor.logistics.filter.line': '线路',
|
||||||
'monitor.studioInfo.label.studioCategory': '直播类目',
|
'monitor.logistics.filter.signDays': '签收天数',
|
||||||
'monitor.studioInfo.placeholder.studioTitle': '的直播间',
|
'monitor.logistics.filter.allLines': '全部线路',
|
||||||
'monitor.studioInfo.btn.fresh': '更新',
|
'monitor.logistics.filter.signDaysOption': '{n} 天',
|
||||||
'monitor.studioStatus.title.studioStatus': '直播状态',
|
'monitor.logistics.line.us': '美线',
|
||||||
'monitor.studioStatus.title.pictureInfo': '画面信息',
|
'monitor.logistics.line.eu': '欧线',
|
||||||
'monitor.studioStatus.smooth': '流畅',
|
'monitor.logistics.line.sea': '东南亚线',
|
||||||
'monitor.studioStatus.frameRate': '帧率',
|
'monitor.logistics.line.au': '澳线',
|
||||||
'monitor.studioStatus.bitRate': '码率',
|
'monitor.logistics.line.jp': '日本线',
|
||||||
'monitor.studioStatus.mainstream': '主流',
|
'monitor.logistics.line.uk': '英国线',
|
||||||
'monitor.studioStatus.hotStandby': '热备',
|
'monitor.logistics.series.orders': '订单数',
|
||||||
'monitor.studioStatus.coldStandby': '冷备',
|
'monitor.logistics.series.revenue': '营收',
|
||||||
'monitor.studioStatus.line': '线路',
|
'monitor.logistics.series.grossProfit': '毛利',
|
||||||
'monitor.studioStatus.play': '播放格式',
|
'monitor.logistics.axis.d1': '1日',
|
||||||
'monitor.studioStatus.pictureQuality': '画质',
|
'monitor.logistics.axis.d2': '2日',
|
||||||
'monitor.studioPreview.studio': '直播间',
|
'monitor.logistics.axis.d3': '3日',
|
||||||
'monitor.studioPreview.watching': '在看',
|
'monitor.logistics.axis.d4': '4日',
|
||||||
|
'monitor.logistics.axis.d5': '5日',
|
||||||
|
'monitor.logistics.axis.d6': '6日',
|
||||||
|
'monitor.logistics.axis.today': '今日',
|
||||||
|
'monitor.logistics.filter.statPeriod': '统计周期',
|
||||||
|
'monitor.logistics.filter.periodWeek': '周',
|
||||||
|
'monitor.logistics.filter.periodMonth': '月',
|
||||||
|
'monitor.logistics.pie.sectionTitle': '轨迹与 OTD 达成(按线路 / 周期)',
|
||||||
|
'monitor.logistics.pie.trackComplete': '轨迹完整率',
|
||||||
|
'monitor.logistics.pie.trackTimely': '轨迹及时率',
|
||||||
|
'monitor.logistics.pie.otd': 'OTD 达标率',
|
||||||
|
'monitor.logistics.pie.pass': '达标',
|
||||||
|
'monitor.logistics.pie.fail': '未达标',
|
||||||
|
'monitor.logistics.tab.customer': '客户',
|
||||||
|
'monitor.logistics.tab.order': '订单',
|
||||||
|
'monitor.logistics.tab.track': '轨迹',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,26 +1,7 @@
|
|||||||
import Mock from 'mockjs';
|
import setupMock from '@/utils/setup-mock';
|
||||||
|
|
||||||
import setupMock, {
|
|
||||||
successResponseWrap,
|
|
||||||
// failResponseWrap,
|
|
||||||
} from '@/utils/setup-mock';
|
|
||||||
|
|
||||||
setupMock({
|
setupMock({
|
||||||
setup() {
|
setup() {
|
||||||
Mock.mock(new RegExp('/api/chat/list'), () => {
|
/* 物流监控页暂无独立 Mock 接口 */
|
||||||
// return failResponseWrap(null, '重新登陆', 50008);
|
|
||||||
const data = Mock.mock({
|
|
||||||
'data|4-6': [
|
|
||||||
{
|
|
||||||
'id|+1': 1,
|
|
||||||
'username': '用户7352772',
|
|
||||||
'content': '马上就开始了,好激动!',
|
|
||||||
'time': '13:09:12',
|
|
||||||
'isCollect|2': true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
return successResponseWrap(data.data);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -101,7 +101,6 @@
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-fill-1);
|
background-color: var(--color-fill-1);
|
||||||
|
|||||||
@ -12,8 +12,6 @@
|
|||||||
:title="$t('workplace.onlineContent')"
|
:title="$t('workplace.onlineContent')"
|
||||||
:value="373.5"
|
:value="373.5"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
show-group-separator
|
show-group-separator
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -33,8 +31,6 @@
|
|||||||
<a-statistic
|
<a-statistic
|
||||||
:title="$t('workplace.putIn')"
|
:title="$t('workplace.putIn')"
|
||||||
:value="368"
|
:value="368"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
show-group-separator
|
show-group-separator
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -54,8 +50,6 @@
|
|||||||
<a-statistic
|
<a-statistic
|
||||||
:title="$t('workplace.newDay')"
|
:title="$t('workplace.newDay')"
|
||||||
:value="8874"
|
:value="8874"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
show-group-separator
|
show-group-separator
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -75,8 +69,6 @@
|
|||||||
<a-statistic
|
<a-statistic
|
||||||
:title="$t('workplace.pendingOnline')"
|
:title="$t('workplace.pendingOnline')"
|
||||||
:value="156"
|
:value="156"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
show-group-separator
|
show-group-separator
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -96,8 +88,6 @@
|
|||||||
<a-statistic
|
<a-statistic
|
||||||
:title="$t('workplace.problematic')"
|
:title="$t('workplace.problematic')"
|
||||||
:value="12"
|
:value="12"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
show-group-separator
|
show-group-separator
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -118,8 +108,6 @@
|
|||||||
:title="$t('workplace.newFromYesterday')"
|
:title="$t('workplace.newFromYesterday')"
|
||||||
:value="2.8"
|
:value="2.8"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
:value-from="0"
|
|
||||||
animation
|
|
||||||
>
|
>
|
||||||
<template #suffix> % <icon-caret-up class="up-icon" /> </template>
|
<template #suffix> % <icon-caret-up class="up-icon" /> </template>
|
||||||
</a-statistic>
|
</a-statistic>
|
||||||
|
|||||||
@ -48,7 +48,6 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
perspective: 1200px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@ -121,14 +120,7 @@
|
|||||||
background-color: var(--color-bg-2);
|
background-color: var(--color-bg-2);
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transform-style: preserve-3d;
|
|
||||||
transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 0.4s ease;
|
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: translateY(-8px) translateZ(20px) rotateX(2deg);
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.panel-border) {
|
:deep(.panel-border) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="waybill-container">
|
<div class="waybill-container">
|
||||||
|
<div class="waybill-layout">
|
||||||
<!-- 表单区域 -->
|
<!-- 表单区域 -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<a-form :model="formData" layout="vertical" class="waybill-form">
|
<a-form :model="formData" layout="vertical" class="waybill-form">
|
||||||
@ -128,6 +129,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -289,12 +291,21 @@ onMounted(() => {
|
|||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waybill-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 16px;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -333,9 +344,13 @@ onMounted(() => {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex-shrink: 0;
|
flex: 3 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waybill-form {
|
.waybill-form {
|
||||||
@ -348,7 +363,8 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.large-input {
|
.large-input {
|
||||||
width: 50%;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
@ -377,11 +393,11 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline-field {
|
.inline-field {
|
||||||
flex: 1;
|
flex: 1 1 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
.inline-label {
|
.inline-label {
|
||||||
@ -435,7 +451,8 @@ onMounted(() => {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex: 1;
|
flex: 7 1 0;
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -490,5 +507,24 @@ onMounted(() => {
|
|||||||
touch-action: pan-x pan-y;
|
touch-action: pan-x pan-y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.waybill-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-width: none;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-orders-section {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 360px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="waybill-container">
|
<div class="waybill-container">
|
||||||
|
<div class="waybill-layout">
|
||||||
<!-- 表单区域 -->
|
<!-- 表单区域 -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<a-form :model="formData" layout="vertical" class="waybill-form">
|
<a-form :model="formData" layout="vertical" class="waybill-form">
|
||||||
@ -57,6 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -164,12 +166,21 @@ onMounted(() => {
|
|||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waybill-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 16px;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -208,9 +219,13 @@ onMounted(() => {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex-shrink: 0;
|
flex: 3 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waybill-form {
|
.waybill-form {
|
||||||
@ -223,7 +238,8 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.large-input {
|
.large-input {
|
||||||
width: 50%;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
@ -248,7 +264,8 @@ onMounted(() => {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex: 1;
|
flex: 7 1 0;
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -303,5 +320,24 @@ onMounted(() => {
|
|||||||
touch-action: pan-x pan-y;
|
touch-action: pan-x pan-y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.waybill-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-width: none;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-orders-section {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 360px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="waybill-container">
|
<div class="waybill-container">
|
||||||
|
<div class="waybill-layout">
|
||||||
<!-- 表单区域 -->
|
<!-- 表单区域 -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<a-form :model="formData" layout="vertical" class="waybill-form">
|
<a-form :model="formData" layout="vertical" class="waybill-form">
|
||||||
<!-- 单号输入、单号类型、标签模板 同一行 -->
|
<!-- 单号一行;单号类型、标签模板下拉同一行 -->
|
||||||
<a-form-item :label="$t('operation.printLabel.form.scanNumber')" class="form-item-inline">
|
<a-form-item :label="$t('operation.printLabel.form.scanNumber')" class="form-item-scan">
|
||||||
<div class="form-row-inline">
|
|
||||||
<a-input
|
<a-input
|
||||||
v-model="formData.waybillNumber"
|
v-model="formData.waybillNumber"
|
||||||
:placeholder="$t('operation.printLabel.form.placeholder.scanOrInput')"
|
:placeholder="$t('operation.printLabel.form.placeholder.scanOrInput')"
|
||||||
size="large"
|
size="large"
|
||||||
class="large-input"
|
class="scan-input"
|
||||||
@press-enter="handleScan"
|
@press-enter="handleScan"
|
||||||
/>
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item class="form-item-selects" hide-label>
|
||||||
|
<div class="form-row-selects">
|
||||||
<a-select
|
<a-select
|
||||||
v-model="formData.numberType"
|
v-model="formData.numberType"
|
||||||
:placeholder="$t('operation.printLabel.form.placeholder.numberType')"
|
:placeholder="$t('operation.printLabel.form.placeholder.numberType')"
|
||||||
@ -104,6 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -273,12 +277,21 @@ function handleReset() {
|
|||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waybill-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 16px;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -317,13 +330,17 @@ function handleReset() {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex-shrink: 0;
|
flex: 3 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waybill-form {
|
.waybill-form {
|
||||||
.form-item-inline {
|
.form-item-scan {
|
||||||
:deep(.arco-form-item-label) {
|
:deep(.arco-form-item-label) {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -331,24 +348,34 @@ function handleReset() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-row-inline {
|
.form-item-selects {
|
||||||
display: flex;
|
margin-bottom: 0;
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
:deep(.arco-form-item-wrapper) {
|
||||||
flex-wrap: nowrap;
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.large-input {
|
.scan-input {
|
||||||
width: 1000px;
|
width: 100%;
|
||||||
min-width: 1000px;
|
min-width: 0;
|
||||||
height: 60px;
|
height: 48px;
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row-selects {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-number-type,
|
.select-number-type,
|
||||||
.select-label-template {
|
.select-label-template {
|
||||||
width: 300px;
|
flex: 1 1 0;
|
||||||
min-width: 300px;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-actions {
|
.form-actions {
|
||||||
@ -371,7 +398,8 @@ function handleReset() {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
flex: 1;
|
flex: 7 1 0;
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -426,4 +454,23 @@ function handleReset() {
|
|||||||
touch-action: pan-x pan-y;
|
touch-action: pan-x pan-y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.waybill-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-width: none;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-orders-section {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 360px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="profile-center">
|
<div class="profile-center">
|
||||||
<!-- 顶部个人信息卡片 - 3D 悬浮 -->
|
<!-- 顶部个人信息卡片 -->
|
||||||
<div class="profile-hero-card card-3d">
|
<div class="profile-hero-card">
|
||||||
<div class="hero-bg" />
|
<div class="hero-bg" />
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<div class="avatar-wrap">
|
<div class="avatar-wrap">
|
||||||
@ -39,9 +39,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 账户概览卡片组 - 3D 悬浮 -->
|
<!-- 账户概览卡片组 -->
|
||||||
<div class="cards-row">
|
<div class="cards-row">
|
||||||
<div class="stat-card card-3d stat-balance">
|
<div class="stat-card stat-balance">
|
||||||
<div class="stat-icon">
|
<div class="stat-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
|
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<span class="stat-value">¥{{ formatNumber(profile.accountBalance) }}</span>
|
<span class="stat-value">¥{{ formatNumber(profile.accountBalance) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card card-3d stat-quota">
|
<div class="stat-card stat-quota">
|
||||||
<div class="stat-icon">
|
<div class="stat-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||||
@ -63,7 +63,7 @@
|
|||||||
<span class="stat-value">{{ formatNumber(profile.totalQuota) }}</span>
|
<span class="stat-value">{{ formatNumber(profile.totalQuota) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card card-3d stat-used">
|
<div class="stat-card stat-used">
|
||||||
<div class="stat-icon">
|
<div class="stat-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M9 19v-6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2zm0 0V9a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v10m-6 0a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2m0 0V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2z" />
|
<path d="M9 19v-6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2zm0 0V9a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v10m-6 0a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2m0 0V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2z" />
|
||||||
@ -76,9 +76,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 联系信息 + 快捷操作 - 3D 悬浮 -->
|
<!-- 联系信息 + 快捷操作 -->
|
||||||
<div class="cards-grid">
|
<div class="cards-grid">
|
||||||
<div class="info-card card-3d">
|
<div class="info-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">{{ t('profile.contactInfo') }}</h3>
|
<h3 class="card-title">{{ t('profile.contactInfo') }}</h3>
|
||||||
</div>
|
</div>
|
||||||
@ -106,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-card quick-actions-card card-3d">
|
<div class="info-card quick-actions-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">{{ t('profile.quickActions') }}</h3>
|
<h3 class="card-title">{{ t('profile.quickActions') }}</h3>
|
||||||
</div>
|
</div>
|
||||||
@ -361,19 +361,6 @@ onMounted(() => {
|
|||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: 32px 24px 48px;
|
padding: 32px 24px 48px;
|
||||||
background: #f7f8fa;
|
background: #f7f8fa;
|
||||||
perspective: 1200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3D 悬浮卡片通用样式
|
|
||||||
.card-3d {
|
|
||||||
transform-style: preserve-3d;
|
|
||||||
transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 0.4s ease;
|
|
||||||
will-change: transform;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: translateY(-8px) translateZ(20px) rotateX(2deg);
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 顶部个人信息卡片
|
// 顶部个人信息卡片
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user