feat: 完善工作台界面

This commit is contained in:
liulujian 2026-04-06 00:16:20 +08:00
parent f238c23e19
commit d85aadcf9a
4 changed files with 506 additions and 187 deletions

View File

@ -0,0 +1,246 @@
<template>
<div class="enterprise-cert">
<div class="cert-header">
<div class="cert-icon">
<t-icon name="user" />
</div>
<div class="cert-title">
<h3>企业认证</h3>
<span class="cert-status" :class="statusClass">{{ statusText }}</span>
</div>
</div>
<div class="cert-body">
<template v-if="certData.qymc">
<div class="cert-info">
<div class="info-row">
<span class="info-label">企业名称</span>
<span class="info-value">{{ certData.qymc }}</span>
</div>
<div class="info-row">
<span class="info-label">统一社会信用代码</span>
<span class="info-value">{{ certData.nsrsbh }}</span>
</div>
<div class="info-row">
<span class="info-label">认证时间</span>
<span class="info-value">{{ formatDate(certData.lrrq) }}</span>
</div>
</div>
</template>
<template v-else>
<div class="cert-empty">
<span>暂未认证企业信息</span>
</div>
</template>
<div class="cert-actions">
<button class="cert-btn" @click="handleClick">
<span>{{ certData.qymc ? '查看详情' : '立即认证' }}</span>
<t-icon name="arrow-right" />
</button>
</div>
</div>
</div>
</template>
<script>
import api from '@/pages/index/api/gxzx/index.js';
export default {
name: 'EnterpriseCert',
data() {
return {
certData: {},
};
},
computed: {
statusText() {
if (!this.certData.qymc) return '未认证';
return '已认证';
},
statusClass() {
if (!this.certData.qymc) return 'status--unreviewed';
return 'status--certified';
},
},
mounted() {
this.fetchCertData();
},
methods: {
async fetchCertData() {
try {
const { data } = await api.init();
this.certData = data || {};
} catch (error) {
console.error('获取企业认证信息失败', error);
this.certData = {};
}
},
formatDate(dateStr) {
if (!dateStr) return '-';
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
handleClick() {
this.$router.push('/yhzx/qyrenzheng');
},
},
};
</script>
<style lang="less" scoped>
@green-primary: #48C666;
@green-dark: #2D8A45;
@green-light: #E8FFEA;
@text-dark: #1A2B3C;
@text-muted: #6B7C8D;
@text-light: #94A3B8;
@bg-card: #FFFFFF;
@border-light: rgba(0, 0, 0, 0.06);
@shadow-hover: 0 4px 16px rgba(0, 0, 0, 0.1);
.enterprise-cert {
width: 100%;
overflow: hidden;
background: @bg-card;
border: 1px solid @border-light;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: @shadow-hover;
}
}
.cert-header {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 20px;
background: linear-gradient(180deg, #FAFFFE 0%, @bg-card 100%);
border-bottom: 1px solid @border-light;
.cert-icon {
display: flex;
width: 40px;
height: 40px;
font-size: 20px;
color: #fff;
background: linear-gradient(135deg, @green-primary 0%, @green-dark 100%);
border-radius: 10px;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.cert-title {
flex: 1;
display: flex;
align-items: center;
gap: 10px;
h3 {
margin: 0;
font-size: 15px;
font-weight: 600;
color: @text-dark;
}
.cert-status {
padding: 3px 10px;
font-size: 11px;
font-weight: 600;
border-radius: 20px;
&.status--certified {
color: @green-dark;
background: @green-light;
}
&.status--pending {
color: #F9A825;
background: #FFF8E1;
}
&.status--unreviewed {
color: @text-muted;
background: #F5F5F5;
}
}
}
}
.cert-body {
padding: 16px 20px;
}
.cert-info {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 14px;
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
.info-label {
font-size: 12px;
color: @text-muted;
}
.info-value {
font-size: 12px;
font-weight: 500;
color: @text-dark;
}
}
}
.cert-empty {
display: flex;
align-items: center;
justify-content: center;
height: 60px;
margin-bottom: 14px;
font-size: 13px;
color: @text-muted;
}
.cert-actions {
.cert-btn {
display: flex;
width: 100%;
padding: 10px;
font-size: 13px;
font-weight: 600;
color: @green-primary;
cursor: pointer;
background: @green-light;
border: 1px solid rgba(72, 198, 102, 0.2);
border-radius: 8px;
transition: all 0.3s ease;
align-items: center;
justify-content: center;
gap: 6px;
&:hover {
color: #fff;
background: @green-primary;
border-color: @green-primary;
}
.t-icon {
font-size: 14px;
transition: transform 0.3s ease;
}
&:hover .t-icon {
transform: translateX(3px);
}
}
}
</style>

View File

@ -86,6 +86,7 @@ export default {
@shadow-hover: 0 8px 24px rgba(0, 0, 0, 0.08);
.policy-news {
width: 100%;
overflow: hidden;
background: @bg-card;
border-radius: 16px;

View File

@ -1,22 +1,25 @@
<template>
<div class="quick-actions">
<div class="actions-grid">
<button
v-for="(action, index) in actions"
:key="action.label"
class="action-btn"
:class="`action-btn--${index}`"
class="action-item"
:style="{ '--delay': `${index * 0.06}s` }"
@click="handleClick(action.to)"
>
<span class="btn-icon">
<div class="item-icon-wrap">
<div class="item-icon" :style="{ background: action.bgColor, color: action.color }">
<t-icon :name="action.icon" />
</span>
<span class="btn-label">{{ action.label }}</span>
<span class="btn-arrow">
</div>
</div>
<span class="item-label">{{ action.label }}</span>
<div class="item-arrow">
<t-icon name="arrow-right" />
</span>
<div class="btn-bg"></div>
</div>
</button>
</div>
</div>
</template>
<script>
@ -25,10 +28,10 @@ export default {
data() {
return {
actions: [
{ label: '发布服务', to: '/yhzx/tfwgj', icon: 'upload' },
{ label: '发布数据', to: '/yhzx/tfwgj?action=publishData', icon: 'cloud-upload' },
{ label: '发布需求', to: '/yhzx/tfwxq', icon: 'edit' },
{ label: '质证申请', to: '/yhzx/zzgl', icon: 'certificate' },
{ label: '发布服务', to: '/yhzx/tfwgj', icon: 'upload', bgColor: '#E8FFEA', color: '#48C666' },
{ label: '发布数据', to: '/yhzx/tfwgj?action=publishData', icon: 'cloud-upload', bgColor: '#E3F2FD', color: '#2196F3' },
{ label: '发布需求', to: '/yhzx/tfwxq', icon: 'edit', bgColor: '#FFF8E1', color: '#FF9800' },
{ label: '质证申请', to: '/yhzx/zzgl', icon: 'bulletpoint', bgColor: '#FCE4EC', color: '#E91E63' },
],
};
},
@ -44,112 +47,129 @@ export default {
@green-primary: #48C666;
@green-dark: #2D8A45;
@green-light: #E8FFEA;
@green-glow: rgba(72, 198, 102, 0.2);
@text-dark: #1A2B3C;
@text-muted: #6B7C8D;
@bg-card: #FFFFFF;
@border-light: rgba(72, 198, 102, 0.3);
@border-light: rgba(0, 0, 0, 0.06);
@shadow-hover: 0 4px 16px rgba(0, 0, 0, 0.1);
.quick-actions {
display: flex;
flex-wrap: wrap;
gap: 14px;
align-items: center;
.actions-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
}
.action-btn {
.action-item {
position: relative;
display: inline-flex;
padding: 0;
font-family: inherit;
display: flex;
padding: 20px 12px;
overflow: hidden;
cursor: pointer;
background: transparent;
border: none;
outline: none;
background: @bg-card;
border: 1px solid @border-light;
border-radius: 14px;
animation: fadeIn 0.4s ease backwards;
animation-delay: var(--delay);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
flex-direction: column;
align-items: center;
gap: 8px;
gap: 10px;
.btn-bg {
&::before {
position: absolute;
z-index: 0;
background: linear-gradient(135deg, @green-light 0%, #fff 100%);
border: 2px solid @green-primary;
border-radius: 10px;
opacity: 0;
transform: scale(0.95);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
inset: 0;
}
.btn-icon {
position: relative;
z-index: 1;
display: flex;
width: 40px;
height: 40px;
font-size: 18px;
color: #fff;
background: linear-gradient(135deg, @green-primary 0%, @green-dark 100%);
border-radius: 10px 0 0 10px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
align-items: center;
justify-content: center;
}
.btn-label {
position: relative;
z-index: 1;
padding: 10px 14px 10px 6px;
font-size: 14px;
font-weight: 600;
color: @green-dark;
white-space: nowrap;
background: transparent;
border: 2px solid @green-primary;
border-left: none;
border-radius: 0 10px 10px 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-arrow {
position: relative;
z-index: 1;
display: flex;
width: 24px;
height: 24px;
margin-right: 10px;
color: @green-primary;
opacity: 0;
transform: translateX(-8px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
align-items: center;
justify-content: center;
top: 0;
right: 0;
left: 0;
height: 3px;
background: linear-gradient(90deg, @green-primary, @green-dark);
content: '';
transform: scaleX(0);
transition: transform 0.3s ease;
}
&:hover {
.btn-bg {
opacity: 1;
transform: scale(1);
border-color: transparent;
transform: translateY(-3px);
box-shadow: @shadow-hover;
&::before {
transform: scaleX(1);
}
.btn-icon {
transform: translateX(4px);
box-shadow: 0 4px 16px @green-glow;
.item-icon {
transform: scale(1.1);
}
.btn-label {
padding-left: 10px;
color: @green-primary;
}
.btn-arrow {
.item-arrow {
opacity: 1;
transform: translateX(0);
}
}
&:active {
transform: scale(0.98);
transform: translateY(-1px);
}
.item-icon-wrap {
display: flex;
align-items: center;
justify-content: center;
}
.item-icon {
display: flex;
width: 48px;
height: 48px;
font-size: 22px;
border-radius: 12px;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
align-items: center;
justify-content: center;
}
.item-label {
font-size: 13px;
font-weight: 600;
color: @text-dark;
text-align: center;
}
.item-arrow {
position: absolute;
top: 50%;
right: 12px;
display: flex;
font-size: 14px;
color: @green-primary;
opacity: 0;
transform: translateX(-4px);
transition: all 0.3s ease;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 1200px) {
.quick-actions .actions-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.quick-actions .actions-grid {
grid-template-columns: 1fr 1fr;
gap: 10px;
}
}
</style>

View File

@ -8,15 +8,14 @@
</div>
<div class="gzt-container">
<!-- 欢迎区域 -->
<!-- 第一行欢迎区域 + 企业认证 -->
<div class="top-row">
<!-- 左侧欢迎 + 统计 -->
<div class="left-column">
<div class="welcome-section">
<div class="welcome-left">
<div class="welcome-badge">
<t-icon name="leaf" />
<span>碳信网</span>
</div>
<h1 class="welcome-title">欢迎回来</h1>
<p class="welcome-subtitle">今天是碳市场活跃日把握每一个交易机会</p>
<p class="welcome-subtitle">{{ currentGreeting }}祝您工作顺利</p>
</div>
<div class="welcome-right">
<div class="time-widget">
@ -28,10 +27,6 @@
<!-- 统计卡片区域 -->
<div class="stats-section">
<div class="section-header">
<div class="header-line"></div>
<span class="section-label">数据概览</span>
</div>
<div class="stats-grid">
<StatsCard
title="我的供给"
@ -48,7 +43,7 @@
unit="条"
bgColor="#E3F2FD"
borderColor="#2196F3"
iconName="request"
iconName="search"
to="/yhzx/wdxq"
/>
<StatsCard
@ -71,6 +66,13 @@
/>
</div>
</div>
</div>
<!-- 右侧企业认证 -->
<div class="right-column">
<EnterpriseCert />
</div>
</div>
<!-- 主要内容区 -->
<div class="main-content">
@ -82,9 +84,11 @@
<div class="header-icon">
<t-icon name="app" />
</div>
<div class="header-text">
<h2 class="panel-title">常用功能</h2>
<p class="panel-desc">快速访问核心功能</p>
</div>
</div>
<div class="panel-body">
<QuickActions />
</div>
@ -96,9 +100,11 @@
<div class="header-icon header-icon--account">
<t-icon name="setting" />
</div>
<div class="header-text">
<h2 class="panel-title">账号管理</h2>
<p class="panel-desc">账户设置与安全</p>
</div>
</div>
<div class="panel-body">
<AccountShortcuts />
</div>
@ -119,6 +125,7 @@ import StatsCard from './components/StatsCard.vue';
import QuickActions from './components/QuickActions.vue';
import PolicyNews from './components/PolicyNews.vue';
import AccountShortcuts from './components/AccountShortcuts.vue';
import EnterpriseCert from './components/EnterpriseCert.vue';
export default {
name: 'GztIndex',
@ -127,11 +134,13 @@ export default {
QuickActions,
PolicyNews,
AccountShortcuts,
EnterpriseCert,
},
data() {
return {
currentDate: '',
currentWeekday: '',
currentGreeting: '',
};
},
mounted() {
@ -140,9 +149,19 @@ export default {
methods: {
updateDateTime() {
const now = new Date();
const hours = now.getHours();
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
this.currentDate = `${now.getFullYear()}${now.getMonth() + 1}${now.getDate()}`;
this.currentWeekday = weekdays[now.getDay()];
if (hours < 12) {
this.currentGreeting = '早上好';
} else if (hours < 14) {
this.currentGreeting = '中午好';
} else if (hours < 18) {
this.currentGreeting = '下午好';
} else {
this.currentGreeting = '晚上好';
}
},
},
};
@ -216,16 +235,35 @@ export default {
margin: 0 auto;
}
// ========== ==========
.top-row {
display: grid;
grid-template-columns: 1fr 300px;
gap: 20px;
margin-bottom: 24px;
animation: fadeSlideUp 0.5s ease backwards;
}
.left-column {
display: flex;
flex-direction: column;
gap: 16px;
}
.right-column {
display: flex;
width: 300px;
flex-shrink: 0;
}
// ========== ==========
.welcome-section {
display: flex;
padding: 28px 32px;
margin-bottom: 28px;
padding: 20px 24px;
background: linear-gradient(135deg, #FFF 0%, #FAFFFE 50%, @green-soft 100%);
border: 1px solid rgba(72, 198, 102, 0.1);
border-radius: 20px;
border-radius: 16px;
box-shadow: @shadow-soft;
animation: fadeSlideUp 0.5s ease backwards;
align-items: flex-start;
justify-content: space-between;
}
@ -233,8 +271,8 @@ export default {
.welcome-left {
.welcome-badge {
display: inline-flex;
padding: 6px 14px;
margin-bottom: 12px;
padding: 5px 12px;
margin-bottom: 8px;
font-size: 12px;
font-weight: 600;
color: @green-dark;
@ -245,13 +283,13 @@ export default {
gap: 6px;
.t-icon {
font-size: 14px;
font-size: 13px;
}
}
.welcome-title {
margin: 0 0 8px;
font-size: 28px;
margin: 0 0 6px;
font-size: 24px;
font-weight: 700;
letter-spacing: -0.5px;
color: @text-dark;
@ -259,28 +297,28 @@ export default {
.welcome-subtitle {
margin: 0;
font-size: 14px;
font-size: 13px;
color: @text-muted;
}
}
.welcome-right {
.time-widget {
padding: 12px 16px;
padding: 8px 12px;
text-align: right;
background: rgba(255, 255, 255, 0.8);
border: 1px solid @border-light;
border-radius: 12px;
border-radius: 8px;
.time-date {
margin-bottom: 2px;
font-size: 14px;
font-size: 12px;
font-weight: 600;
color: @text-dark;
}
.time-weekday {
font-size: 12px;
font-size: 11px;
color: @text-muted;
}
}
@ -288,7 +326,6 @@ export default {
// ========== ==========
.stats-section {
margin-bottom: 28px;
animation: fadeSlideUp 0.5s ease backwards;
animation-delay: 0.1s;
}
@ -336,6 +373,11 @@ export default {
gap: 24px;
}
.right-panel {
width: 300px;
flex-shrink: 0;
}
.panel-card {
overflow: hidden;
background: @bg-card;
@ -345,22 +387,25 @@ export default {
}
.panel-header {
padding: 24px 28px 20px;
display: flex;
align-items: center;
gap: 14px;
padding: 18px 24px 16px;
background: linear-gradient(180deg, #FAFFFE 0%, @bg-card 100%);
border-bottom: 1px solid @border-light;
.header-icon {
display: inline-flex;
display: flex;
width: 40px;
height: 40px;
margin-bottom: 12px;
font-size: 20px;
color: #fff;
background: linear-gradient(135deg, @green-primary 0%, @green-dark 100%);
border-radius: 12px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(72, 198, 102, 0.3);
align-items: center;
justify-content: center;
flex-shrink: 0;
&--account {
background: linear-gradient(135deg, #78909C 0%, #546E7A 100%);
@ -368,22 +413,29 @@ export default {
}
}
.header-text {
flex: 1;
min-width: 0;
}
.panel-title {
margin: 0 0 4px;
font-size: 18px;
margin: 0;
font-size: 16px;
font-weight: 600;
line-height: 1.4;
color: @text-dark;
}
.panel-desc {
margin: 0;
font-size: 13px;
margin: 2px 0 0;
font-size: 12px;
line-height: 1.4;
color: @text-light;
}
}
.panel-body {
padding: 24px 28px;
padding: 18px 24px;
}
// ========== ==========