Feat: 前端改版 Web 端界面与业务作业流程
按设计稿改版登录后的全部页面,登录页与 Logo 资源未改动。 - 全局外壳:浅色侧边栏与分组菜单、左下角用户卡片、Ctrl/⌘K 搜索面板、 测试模式提示条、深色模式配色、窄屏适配 - 共用组件:页头 PageHeader、托盘流程条 FlowStepper、扫码反馈 ScanFeedback、 缩短单号 DocNo、托盘档案链接 PalletCodeLink、图标 SfIcon、上级资料选择 MasterRefSelect,以及编号段解析等工具 - 工作台重做;新增托盘档案页;托盘追溯增加单托盘入口,报表托盘号可跳转档案 - 基础资料维护:各页加指标条、名称代替 ID、详情面板;三步式批量导入预览; 分配用户对话框标注增减;7 个新增/编辑对话框统一布局 - 业务管理:发货出库、仓库入库、工厂装填、客户现场使用、退回仓库改为 列表 + 详情面板 + 全屏作业区;写入流程、幂等键与防串单逻辑保持不变 - 修复入库页扫码反馈条因同名状态变量遮蔽组件而不显示的问题,并新增契约检查 - 新增入库粘贴解析、退回、装填的行为测试与现场使用页新流程测试, 同步更新业务与工作台契约脚本 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,13 +9,18 @@
|
||||
</template>
|
||||
|
||||
<div class="right-menu">
|
||||
<button type="button" class="right-menu-item search-trigger" aria-label="搜索或扫码(Ctrl K)" @click="openSearch">
|
||||
<sf-icon name="search" :size="15" />
|
||||
<span class="search-trigger__text">搜索或扫码</span>
|
||||
<kbd class="search-trigger__kbd">Ctrl K</kbd>
|
||||
</button>
|
||||
<test-batch-mode-switch class="right-menu-item test-batch-mode" aria-label="测试数据模式" />
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<header-search id="header-search" class="right-menu-item" />
|
||||
<el-tooltip content="全屏" effect="dark" placement="bottom">
|
||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
|
||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
|
||||
<el-tooltip content="主题模式" effect="dark" placement="bottom">
|
||||
<el-tooltip :content="settingsStore.isDark ? '切换浅色模式' : '切换深色模式'" effect="dark" placement="bottom">
|
||||
<div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">
|
||||
<svg-icon v-if="settingsStore.isDark" icon-class="sunny" />
|
||||
<svg-icon v-if="!settingsStore.isDark" icon-class="moon" />
|
||||
@@ -27,9 +32,9 @@
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<el-dropdown @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover">
|
||||
<el-dropdown v-if="!sidebarShowsUser" @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover">
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="userStore.avatar" class="user-avatar" />
|
||||
<img :src="userStore.avatar" class="user-avatar" alt="" />
|
||||
<span class="user-nickname"> {{ userStore.nickName }} </span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
@@ -59,7 +64,7 @@ import Logo from './Sidebar/Logo'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import Screenfull from '@/components/Screenfull'
|
||||
import SizeSelect from '@/components/SizeSelect'
|
||||
import HeaderSearch from '@/components/HeaderSearch'
|
||||
import SfIcon from '@/components/SfIcon'
|
||||
import TestBatchModeSwitch from '@/components/TestBatchModeSwitch'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
@@ -68,6 +73,8 @@ import useSettingsStore from '@/store/modules/settings'
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
// 左侧导航底部已展示当前用户时,顶部不再重复显示头像
|
||||
const sidebarShowsUser = computed(() => appStore.device !== 'mobile' && !appStore.sidebar.hide && settingsStore.navType == 1)
|
||||
|
||||
function toggleSideBar() {
|
||||
appStore.toggleSideBar()
|
||||
@@ -98,11 +105,15 @@ function logout() {
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
const emits = defineEmits(['setLayout'])
|
||||
const emits = defineEmits(['setLayout', 'openSearch'])
|
||||
function setLayout() {
|
||||
emits('setLayout')
|
||||
}
|
||||
|
||||
function openSearch() {
|
||||
emits('openSearch')
|
||||
}
|
||||
|
||||
async function toggleTheme(event) {
|
||||
const x = event?.clientX || window.innerWidth / 2
|
||||
const y = event?.clientY || window.innerHeight / 2
|
||||
@@ -152,35 +163,46 @@ async function toggleTheme(event) {
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: 50px;
|
||||
height: 56px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: var(--navbar-bg);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
box-shadow: 0 1px 4px rgba(15, 34, 58, 0.04);
|
||||
border-bottom: 1px solid var(--sf-border-soft, #eef0f2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding: 0 8px;
|
||||
gap: 4px;
|
||||
padding: 0 12px 0 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
color: var(--sf-text-3, #5b616e);
|
||||
transition: background 0.15s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
margin-right: 4px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
background: var(--sf-hover, rgba(15, 17, 21, 0.045));
|
||||
}
|
||||
|
||||
:deep(div) {
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
|
||||
:deep(.hamburger) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
flex-shrink: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.topmenu-container {
|
||||
@@ -197,16 +219,11 @@ async function toggleTheme(event) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.errLog-container {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
margin-left: auto;
|
||||
min-width: 0;
|
||||
flex-shrink: 1;
|
||||
@@ -220,75 +237,94 @@ async function toggleTheme(event) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 34px;
|
||||
height: 34px;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: var(--el-text-color-regular, #5a5e66);
|
||||
border-radius: 8px;
|
||||
font-size: 17px;
|
||||
color: var(--sf-text-3, #5b616e);
|
||||
vertical-align: middle;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background 0.3s, color 0.2s;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.035);
|
||||
color: var(--el-color-primary, #008596);
|
||||
background: var(--sf-hover, rgba(15, 17, 21, 0.045));
|
||||
color: var(--sf-text-1, #0f1115);
|
||||
}
|
||||
}
|
||||
|
||||
&.theme-switch-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
transition: transform 0.3s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
.search-trigger {
|
||||
gap: 8px;
|
||||
width: 248px;
|
||||
height: 34px;
|
||||
margin-right: 8px;
|
||||
padding: 0 8px 0 10px;
|
||||
border: 1px solid var(--sf-border-strong, #dde0e4);
|
||||
background: var(--sf-surface, #fff);
|
||||
color: var(--sf-text-4, #6b717d);
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
justify-content: flex-start;
|
||||
transition: border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
border-color: #c3c8cf;
|
||||
}
|
||||
|
||||
.search-trigger__text {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.search-trigger__kbd {
|
||||
padding: 1px 6px;
|
||||
border: 1px solid var(--sf-border, #e7e9ec);
|
||||
border-radius: 5px;
|
||||
font-family: var(--sf-font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--sf-text-4, #6b717d);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 4px;
|
||||
padding: 0 4px;
|
||||
margin-left: 4px;
|
||||
padding: 0;
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 20px;
|
||||
transition: background 0.25s ease;
|
||||
padding: 2px 8px 2px 2px;
|
||||
border-radius: 18px;
|
||||
transition: background 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
background: var(--sf-hover, rgba(15, 17, 21, 0.045));
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 1.5px solid var(--el-color-primary-light-7, #b2e0e6);
|
||||
box-shadow: 0 2px 6px rgba(0, 133, 150, 0.12);
|
||||
border: 1px solid var(--sf-border, #e7e9ec);
|
||||
}
|
||||
|
||||
.user-nickname {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
color: var(--sf-text-1, #0f1115);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,7 +333,20 @@ async function toggleTheme(event) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
margin-right: 6px;
|
||||
font-size: 14px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.navbar .right-menu .search-trigger {
|
||||
width: auto;
|
||||
|
||||
.search-trigger__text,
|
||||
.search-trigger__kbd {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,6 +364,11 @@ async function toggleTheme(event) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.search-trigger {
|
||||
margin-right: 2px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.avatar-container .avatar-wrapper .user-nickname {
|
||||
display: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user