feat/ui: 优化订单列表和详情页面,更新登录界面

- 移除 components.d.ts 中未使用的 VanCheckbox 组件引用
- 在 Detail 页面添加常用审批意见标签功能
- 调整 List 页面样式,优化搜索栏设计- 更新 Login 页面布局和样式,移除不必要的元素
master
chenhao 2025-08-28 17:33:10 +08:00
parent 411253a277
commit 92dd433eee
4 changed files with 236 additions and 99 deletions

2
components.d.ts vendored
View File

@ -11,7 +11,6 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanCheckbox: typeof import('vant/es')['Checkbox']
VanEmpty: typeof import('vant/es')['Empty']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
@ -26,5 +25,6 @@ declare module 'vue' {
VanSteps: typeof import('vant/es')['Steps']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VanTag: typeof import('vant/es')['Tag']
}
}

View File

@ -372,7 +372,7 @@
v-model:show="approvalDialogVisible"
position="bottom"
round
:style="{ height: '40%' }"
:style="{ height: '50%' }"
>
<div class="approval-dialog">
<div class="dialog-header">
@ -380,6 +380,25 @@
<van-icon name="cross" @click="approvalDialogVisible = false"/>
</div>
<div class="dialog-body">
<!-- 默认意见标签 -->
<div class="opinion-tags">
<div class="tags-title">常用意见</div>
<div class="tags-container">
<van-tag
v-for="tag in getOpinionTags()"
:key="tag"
:type="selectedTag === tag ? 'primary' : 'default'"
size="medium"
@click="selectTag(tag)"
class="opinion-tag"
>
{{ tag }}
</van-tag>
</div>
</div>
<!-- 意见输入框 -->
<div class="opinion-input">
<van-field
v-model="approvalOpinion"
type="textarea"
@ -390,6 +409,7 @@
show-word-limit
/>
</div>
</div>
<div class="dialog-footer">
<van-button
type="primary"
@ -432,6 +452,7 @@ const approvalDialogVisible = ref(false)
const approvalOpinion = ref('')
const currentApprovalStatus = ref<ApprovalStatus>(3)
const submitting = ref(false)
const selectedTag = ref('')
// Tab
const activeTab = ref('order')
@ -542,9 +563,48 @@ const previewFile = (file: AttachmentFile) => {
const showApprovalDialog = (status: ApprovalStatus) => {
currentApprovalStatus.value = status
approvalOpinion.value = ''
selectedTag.value = ''
approvalDialogVisible.value = true
}
//
const getOpinionTags = () => {
if (currentApprovalStatus.value === 0) {
//
return [
'资料不齐全,请补充相关文件',
'订单金额需要重新核实',
'客户信息有误,请修正',
'产品配置不符合要求',
'需要提供更多技术细节',
'合同条款需要调整'
]
} else {
//
return [
'审核通过,订单信息完整',
'符合公司政策,同意执行',
'客户资质良好,建议通过',
'产品配置合理,批准发货',
'风险可控,同意此订单',
'经审查无误,予以批准'
]
}
}
//
const selectTag = (tag: string) => {
if (selectedTag.value === tag) {
//
selectedTag.value = ''
approvalOpinion.value = ''
} else {
//
selectedTag.value = tag
approvalOpinion.value = tag
}
}
//
const submitApproval = async () => {
if (!currentOrder.value || !currentOrder.value.todo) {
@ -846,6 +906,7 @@ onMounted(async () => {
.dialog-body {
flex: 1;
padding: var(--spacing-lg);
overflow-y: auto;
}
.dialog-footer {
@ -854,6 +915,45 @@ onMounted(async () => {
}
}
//
.opinion-tags {
margin-bottom: var(--spacing-lg);
.tags-title {
font-size: 14px;
color: var(--text-color-secondary);
margin-bottom: var(--spacing-md);
font-weight: 500;
}
.tags-container {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-sm);
.opinion-tag {
cursor: pointer;
transition: all 0.2s ease;
&:hover {
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
}
}
}
}
.opinion-input {
.van-field {
border: 1px solid var(--divider-color);
border-radius: var(--border-radius-sm);
background: var(--background-color-secondary);
}
}
:deep(.van-steps--vertical) {
padding-left: 0;
}

View File

@ -1,12 +1,22 @@
<template>
<div class="order-list-page">
<!-- 搜索栏 -->
<div class="search-container">
<van-search
v-model="searchKeyword"
placeholder="搜索订单编号、客户名称"
@search="handleSearch"
@clear="handleClear"
/>
class="custom-search"
>
<template #left-icon>
<svg class="search-icon" viewBox="0 0 24 24" fill="none">
<circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/>
<path d="M21 21L16.65 16.65" stroke="currentColor" stroke-width="2"/>
</svg>
</template>
</van-search>
</div>
<!-- 下拉刷新 -->
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
@ -134,39 +144,25 @@ onMounted(() => {
<style lang="scss" scoped>
.order-list-page {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 20px;
background: #ffffff;
padding: 16px;
box-sizing: border-box;
position: relative;
}
.order-item {
background: white;
background: #ffffff;
margin-bottom: 16px;
padding: 20px;
padding: 16px;
cursor: pointer;
transition: all 0.2s;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 4px;
background: linear-gradient(90deg, #1989fa, #07c160);
}
transition: all 0.2s ease;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
&:active {
transform: translateY(2px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
&:hover {
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
transform: translateY(1px);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
}
@ -182,35 +178,39 @@ onMounted(() => {
.order-code {
font-size: 16px;
font-weight: 600;
color: #333;
color: #333333;
}
.status-tag {
font-size: 12px;
padding: 4px 10px;
border-radius: 20px;
padding: 4px 12px;
border-radius: 12px;
font-weight: 500;
&.pending {
background-color: #FFF7E6;
color: #FA8C16;
background: #FFF3E0;
color: #FF9800;
border: 1px solid #FFE0B2;
}
&.approved {
background-color: #F6FFED;
color: #52C41A;
background: #E8F5E8;
color: #4CAF50;
border: 1px solid #C8E6C9;
}
&.rejected {
background-color: #FFF2F0;
color: #FF4D4F;
background: #FFEBEE;
color: #F44336;
border: 1px solid #FFCDD2;
}
}
.order-info {
.info-row {
display: flex;
margin-bottom: 12px;
margin-bottom: 8px;
align-items: center;
&:last-child {
margin-bottom: 0;
@ -218,19 +218,22 @@ onMounted(() => {
.label {
width: 80px;
color: #666;
color: #666666;
font-size: 14px;
font-weight: 400;
flex-shrink: 0;
}
.value {
flex: 1;
color: #333;
color: #333333;
font-size: 14px;
font-weight: 400;
word-break: break-all;
line-height: 1.4;
&.amount {
color: #FF6600;
color: #1976D2;
font-weight: 600;
}
}
@ -238,31 +241,71 @@ onMounted(() => {
}
.empty-state {
padding: 60px 20px;
padding: 80px 20px;
text-align: center;
position: relative;
:deep(.van-empty) {
.van-empty__image {
width: 120px;
height: 120px;
width: 160px;
height: 160px;
filter: drop-shadow(0 8px 32px rgba(102, 126, 234, 0.2));
animation: float 3s ease-in-out infinite;
}
.van-empty__description {
font-size: 16px;
color: #666;
font-size: 18px;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
margin-top: 24px;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
}
}
//
.search-container {
position: relative;
z-index: 10;
margin-bottom: 20px;
}
//
:deep(.van-search) {
margin-bottom: 16px;
border-radius: 12px;
:deep(.custom-search) {
border-radius: 16px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
&:focus-within {
transform: translateY(-2px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
}
.van-search__content {
background: white;
background: transparent;
padding: 12px 16px;
.van-field__control {
font-size: 15px;
font-weight: 500;
color: #333;
&::placeholder {
color: #999;
font-weight: normal;
}
}
}
}
.search-icon {
width: 20px;
height: 20px;
color: #666;
margin-right: 8px;
}
</style>

View File

@ -4,12 +4,31 @@
<div class="login-header">
<div class="logo-placeholder">
<svg class="logo-icon" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#1989fa" />
<path d="M30,50 L45,65 L70,35" stroke="white" stroke-width="8" fill="none" />
<!-- 立体盒子效果 -->
<defs>
<linearGradient id="topFace" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#4A90E2;stop-opacity:1" />
<stop offset="100%" style="stop-color:#357ABD;stop-opacity:1" />
</linearGradient>
<linearGradient id="leftFace" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#357ABD;stop-opacity:1" />
<stop offset="100%" style="stop-color:#2E6B9D;stop-opacity:1" />
</linearGradient>
<linearGradient id="rightFace" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#2E6B9D;stop-opacity:1" />
<stop offset="100%" style="stop-color:#1E4A6B;stop-opacity:1" />
</linearGradient>
</defs>
<!-- 立体盒子 -->
<!-- 顶面 -->
<polygon points="20,35 50,20 80,35 50,50" fill="url(#topFace)" />
<!-- 左面 -->
<polygon points="20,35 50,50 50,80 20,65" fill="url(#leftFace)" />
<!-- 右面 -->
<polygon points="50,50 80,35 80,65 50,80" fill="url(#rightFace)" />
</svg>
</div>
<h1 class="login-title">OMS</h1>
<p class="login-subtitle">Order Management System</p>
<h1 class="login-title">欢迎登录OMS</h1>
</div>
<van-form @submit="onSubmit" class="login-form">
@ -17,18 +36,11 @@
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="请输入用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
label="账号"
placeholder="请输入账号"
:rules="[{ required: true, message: '请填写账号' }]"
class="login-input"
>
<template #left-icon>
<svg class="input-icon" viewBox="0 0 100 100">
<circle cx="50" cy="35" r="15" fill="none" stroke="#1989fa" stroke-width="8" />
<path d="M25,85 Q50,65 75,85" stroke="#1989fa" stroke-width="8" fill="none" />
</svg>
</template>
</van-field>
/>
<van-field
v-model="password"
@ -38,33 +50,15 @@
placeholder="请输入密码"
:rules="[{ required: true, message: '请填写密码' }]"
class="login-input"
>
<template #left-icon>
<svg class="input-icon" viewBox="0 0 100 100">
<rect x="20" y="40" width="60" height="40" rx="5" fill="none" stroke="#1989fa" stroke-width="8" />
<circle cx="50" cy="25" r="10" fill="#1989fa" />
</svg>
</template>
</van-field>
/>
</van-cell-group>
<div class="login-options">
<van-checkbox v-model="rememberMe" name="rememberMe" checked-color="#1989fa">
记住密码
</van-checkbox>
<a href="javascript:void(0)" class="forgot-password">忘记密码</a>
</div>
<div class="login-button-container">
<van-button round block type="primary" native-type="submit" :loading="loading" class="login-button">
登录
</van-button>
</div>
</van-form>
<div class="login-footer">
<p class="footer-text">© 2025 订单管理系统 - 安全可靠的订单管理平台</p>
</div>
</div>
</div>
</template>