修改样式

This commit is contained in:
zhangxiaohua 2026-01-16 14:48:14 +08:00
parent b002e3ca1c
commit 8411df8ad6
9 changed files with 464 additions and 229 deletions

View File

@ -17,15 +17,15 @@ description: "比赛管理系统设计规范。当用户提出页面开发需求
// ==========================================
// 项目统一设计变量 - 必须复制
// ==========================================
$primary: #0958d9;
$primary-light: #1677ff;
$primary-dark: #003eb3;
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
$secondary: #4096ff;
$success: #52c41a;
$warning: #faad14;
$error: #ff4d4f;
$background: #f5f5f5;
$background: #f5f7fa;
$surface: #ffffff;
$text: rgba(0, 0, 0, 0.85);
@ -35,7 +35,7 @@ $text-muted: rgba(0, 0, 0, 0.45);
$border: #d9d9d9;
$border-light: #e8e8e8;
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
```
---
@ -46,9 +46,9 @@ $gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
| 变量 | 色值 | 用途 |
|------|------|------|
| `$primary` | `#0958d9` | 主色、按钮、链接 |
| `$primary-light` | `#1677ff` | 悬停态 |
| `$primary-dark` | `#003eb3` | 激活态 |
| `$primary` | `#1890ff` | 主色、按钮、链接 |
| `$primary-dark` | `#0958d9` | 渐变深色、激活态 |
| `$primary-light` | `#40a9ff` | 悬停态、浅色 |
| `$secondary` | `#4096ff` | 辅助蓝 |
### 功能色
@ -156,20 +156,45 @@ $gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
</a-button>
```
### 主按钮
### 主按钮(渐变样式)
```scss
.primary-btn {
background: $gradient-primary !important;
.primary-btn,
.gradient-btn {
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%) !important;
border: none !important;
color: #fff !important;
font-weight: 500 !important;
border-radius: 20px !important;
padding: 6px 16px !important;
transition: all 0.3s ease !important;
box-shadow: 0 2px 8px rgba($primary, 0.3);
&:hover {
filter: brightness(1.1);
transform: translateY(-2px);
box-shadow: 0 12px 24px rgba($primary, 0.2);
box-shadow: 0 6px 20px rgba($primary, 0.4);
}
}
// 用于 hero 区域的大按钮
.action-btn.primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 28px;
border-radius: 24px;
font-size: 15px;
font-weight: 600;
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
color: #fff;
border: none;
cursor: pointer;
box-shadow: 0 4px 15px rgba($primary, 0.4);
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba($primary, 0.5);
}
}
```

View File

@ -211,26 +211,25 @@ const handleLogout = async () => {
</script>
<style scoped lang="scss">
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
.layout {
min-height: 100vh;
}
// -
//
.custom-sider {
background: var(--sidebar-bg, #f5f5f5) !important; //
border-right: none !important; // 线
background: #fff !important;
border-right: none !important;
box-shadow: 2px 0 12px rgba(0, 0, 0, 0.05);
:deep(.ant-layout-sider-children) {
background: var(--sidebar-bg, #f5f5f5);
background: #fff;
display: flex;
flex-direction: column;
height: 100%;
padding-right: 10px;
}
// Ant Design Vue
:deep(.ant-layout-sider) {
border-right: none !important;
}
}
@ -244,10 +243,37 @@ const handleLogout = async () => {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 0 8px;
}
// Logo -
.logo {
height: 64px;
display: flex;
align-items: center;
justify-content: center;
padding: 16px 12px;
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
margin-bottom: 8px;
img {
max-width: 100%;
max-height: 32px;
object-fit: contain;
}
.logo-text {
color: $primary;
font-size: 18px;
font-weight: 700;
margin: 0;
letter-spacing: 1px;
}
}
//
.sider-bottom {
padding: 12px;
padding: 12px 16px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
@ -258,7 +284,7 @@ const handleLogout = async () => {
display: flex;
align-items: center;
gap: 10px;
padding: 8px;
padding: 6px 10px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
@ -266,12 +292,17 @@ const handleLogout = async () => {
min-width: 0;
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed);
background: rgba($primary, 0.08);
}
:deep(.ant-avatar) {
border: 2px solid rgba($primary, 0.2);
}
.username {
font-size: 14px;
color: var(--sidebar-menu-text, rgba(0, 0, 0, 0.85));
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -280,7 +311,7 @@ const handleLogout = async () => {
.user-info-collapsed {
justify-content: center;
padding: 8px;
padding: 6px;
flex: unset;
}
@ -290,15 +321,15 @@ const handleLogout = async () => {
justify-content: center;
width: 32px;
height: 32px;
border-radius: 6px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
color: var(--sidebar-menu-text, rgba(0, 0, 0, 0.65));
color: rgba(0, 0, 0, 0.45);
flex-shrink: 0;
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed);
color: var(--sidebar-menu-text-selected, #01412b);
background: rgba($primary, 0.08);
color: $primary;
}
}
}
@ -306,7 +337,7 @@ const handleLogout = async () => {
.sider-bottom-collapsed {
flex-direction: column;
align-items: center;
gap: 12px;
gap: 10px;
padding: 12px 8px;
.collapse-trigger {
@ -314,59 +345,51 @@ const handleLogout = async () => {
}
}
.logo {
height: 64px;
display: flex;
align-items: center;
justify-content: center;
background: transparent; //
color: var(--sidebar-menu-text-selected, #01412b); // Logo 使
margin-bottom: 8px;
border-radius: 0; //
padding: 20px 12px;
img {
max-width: 100%;
max-height: 30px;
object-fit: contain;
}
.logo-text {
color: var(--sidebar-menu-text-selected, #01412b); // Logo 使
font-size: 18px;
font-weight: bold;
margin: 0;
}
}
// Ant Design 使
// Ant Design
:deep(.ant-menu-light.ant-menu-root.ant-menu-inline),
:deep(.ant-menu-light.ant-menu-root.ant-menu-vertical) {
border-inline-end: none !important;
}
//
// -
.custom-menu {
background: transparent !important;
border-right: none !important;
border-inline-end: none !important;
padding: 4px 0;
:deep(.ant-menu-item) {
color: var(--sidebar-menu-text, rgba(0, 0, 0, 0.85));
margin: 4px 8px;
border-radius: 6px;
transition: all 0.3s;
color: rgba(0, 0, 0, 0.75);
margin: 4px 0;
border-radius: 10px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: transparent !important;
height: 44px;
line-height: 44px;
.anticon {
font-size: 16px;
transition: all 0.3s;
}
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: var(--sidebar-menu-text-selected, #01412b) !important;
color: $primary !important;
background: rgba($primary, 0.08) !important;
.anticon {
color: $primary;
}
}
&.ant-menu-item-selected {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: var(--sidebar-menu-text-selected, #01412b) !important;
color: #fff !important;
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%) !important;
font-weight: 500;
box-shadow: 0 2px 8px rgba($primary, 0.3);
.anticon {
color: #fff;
}
&::after {
display: none;
@ -376,34 +399,41 @@ const handleLogout = async () => {
:deep(.ant-menu-submenu) {
.ant-menu-submenu-title {
color: var(--sidebar-menu-text, rgba(0, 0, 0, 0.85));
margin: 4px 8px;
border-radius: 6px;
transition: all 0.3s;
color: rgba(0, 0, 0, 0.75);
margin: 4px 0;
border-radius: 10px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: transparent !important;
height: 44px;
line-height: 44px;
.anticon {
font-size: 16px;
transition: all 0.3s;
}
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: var(--sidebar-menu-text-selected, #01412b) !important;
color: $primary !important;
background: rgba($primary, 0.08) !important;
.anticon {
color: $primary;
}
}
}
&.ant-menu-submenu-open > .ant-menu-submenu-title {
color: var(--sidebar-menu-text-selected, #01412b);
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: $primary;
background: rgba($primary, 0.08) !important;
.anticon {
color: $primary;
}
}
&.ant-menu-submenu-selected > .ant-menu-submenu-title {
color: var(--sidebar-menu-text-selected, #01412b);
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
}
}
:deep(.ant-menu-submenu-inner) {
.ant-menu-submenu-title {
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
}
color: $primary;
font-weight: 500;
}
}
@ -412,20 +442,27 @@ const handleLogout = async () => {
.ant-menu-item {
padding-left: 48px !important;
background: transparent !important;
&:hover {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: var(--sidebar-menu-text-selected, #01412b) !important;
}
height: 40px;
line-height: 40px;
margin: 2px 0;
&.ant-menu-item-selected {
background: var(--sidebar-menu-item-selected-bg, #e2f0ed) !important;
color: var(--sidebar-menu-text-selected, #01412b) !important;
font-weight: 500;
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%) !important;
box-shadow: 0 2px 8px rgba($primary, 0.3);
}
}
}
//
:deep(.ant-menu-submenu-arrow) {
color: rgba(0, 0, 0, 0.45);
transition: all 0.3s;
}
:deep(.ant-menu-submenu-open > .ant-menu-submenu-title > .ant-menu-submenu-arrow),
:deep(.ant-menu-submenu:hover > .ant-menu-submenu-title > .ant-menu-submenu-arrow) {
color: $primary;
}
}
.main-layout {
@ -435,7 +472,7 @@ const handleLogout = async () => {
.content {
padding: 20px;
background: #fff;
background: #f5f7fa;
height: 100vh;
overflow-y: auto;
overflow-x: hidden;

View File

@ -523,9 +523,10 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
//
$primary: #0958d9;
$primary-light: #1677ff;
// -
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
.contests-activities-page {
padding: 24px;
@ -582,7 +583,7 @@ $primary-light: #1677ff;
&.active {
color: #fff;
background: linear-gradient(135deg, $primary-light 0%, $primary 100%);
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
box-shadow: 0 4px 12px rgba($primary, 0.35);
.anticon {
@ -834,19 +835,19 @@ $primary-light: #1677ff;
padding: 6px 16px;
height: auto;
font-size: 13px;
background: linear-gradient(135deg, #1890ff 0%, #0050b3 100%);
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
box-shadow: 0 2px 8px rgba($primary, 0.3);
transition: all 0.3s ease;
&:hover {
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.5);
background: linear-gradient(135deg, $primary-light 0%, $primary 100%);
box-shadow: 0 4px 12px rgba($primary, 0.4);
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.4);
box-shadow: 0 2px 6px rgba($primary, 0.3);
}
}
@ -864,7 +865,7 @@ $primary-light: #1677ff;
&:hover {
background: linear-gradient(135deg, #e8ecf0 0%, #dce1e6 100%);
color: #1890ff;
color: $primary;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
transform: translateY(-1px);
}

View File

@ -30,7 +30,9 @@
<!-- 状态标签 -->
<div class="status-tags">
<span class="tag tag-type">
{{ contest?.contestType === "individual" ? "个人赛" : "团队赛" }}
{{
contest?.contestType === "individual" ? "个人赛" : "团队赛"
}}
</span>
<span v-if="getStageText()" class="tag" :class="getStageClass()">
{{ getStageText() }}
@ -44,11 +46,17 @@
<div class="hero-meta">
<div class="meta-item">
<CalendarOutlined />
<span>比赛时间{{ formatDate(contest?.startTime) }} ~ {{ formatDate(contest?.endTime) }}</span>
<span
>比赛时间{{ formatDate(contest?.startTime) }} ~
{{ formatDate(contest?.endTime) }}</span
>
</div>
<div class="meta-item">
<ClockCircleOutlined />
<span>报名时间{{ formatDate(contest?.registerStartTime) }} ~ {{ formatDate(contest?.registerEndTime) }}</span>
<span
>报名时间{{ formatDate(contest?.registerStartTime) }} ~
{{ formatDate(contest?.registerEndTime) }}</span
>
</div>
</div>
@ -76,7 +84,7 @@
disabled
>
<FormOutlined />
{{ isRegistering ? '立即报名' : '报名已截止' }}
{{ isRegistering ? "立即报名" : "报名已截止" }}
</button>
<span v-if="isRegistering" class="countdown">
距离报名截止还有 <strong>{{ daysRemaining }}</strong>
@ -105,7 +113,9 @@
>
<BellOutlined />
<span>通知公告</span>
<span v-if="notices.length > 0" class="badge">{{ notices.length }}</span>
<span v-if="notices.length > 0" class="badge">{{
notices.length
}}</span>
</div>
<div
class="tab-item"
@ -134,7 +144,11 @@
<h2>竞赛详情</h2>
</div>
<div class="card-body">
<div v-if="contest.content" class="rich-content" v-html="contest.content"></div>
<div
v-if="contest.content"
class="rich-content"
v-html="contest.content"
></div>
<a-empty v-else description="暂无详情内容" />
</div>
</div>
@ -151,11 +165,18 @@
<div v-if="noticesLoading" class="loading-placeholder">
<a-spin />
</div>
<div v-else-if="notices.length === 0" class="empty-placeholder">
<div
v-else-if="notices.length === 0"
class="empty-placeholder"
>
<a-empty description="暂无公告" />
</div>
<div v-else class="notice-list">
<div v-for="item in notices" :key="item.id" class="notice-item">
<div
v-for="item in notices"
:key="item.id"
class="notice-item"
>
<div class="notice-header">
<span class="notice-title">{{ item.title }}</span>
<span class="notice-type" :class="item.noticeType">
@ -192,15 +213,26 @@
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'rank'">
<div class="rank-badge" :class="getRankClass(record.rank)">
<div
class="rank-badge"
:class="getRankClass(record.rank)"
>
{{ record.rank || "-" }}
</div>
</template>
<template v-else-if="column.key === 'author'">
{{ record.registration?.user?.nickname || record.registration?.team?.teamName || "-" }}
{{
record.registration?.user?.nickname ||
record.registration?.team?.teamName ||
"-"
}}
</template>
<template v-else-if="column.key === 'award'">
<span v-if="record.awardName" class="award-tag" :class="getAwardClass(record.awardName)">
<span
v-if="record.awardName"
class="award-tag"
:class="getAwardClass(record.awardName)"
>
{{ record.awardName }}
</span>
<span v-else>-</span>
@ -230,8 +262,16 @@
主办单位
</div>
<div class="item-value">
<template v-if="contest.organizers && contest.organizers.length">
<div v-for="org in contest.organizers" :key="org" class="org-name">{{ org }}</div>
<template
v-if="contest.organizers && contest.organizers.length"
>
<div
v-for="org in contest.organizers"
:key="org"
class="org-name"
>
{{ org }}
</div>
</template>
<span v-else class="empty-text">暂无</span>
</div>
@ -243,8 +283,18 @@
协办单位
</div>
<div class="item-value">
<template v-if="contest.coOrganizers && contest.coOrganizers.length">
<div v-for="org in contest.coOrganizers" :key="org" class="org-name">{{ org }}</div>
<template
v-if="
contest.coOrganizers && contest.coOrganizers.length
"
>
<div
v-for="org in contest.coOrganizers"
:key="org"
class="org-name"
>
{{ org }}
</div>
</template>
<span v-else class="empty-text">暂无</span>
</div>
@ -256,8 +306,16 @@
赞助单位
</div>
<div class="item-value">
<template v-if="contest.sponsors && contest.sponsors.length">
<div v-for="sp in contest.sponsors" :key="sp" class="org-name">{{ sp }}</div>
<template
v-if="contest.sponsors && contest.sponsors.length"
>
<div
v-for="sp in contest.sponsors"
:key="sp"
class="org-name"
>
{{ sp }}
</div>
</template>
<span v-else class="empty-text">暂无</span>
</div>
@ -266,7 +324,10 @@
</div>
<!-- 联系方式 -->
<div v-if="contest.contactName || contest.contactPhone" class="sidebar-card">
<div
v-if="contest.contactName || contest.contactPhone"
class="sidebar-card"
>
<div class="sidebar-header">
<PhoneOutlined />
<span>联系方式</span>
@ -293,7 +354,11 @@
</div>
</div>
<a-empty v-else-if="!loading" description="比赛不存在" style="padding: 100px 0" />
<a-empty
v-else-if="!loading"
description="比赛不存在"
style="padding: 100px 0"
/>
</a-spin>
</div>
</template>
@ -347,7 +412,10 @@ const myRegistration = ref<any>(null)
const canViewRegistration = computed(() => {
const permissions = authStore.user?.permissions || []
return permissions.includes("registration:read") || permissions.includes("registration:create")
return (
permissions.includes("registration:read") ||
permissions.includes("registration:create")
)
})
const isTeacher = computed(() => authStore.hasRole("teacher"))
@ -364,7 +432,13 @@ const resultColumns = [
{ title: "排名", key: "rank", dataIndex: "rank", width: 80 },
{ title: "作品名称", key: "title", dataIndex: "title", width: 200 },
{ title: "作者", key: "author", width: 150 },
{ title: "最终得分", key: "finalScore", dataIndex: "finalScore", width: 120, sorter: true },
{
title: "最终得分",
key: "finalScore",
dataIndex: "finalScore",
width: 120,
sorter: true,
},
{ title: "奖项", key: "award", width: 120 },
]
@ -387,15 +461,23 @@ const isRegistering = computed(() => {
})
const isSubmitting = computed(() => {
if (!contest.value?.submitStartTime || !contest.value?.submitEndTime) return false
if (!contest.value?.submitStartTime || !contest.value?.submitEndTime)
return false
const now = dayjs()
return now.isAfter(dayjs(contest.value.submitStartTime)) && now.isBefore(dayjs(contest.value.submitEndTime))
return (
now.isAfter(dayjs(contest.value.submitStartTime)) &&
now.isBefore(dayjs(contest.value.submitEndTime))
)
})
const isReviewing = computed(() => {
if (!contest.value?.reviewStartTime || !contest.value?.reviewEndTime) return false
if (!contest.value?.reviewStartTime || !contest.value?.reviewEndTime)
return false
const now = dayjs()
return now.isAfter(dayjs(contest.value.reviewStartTime)) && now.isBefore(dayjs(contest.value.reviewEndTime))
return (
now.isAfter(dayjs(contest.value.reviewStartTime)) &&
now.isBefore(dayjs(contest.value.reviewEndTime))
)
})
const daysRemaining = computed(() => {
@ -422,9 +504,12 @@ const getStageClass = () => {
const getNoticeTypeText = (type?: string) => {
switch (type) {
case "urgent": return "紧急"
case "system": return "系统"
default: return "公告"
case "urgent":
return "紧急"
case "system":
return "系统"
default:
return "公告"
}
}
@ -488,7 +573,11 @@ const fetchResults = async () => {
if (!contest.value || contest.value.resultState !== "published") return
resultsLoading.value = true
try {
const response = await resultsApi.getResults(contestId, resultsPagination.value.current, resultsPagination.value.pageSize)
const response = await resultsApi.getResults(
contestId,
resultsPagination.value.current,
resultsPagination.value.pageSize
)
results.value = response.list || []
resultsPagination.value.total = response.total || 0
} catch (error: any) {
@ -566,7 +655,11 @@ $primary-dark: #0958d9;
.hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.6) 100%);
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0.3) 0%,
rgba(0, 0, 0, 0.6) 100%
);
}
.hero-nav {
@ -579,9 +672,9 @@ $primary-dark: #0958d9;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: rgba(255,255,255,0.15);
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
color: #fff;
font-size: 14px;
@ -589,7 +682,7 @@ $primary-dark: #0958d9;
transition: all 0.3s;
&:hover {
background: rgba(255,255,255,0.25);
background: rgba(255, 255, 255, 0.25);
}
}
}
@ -624,14 +717,22 @@ $primary-dark: #0958d9;
}
.tag-type {
background: rgba(255,255,255,0.2);
border: 1px solid rgba(255,255,255,0.3);
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.tag-registering { background: linear-gradient(135deg, #52c41a, #73d13d); }
.tag-submitting { background: linear-gradient(135deg, #1890ff, #40a9ff); }
.tag-reviewing { background: linear-gradient(135deg, #faad14, #ffc53d); }
.tag-finished { background: linear-gradient(135deg, #8c8c8c, #bfbfbf); }
.tag-registering {
background: linear-gradient(135deg, #52c41a, #73d13d);
}
.tag-submitting {
background: linear-gradient(135deg, #1890ff, #40a9ff);
}
.tag-reviewing {
background: linear-gradient(135deg, #faad14, #ffc53d);
}
.tag-finished {
background: linear-gradient(135deg, #8c8c8c, #bfbfbf);
}
}
.hero-title {
@ -639,7 +740,7 @@ $primary-dark: #0958d9;
font-weight: 700;
color: #fff;
margin: 0 0 20px;
text-shadow: 0 2px 10px rgba(0,0,0,0.3);
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
line-height: 1.3;
}
@ -654,9 +755,11 @@ $primary-dark: #0958d9;
align-items: center;
gap: 8px;
font-size: 14px;
color: rgba(255,255,255,0.9);
color: rgba(255, 255, 255, 0.9);
.anticon { font-size: 16px; }
.anticon {
font-size: 16px;
}
}
}
@ -689,7 +792,7 @@ $primary-dark: #0958d9;
}
&.secondary {
background: rgba(255,255,255,0.9);
background: rgba(255, 255, 255, 0.9);
color: $primary;
&:hover {
@ -698,15 +801,15 @@ $primary-dark: #0958d9;
}
&.disabled {
background: rgba(255,255,255,0.3);
color: rgba(255,255,255,0.6);
background: rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.6);
cursor: not-allowed;
}
}
.countdown {
font-size: 14px;
color: rgba(255,255,255,0.85);
color: rgba(255, 255, 255, 0.85);
strong {
color: #ffc53d;
@ -719,9 +822,9 @@ $primary-dark: #0958d9;
// Tab
.tab-section {
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
position: sticky;
top: 0;
top: -20px;
z-index: 100;
.tab-container {
@ -741,7 +844,7 @@ $primary-dark: #0958d9;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
color: rgba(0,0,0,0.65);
color: rgba(0, 0, 0, 0.65);
cursor: pointer;
transition: all 0.3s;
position: relative;
@ -782,7 +885,7 @@ $primary-dark: #0958d9;
padding: 24px 0 48px;
.main-container {
padding: 0 24px;
padding: 0;
}
.content-grid {
@ -796,7 +899,7 @@ $primary-dark: #0958d9;
.content-card {
background: #fff;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
overflow: hidden;
.card-header {
@ -821,7 +924,7 @@ $primary-dark: #0958d9;
h2 {
font-size: 18px;
font-weight: 600;
color: rgba(0,0,0,0.85);
color: rgba(0, 0, 0, 0.85);
margin: 0;
}
}
@ -834,20 +937,29 @@ $primary-dark: #0958d9;
//
.rich-content {
font-size: 14px;
color: rgba(0,0,0,0.75);
color: rgba(0, 0, 0, 0.75);
line-height: 1.8;
:deep(p) {
margin-bottom: 16px;
&:last-child { margin-bottom: 0; }
&:last-child {
margin-bottom: 0;
}
}
:deep(h1), :deep(h2), :deep(h3), :deep(h4), :deep(h5), :deep(h6) {
color: rgba(0,0,0,0.85);
:deep(h1),
:deep(h2),
:deep(h3),
:deep(h4),
:deep(h5),
:deep(h6) {
color: rgba(0, 0, 0, 0.85);
font-weight: 600;
margin-top: 24px;
margin-bottom: 12px;
&:first-child { margin-top: 0; }
&:first-child {
margin-top: 0;
}
}
:deep(img) {
@ -856,7 +968,8 @@ $primary-dark: #0958d9;
margin: 16px 0;
}
:deep(ul), :deep(ol) {
:deep(ul),
:deep(ol) {
padding-left: 24px;
margin-bottom: 16px;
}
@ -870,7 +983,8 @@ $primary-dark: #0958d9;
border-collapse: collapse;
margin: 16px 0;
th, td {
th,
td {
border: 1px solid #e8e8e8;
padding: 12px;
text-align: left;
@ -887,13 +1001,15 @@ $primary-dark: #0958d9;
padding: 12px 20px;
background: #f9f9f9;
border-left: 4px solid $primary;
color: rgba(0,0,0,0.65);
color: rgba(0, 0, 0, 0.65);
}
:deep(a) {
color: $primary;
text-decoration: none;
&:hover { text-decoration: underline; }
&:hover {
text-decoration: underline;
}
}
}
@ -905,7 +1021,9 @@ $primary-dark: #0958d9;
border-radius: 12px;
margin-bottom: 12px;
&:last-child { margin-bottom: 0; }
&:last-child {
margin-bottom: 0;
}
.notice-header {
display: flex;
@ -916,7 +1034,7 @@ $primary-dark: #0958d9;
.notice-title {
font-size: 15px;
font-weight: 600;
color: rgba(0,0,0,0.85);
color: rgba(0, 0, 0, 0.85);
}
.notice-type {
@ -925,21 +1043,27 @@ $primary-dark: #0958d9;
font-size: 11px;
font-weight: 600;
&.urgent { background: #fff2f0; color: #ff4d4f; }
&.system { background: #e6f7ff; color: #1890ff; }
&.urgent {
background: #fff2f0;
color: #ff4d4f;
}
&.system {
background: #e6f7ff;
color: #1890ff;
}
}
}
.notice-content {
font-size: 14px;
color: rgba(0,0,0,0.65);
color: rgba(0, 0, 0, 0.65);
line-height: 1.6;
margin-bottom: 10px;
}
.notice-time {
font-size: 12px;
color: rgba(0,0,0,0.45);
color: rgba(0, 0, 0, 0.45);
display: flex;
align-items: center;
gap: 6px;
@ -958,11 +1082,20 @@ $primary-dark: #0958d9;
font-weight: 700;
font-size: 14px;
background: #f0f0f0;
color: rgba(0,0,0,0.65);
color: rgba(0, 0, 0, 0.65);
&.rank-1 { background: linear-gradient(135deg, #ffd700, #ffb800); color: #fff; }
&.rank-2 { background: linear-gradient(135deg, #c0c0c0, #a0a0a0); color: #fff; }
&.rank-3 { background: linear-gradient(135deg, #cd7f32, #b8860b); color: #fff; }
&.rank-1 {
background: linear-gradient(135deg, #ffd700, #ffb800);
color: #fff;
}
&.rank-2 {
background: linear-gradient(135deg, #c0c0c0, #a0a0a0);
color: #fff;
}
&.rank-3 {
background: linear-gradient(135deg, #cd7f32, #b8860b);
color: #fff;
}
}
//
@ -972,33 +1105,51 @@ $primary-dark: #0958d9;
font-size: 12px;
font-weight: 600;
&.award-gold { background: #fffbe6; color: #d48806; }
&.award-silver { background: #f5f5f5; color: #595959; }
&.award-bronze { background: #fff7e6; color: #d46b08; }
&.award-gold {
background: #fffbe6;
color: #d48806;
}
&.award-silver {
background: #f5f5f5;
color: #595959;
}
&.award-bronze {
background: #fff7e6;
color: #d46b08;
}
}
//
.sidebar-card {
background: #fff;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
overflow: hidden;
margin-bottom: 20px;
&:last-child { margin-bottom: 0; }
&:last-child {
margin-bottom: 0;
}
.sidebar-header {
display: flex;
align-items: center;
gap: 10px;
padding: 16px 20px;
background: linear-gradient(135deg, rgba($primary, 0.05), rgba($primary-dark, 0.08));
background: linear-gradient(
135deg,
rgba($primary, 0.05),
rgba($primary-dark, 0.08)
);
border-bottom: 1px solid #f0f0f0;
font-size: 15px;
font-weight: 600;
color: rgba(0,0,0,0.85);
color: rgba(0, 0, 0, 0.85);
.anticon { color: $primary; font-size: 16px; }
.anticon {
color: $primary;
font-size: 16px;
}
}
.sidebar-body {
@ -1008,32 +1159,40 @@ $primary-dark: #0958d9;
.sidebar-item {
margin-bottom: 16px;
&:last-child { margin-bottom: 0; }
&:last-child {
margin-bottom: 0;
}
.item-label {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: rgba(0,0,0,0.45);
color: rgba(0, 0, 0, 0.45);
margin-bottom: 8px;
.anticon { font-size: 14px; }
.anticon {
font-size: 14px;
}
}
.item-value {
font-size: 14px;
color: rgba(0,0,0,0.85);
color: rgba(0, 0, 0, 0.85);
line-height: 1.6;
.org-name {
padding: 4px 0;
border-bottom: 1px dashed #f0f0f0;
&:last-child { border-bottom: none; }
&:last-child {
border-bottom: none;
}
}
.empty-text { color: rgba(0,0,0,0.25); }
.empty-text {
color: rgba(0, 0, 0, 0.25);
}
}
}
}
@ -1061,9 +1220,16 @@ $primary-dark: #0958d9;
height: auto;
min-height: 360px;
.hero-title { font-size: 24px; }
.hero-meta { flex-direction: column; gap: 12px; }
.hero-actions { flex-wrap: wrap; }
.hero-title {
font-size: 24px;
}
.hero-meta {
flex-direction: column;
gap: 12px;
}
.hero-actions {
flex-wrap: wrap;
}
}
.tab-section .custom-tabs {

View File

@ -361,17 +361,22 @@ const handlePreview3DModel = (fileUrl: string, index: number) => {
// URL
const allModelUrls = modelItems.value.map((m) => m.fileUrl)
// sessionStorageURL
if (allModelUrls.length > 1) {
sessionStorage.setItem("model-viewer-urls", JSON.stringify(allModelUrls))
sessionStorage.setItem("model-viewer-index", String(index))
// URL
sessionStorage.removeItem("model-viewer-url")
} else {
sessionStorage.setItem("model-viewer-url", fileUrl)
sessionStorage.removeItem("model-viewer-urls")
sessionStorage.removeItem("model-viewer-index")
}
// URL
router.push({
path: `/${tenantCode}/workbench/model-viewer`,
query: { url: fileUrl },
})
}

View File

@ -1489,13 +1489,13 @@ onUnmounted(() => {
<style scoped lang="scss">
// ==========================================
// -
// -
// ==========================================
$primary: #0958d9;
$primary-light: #1677ff;
$primary-dark: #003eb3;
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
$secondary: #4096ff;
$accent: #1677ff;
$accent: #40a9ff;
$success: #52c41a;
$warning: #faad14;
$error: #ff4d4f;
@ -1509,8 +1509,8 @@ $text-secondary: rgba(0, 0, 0, 0.65);
$text-muted: rgba(0, 0, 0, 0.45);
$text-light: #ffffff;
//
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
// -
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
.model-viewer-page {
position: fixed;

View File

@ -355,13 +355,13 @@ onUnmounted(() => {
<style scoped lang="scss">
// ==========================================
// - Index.vue
// -
// ==========================================
$primary: #0958d9;
$primary-light: #1677ff;
$primary-dark: #003eb3;
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
$secondary: #4096ff;
$accent: #1677ff;
$accent: #40a9ff;
$success: #52c41a;
$warning: #faad14;
$error: #ff4d4f;
@ -376,8 +376,8 @@ $text: rgba(0, 0, 0, 0.85);
$text-secondary: rgba(0, 0, 0, 0.65);
$text-muted: rgba(0, 0, 0, 0.45);
//
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
// -
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
$gradient-card: linear-gradient(
145deg,
rgba($primary, 0.05) 0%,

View File

@ -391,11 +391,11 @@ onUnmounted(() => {
<style scoped lang="scss">
// ==========================================
//
// -
// ==========================================
$primary: #0958d9;
$primary-light: #1677ff;
$primary-dark: #003eb3;
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
$secondary: #4096ff;
$success: #52c41a;
$warning: #faad14;
@ -412,7 +412,8 @@ $text-muted: rgba(0, 0, 0, 0.45);
$border: #d9d9d9;
$border-light: #e8e8e8;
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
// -
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
.history-page {
min-height: 100vh;

View File

@ -773,14 +773,14 @@ onUnmounted(() => {
<style scoped lang="scss">
// ==========================================
// -
// -
// ==========================================
// -
$primary: #0958d9; //
$primary-light: #1677ff;
$primary-dark: #003eb3;
$secondary: #4096ff; //
$accent: #1677ff; //
$primary: #1890ff;
$primary-dark: #0958d9;
$primary-light: #40a9ff;
$secondary: #4096ff;
$accent: #40a9ff;
$success: #52c41a;
$warning: #faad14;
$error: #ff4d4f;
@ -796,9 +796,9 @@ $text-secondary: rgba(0, 0, 0, 0.65);
$text-muted: rgba(0, 0, 0, 0.45);
$text-light: #ffffff; //
// -
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-light 100%);
$gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
// -
$gradient-primary: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
$gradient-secondary: linear-gradient(135deg, $primary-light 0%, $primary 100%);
.ai-3d-container {
display: flex;
@ -1335,8 +1335,8 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
line-height: 1.3;
background: linear-gradient(
135deg,
$primary 0%,
$primary-light 40%,
$primary-dark 0%,
$primary 35%,
#8b5cf6 70%,
#a855f7 100%
);
@ -1391,16 +1391,16 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
flex-shrink: 0;
&.gradient-1 {
background: linear-gradient(135deg, $primary 0%, $primary-light 100%);
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
}
&.gradient-2 {
background: linear-gradient(135deg, $primary-light 0%, $accent 100%);
background: linear-gradient(135deg, $primary-dark 0%, darken($primary-dark, 10%) 100%);
}
&.gradient-3 {
background: linear-gradient(135deg, $accent 0%, $primary 100%);
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
}
&.gradient-4 {
background: linear-gradient(135deg, $primary 0%, $primary-dark 100%);
background: linear-gradient(135deg, $primary-dark 0%, $primary 100%);
}
}