This commit is contained in:
zlwu committed 2026-06-30 23:44:22 +08:00
1 parent d84f4b944c
commit 7c838cfb2d
249 files changed
+50600 -18556

No files matched your search

+1 -1
View File
@@ -155,7 +155,7 @@ watch(dialogVisible, (val) => {
const queryParams = ref<ContactQuery>({
pageNum: 1,
pageSize: 10,
pageSize: 20,
customerId: props.customerId,
contactName: undefined,
mobile: undefined,
@@ -155,7 +155,7 @@ watch(dialogVisible, (val) => {
const queryParams = ref<Record<string, any>>({
pageNum: 1,
pageSize: 10,
pageSize: 20,
customerName: undefined,
customerNo: undefined,
customerType: undefined,
@@ -14,6 +14,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig'
const props = defineProps<{
total: number
@@ -33,7 +34,7 @@ const pageModel = computed({
})
const limitModel = computed({
get: () => props.limit ?? 10,
get: () => props.limit ?? DEFAULT_LIST_PAGE_SIZE,
set: (val: number) => emit('update:limit', val)
})
@@ -171,7 +171,7 @@ watch(dialogVisible, (val) => {
const queryParams = ref<OpportunityQuery>({
pageNum: 1,
pageSize: 10,
pageSize: 20,
opportunityName: undefined,
opportunityNo: undefined,
customerId: props.customerId,
+1 -1
View File
@@ -181,7 +181,7 @@ watch(dialogVisible, (val) => {
const queryParams = ref<QuoteQuery>({
pageNum: 1,
pageSize: 10,
pageSize: 20,
quoteNo: undefined,
quoteTitle: undefined,
customerName: undefined,
+1 -1
View File
@@ -114,7 +114,7 @@ watch(dialogVisible, (val) => {
const queryParams = ref({
pageNum: 1,
pageSize: 10,
pageSize: 20,
keyword: undefined as string | undefined
})
@@ -207,7 +207,7 @@ const planCountMap = ref<Record<string, number>>({})
const queryParams = reactive<ContractQuery>({
pageNum: 1,
pageSize: 10,
pageSize: 20,
contractNo: '',
contractName: '',
customerName: '',
@@ -7,7 +7,11 @@
:loading="loading"
width="1200px"
modal-class="order-module-dialog-mask"
/>
>
<template #hero-actions>
<slot name="hero-actions" />
</template>
</SystemViewDialog>
</template>
<script setup lang="ts">
@@ -7,7 +7,11 @@
:loading="loading"
width="1200px"
modal-class="order-module-dialog-mask"
/>
>
<template #hero-actions>
<slot name="hero-actions" />
</template>
</SystemViewDialog>
</template>
<script setup lang="ts">
@@ -7,7 +7,11 @@
:loading="loading"
width="1200px"
modal-class="order-module-dialog-mask"
/>
>
<template #hero-actions>
<slot name="hero-actions" />
</template>
</SystemViewDialog>
</template>
<script setup lang="ts">
@@ -0,0 +1,156 @@
<!-- 列表工具栏右侧:刷新 + 列显隐(勾选持久化由 usePersistedListColumns 负责) -->
<template>
<div class="list-toolbar-end">
<el-tooltip content="刷新列表" placement="top">
<el-button
class="list-toolbar-end-btn"
:loading="loading"
aria-label="刷新列表"
@click="emit('refresh')"
>
<el-icon><Refresh /></el-icon>
</el-button>
</el-tooltip>
<el-popover
v-if="showColumns"
placement="bottom-end"
trigger="click"
:width="300"
popper-class="list-column-setting-popover"
>
<template #reference>
<el-button class="list-toolbar-end-btn" aria-label="列设置">
<el-icon><Setting /></el-icon>
</el-button>
</template>
<div class="list-column-setting">
<div class="list-column-setting-head">
<span class="list-column-setting-title">列展示</span>
<button type="button" class="btn-link list-column-setting-reset" @click="handleReset">
恢复默认
</button>
</div>
<el-checkbox
v-model="checkAllProxy"
:indeterminate="isIndeterminate"
class="list-column-setting-check-all"
>
全选
</el-checkbox>
<el-scrollbar max-height="320px" class="list-column-setting-scroll">
<div class="list-column-setting-list">
<el-checkbox
v-for="col in columnDefs"
:key="col.prop"
:model-value="visibleColumns.includes(col.prop)"
:disabled="col.disabled"
class="list-column-setting-item"
@update:model-value="(val) => handleColumnToggle(col.prop, !!val)"
>
{{ col.label }}
</el-checkbox>
</div>
</el-scrollbar>
</div>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Refresh, Setting } from '@element-plus/icons-vue'
import type { ListColumnDef } from '@/composables/usePersistedListColumns'
defineOptions({ name: 'ListToolbarEndActions' })
const props = withDefaults(
defineProps<{
loading?: boolean
columnDefs?: ListColumnDef[]
visibleColumns?: string[]
checkAll?: boolean
isIndeterminate?: boolean
showColumns?: boolean
}>(),
{
loading: false,
columnDefs: () => [],
visibleColumns: () => [],
checkAll: false,
isIndeterminate: false,
showColumns: undefined
}
)
const emit = defineEmits<{
refresh: []
'update:visibleColumns': [value: string[]]
'update:checkAll': [value: boolean]
resetColumns: []
}>()
const showColumns = computed(() => {
if (props.showColumns !== undefined) return props.showColumns
return props.columnDefs.length > 0
})
const checkAllProxy = computed({
get: () => props.checkAll,
set: (value: boolean) => emit('update:checkAll', value)
})
const handleColumnToggle = (prop: string, visible: boolean) => {
const next = new Set(props.visibleColumns)
if (visible) {
next.add(prop)
} else {
next.delete(prop)
}
const ordered = props.columnDefs
.filter((col) => col.disabled || next.has(col.prop))
.map((col) => col.prop)
emit('update:visibleColumns', ordered)
}
const handleReset = () => {
emit('resetColumns')
}
</script>
<style scoped lang="scss">
.list-toolbar-end-btn.el-button {
--el-button-border-color: transparent;
--el-button-hover-border-color: transparent;
--el-button-active-border-color: transparent;
width: 36px;
min-width: 36px;
height: 36px;
padding: 0;
border-radius: 8px;
color: var(--mint-text-muted);
border: none !important;
box-shadow: none;
background: transparent;
.el-icon {
font-size: 16px;
}
&:hover,
&:focus-visible {
color: var(--mint-primary-dark);
border: none !important;
box-shadow: none;
background: var(--mint-primary-bg);
}
&:active {
border: none !important;
box-shadow: none;
}
}
</style>
@@ -13,6 +13,9 @@
@closed="handleClosed"
>
<div class="carrier-view-body" v-loading="loading">
<div v-if="$slots['hero-actions']" class="carrier-view-hero-actions">
<slot name="hero-actions" />
</div>
<section class="carrier-view-top">
<h3 class="carrier-view-block-title">承运商信息</h3>
<ViewKvTable v-if="carrier" :fields="carrierViewFields" mode="triple" />
@@ -78,6 +81,7 @@
<script setup lang="ts">
import { Close } from '@element-plus/icons-vue'
import { carrierApi, vehicleApi, type Carrier } from '@/api/pl'
import { pickBxList } from '@/utils/http/bx'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import PlVehicleViewPanel from '@/components/business/pl-vehicle-view-panel/index.vue'
import ViewKvTable from '@/components/business/system-view-dialog/ViewKvTable.vue'
@@ -170,10 +174,10 @@ async function loadDetail(carrierId: string) {
try {
const [carrierRes, vehicleListRes] = await Promise.all([
carrierApi.get(carrierId),
vehicleApi.list({ carrierId })
vehicleApi.list({ carrierId, page: 1, pageSize: 100 })
])
carrier.value = ((carrierRes.data ?? carrierRes) || null) as Carrier | null
const vehicles = ((vehicleListRes.data ?? vehicleListRes) || []) as { id: string }[]
const vehicles = pickBxList<{ id: string }>(vehicleListRes)
vehicleBundles.value = await loadVehicleViewBundles(vehicles.map(item => item.id))
activeTab.value = vehicleBundles.value[0]?.detail.id || ''
} catch {
@@ -199,6 +203,16 @@ function handleClosed() {
min-height: 120px;
}
.carrier-view-hero-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding-bottom: 16px;
border-bottom: 1px solid #e2e8f0;
}
.carrier-view-block-title {
margin: 0 0 12px;
font-size: 15px;
@@ -81,7 +81,7 @@ function buildCertViewFields(cert: CertRead): ViewField[] {
.view-empty-hint {
margin: 0;
font-size: 13px;
color: #000;
color: var(--mint-text-muted);
line-height: 1.5;
}
@@ -11,15 +11,20 @@
>
<div v-loading="loading" class="view-dialog-body">
<div v-if="settlement" class="view-hero">
<div class="view-hero-main">
<h3 class="view-hero-title">{{ settlement.settlementNo }}</h3>
<el-tag :type="getSettlementStatusTagType(settlement.settlementStatus)" size="small">
{{ getSettlementStatusLabel(settlement.settlementStatus) }}
</el-tag>
<div class="view-hero-top">
<div class="view-hero-main">
<h3 class="view-hero-title">{{ settlement.settlementNo }}</h3>
<el-tag :type="getSettlementStatusTagType(settlement.settlementStatus)" size="small">
{{ getSettlementStatusLabel(settlement.settlementStatus) }}
</el-tag>
</div>
<div class="view-hero-summary">
<span class="view-hero-label">运费合计</span>
<span class="view-hero-amount">{{ formatAmount(settlement.totalFreight) }}</span>
</div>
</div>
<div class="view-hero-summary">
<span class="view-hero-label">运费合计</span>
<span class="view-hero-amount">{{ formatAmount(settlement.totalFreight) }}</span>
<div v-if="$slots['hero-actions']" class="view-hero-actions">
<slot name="hero-actions" />
</div>
</div>
@@ -225,9 +230,8 @@ defineExpose({ open })
.view-hero {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
flex-direction: column;
gap: 12px;
padding: 16px;
margin-bottom: 16px;
border-radius: 10px;
@@ -235,6 +239,21 @@ defineExpose({ open })
border: 1px solid #a7f3d0;
}
.view-hero-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.view-hero-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.view-hero-main {
display: flex;
align-items: center;
@@ -681,7 +681,7 @@ function resetState() {
async function loadMasterData() {
const [vehicleRes, carrierRes] = await Promise.all([
vehicleApi.list({ vehicleStatus: 'available', excludeIneligibleCarrier: true }),
carrierApi.list({ status: '1' })
carrierApi.list({ status: '1', page: 1, pageSize: 100 })
])
vehicleList.value = pickBxList<Vehicle>(vehicleRes)
carrierList.value = pickBxList<Carrier>(carrierRes)
@@ -792,7 +792,7 @@ async function handleSubmit() {
const certMessage = buildMissingHazardCertMessage(products.value)
if (certMessage) {
await ElMessageBox.alert(`${certMessage}。请先上传购买证和运输证。`, '无法安排运输', {
await ElMessageBox.alert(`${certMessage}。请先上传购买证和合法使用证明。`, '无法安排运输', {
type: 'warning'
})
return
@@ -19,7 +19,7 @@
type="info"
:closable="false"
show-icon
title="易制毒或易制爆产品须上传购买证、运输证;安排运输时将校验是否齐全。"
title="易制毒或易制爆产品须上传购买证、合法使用证明;安排运输时将校验是否齐全。"
class="cert-tip"
/>
@@ -40,12 +40,12 @@
hint="支持图片、PDF 等,上传购买证"
/>
</el-form-item>
<el-form-item label="运输证" required>
<el-form-item label="合法使用证明" required>
<AttachmentUploadField
v-model="item.transportCertUrl"
folder="pl/plan-cert"
:limit="1"
hint="支持图片、PDF 等,上传运输证"
hint="支持图片、PDF 等,上传合法使用证明"
/>
</el-form-item>
</div>
@@ -133,7 +133,7 @@ async function handleSubmit() {
p => !p.purchaseCertUrl?.trim() || !p.transportCertUrl?.trim()
)
if (incomplete.length) {
ElMessage.warning('请为每个危化品产品上传购买证和运输证')
ElMessage.warning('请为每个危化品产品上传购买证和合法使用证明')
return
}
@@ -793,7 +793,7 @@ async function loadMasterData() {
try {
const [vehicleRes, carrierRes] = await Promise.all([
vehicleApi.list({ vehicleStatus: 'available', excludeIneligibleCarrier: true }),
carrierApi.list({ status: '1' })
carrierApi.list({ status: '1', page: 1, pageSize: 100 })
])
vehicleList.value = (vehicleRes.data ?? vehicleRes) || []
carrierList.value = (carrierRes.data ?? carrierRes) || []
@@ -27,7 +27,7 @@
disabled
/>
<span v-else class="pl-plan-list-cert-cell__missing">未上传</span>
<span class="pl-plan-list-cert-cell__cert-label">运输证</span>
<span class="pl-plan-list-cert-cell__cert-label">合法使用证明</span>
</div>
</div>
</div>
@@ -52,6 +52,10 @@
</template>
</section>
<div v-if="$slots['hero-actions']" class="pl-plan-view-hero-actions">
<slot name="hero-actions" />
</div>
<PlPlanViewTabs v-if="planId" ref="tabsRef" :plan-id="planId" />
<DbPoundSlipQrcodeDialog
@@ -174,6 +178,15 @@ function handleClosed() {
justify-content: flex-end;
}
.pl-plan-view-hero-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
margin-bottom: 12px;
}
.pl-plan-arrange-summary {
margin-bottom: 12px;
padding: 12px 16px;
@@ -38,7 +38,7 @@
</dd>
</div>
<div class="pl-plan-kv">
<dt>运输证</dt>
<dt>合法使用证明</dt>
<dd>
<AttachmentUploadField
v-if="item.transportCertUrl"
@@ -781,14 +781,14 @@
.pl-plan-form-empty-hint {
margin: 0;
font-size: 13px;
color: #64748b;
color: var(--mint-text-muted);
}
.pl-plan-view-remark {
margin: 0;
font-size: 13px;
font-weight: 600;
color: #000;
color: var(--mint-text);
line-height: 1.5;
word-break: break-word;
white-space: pre-wrap;
@@ -810,7 +810,7 @@
dt {
margin: 0 0 4px;
font-size: 13px;
color: #64748b;
color: var(--mint-text-muted);
}
dd {
@@ -943,7 +943,7 @@
margin-bottom: 8px;
font-size: 13px;
font-weight: 500;
color: #64748b;
color: var(--mint-text-muted);
}
.pl-plan-cert-block {
@@ -1010,7 +1010,7 @@
.pl-plan-site-feedback-batch {
font-size: 12px;
color: #64748b;
color: var(--mint-text-muted);
}
.pl-plan-site-feedback-attachments {
@@ -1042,7 +1042,7 @@
margin: 12px 0 8px;
font-size: 12px;
font-weight: 600;
color: #64748b;
color: var(--mint-text-muted);
}
.pl-plan-dibang-pending {
File diff suppressed because it is too large. Load diff
@@ -69,15 +69,15 @@
dt {
margin: 0;
font-size: 13px;
font-weight: 400;
color: #000;
font-weight: 500;
color: var(--mint-text-muted);
line-height: 1.4;
}
dd {
margin: 0;
font-weight: 600;
color: #000;
color: var(--mint-text);
word-break: break-word;
line-height: 1.5;
}
@@ -403,7 +403,7 @@
.view-hero-meta {
margin: 0;
font-size: 13px;
color: #000;
color: var(--mint-text-muted);
line-height: 1.5;
}
@@ -429,8 +429,8 @@
.view-field-label {
margin: 0 0 8px;
font-size: 13px;
font-weight: 400;
color: #000;
font-weight: 500;
color: var(--mint-text-muted);
line-height: 1.4;
}
@@ -459,7 +459,7 @@
.view-field-group .view-empty-hint {
margin: 0;
font-size: 13px;
color: #000;
color: var(--mint-text-muted);
line-height: 1.5;
}
@@ -3,7 +3,7 @@
height: 100vh;
user-select: none;
scrollbar-width: none;
border-right: none;
border-right: 1px solid var(--mint-border, #d9e8e2);
background: var(--mint-surface, #fff);
&.layout-sidebar-portal {
@@ -106,18 +106,18 @@
overflow: hidden;
background: var(--mint-surface, #fff);
// 长菜单名完整展示:侧栏宽度不变,内容区可横向滚动
// 长菜单名在侧栏内省略展示(对齐 zkxw Fresh Mint 侧栏)
:deep(.el-scrollbar__wrap) {
overflow-x: auto !important;
overflow-x: hidden !important;
}
:deep(.el-scrollbar__view) {
width: max-content;
min-width: 100%;
width: 100%;
min-width: 0;
}
:deep(.el-scrollbar__bar.is-horizontal) {
height: 4px;
display: none;
}
@media only screen and (width <= 640px) {
@@ -10,16 +10,23 @@ $popup-menu-padding: 8px;
$popup-menu-margin: 5px;
$popup-menu-radius: 6px;
// 通用菜单项样式(min-width 保证短标题仍铺满侧栏;width: max-content 允许长标题撑开以配合横向滚动)
// 通用菜单项样式(宽度铺满侧栏,长标题省略)
@mixin menu-item-base {
width: max-content;
min-width: calc(100% - 12px);
margin-left: 6px;
width: 100%;
min-width: 0;
margin-left: 0;
border-radius: 8px;
.menu-icon {
margin-left: -5px;
}
.menu-name {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
}
// 通用 hover 样式
@@ -31,17 +38,26 @@ $popup-menu-radius: 6px;
}
// 通用选中样式
@mixin menu-active($color, $bg-color, $icon-color: var(--theme-color)) {
@mixin menu-active($color, $bg-color, $icon-color: $color) {
.el-menu-item.is-active {
color: $color !important;
background-color: $bg-color;
font-weight: 600;
&:hover {
background-color: $bg-color !important;
}
.menu-icon {
.art-svg-icon {
color: $icon-color !important;
}
}
span,
.menu-name {
color: $color !important;
}
}
}
@@ -107,16 +123,8 @@ $popup-menu-radius: 6px;
// 菜单折叠样式
.menu-left-close {
.header {
.header-brand {
justify-content: center;
}
.header-brand-title {
display: none;
}
.logo {
margin: 0;
margin: 0 auto;
}
}
}
@@ -149,28 +157,44 @@ $popup-menu-radius: 6px;
// 菜单高度
.el-sub-menu__title,
.el-menu-item {
position: relative;
display: flex !important;
align-items: center;
min-width: 0;
height: $menu-height !important;
margin-bottom: 2px;
line-height: $menu-height !important;
overflow: visible !important;
overflow: hidden !important;
.menu-title-wrap {
position: relative;
display: flex;
flex: 1;
align-items: center;
min-width: 0;
padding-right: 28px;
}
.menu-name {
flex-shrink: 0;
flex-shrink: 1;
min-width: 0;
font-size: $menu-font-size !important;
font-weight: 500;
// Fresh Mint:菜单文字使用主文本色
color: var(--mint-text, #1e293b);
// Fresh Mint:默认菜单项为中性色(demo `.nav a`)
color: var(--mint-text-muted, #64748b);
text-rendering: geometricprecision;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.el-sub-menu > .el-sub-menu__title {
font-size: 12px !important;
font-weight: 700;
color: var(--mint-text, #1e293b) !important;
color: var(--mint-text-muted, #64748b) !important;
letter-spacing: 0.02em;
}
@@ -184,46 +208,48 @@ $popup-menu-radius: 6px;
.el-sub-menu .el-menu {
margin: 2px 0 6px 10px;
padding: 2px 0 2px 8px !important;
border-left: 2px solid var(--mint-border, #d9e8e2);
border-left: 2px solid var(--mint-border, #c5e0d4);
}
// 菜单折叠
.el-menu--collapse {
.el-sub-menu.is-active {
.el-sub-menu__title {
background-color: var(--primary, #10b981);
.menu-icon {
.art-svg-icon {
// 选中菜单图标颜色
color: var(--theme-color) !important;
color: #fff !important;
}
}
}
}
.el-menu-item.is-active {
background-color: var(--primary, #10b981);
color: #fff !important;
span,
.menu-name,
.menu-icon .art-svg-icon {
color: #fff !important;
}
}
}
// ---------------------- Design theme menu ----------------------
.el-menu-design {
@include theme-menu-base;
@include menu-active(
var(--mint-primary-dark, #059669),
var(--mint-primary-bg, #ecfdf5),
var(--mint-primary-dark, #059669)
);
@include menu-active(#fff, var(--primary, #10b981), #fff);
@include menu-hover($hover-bg-color);
.el-menu-item,
.el-sub-menu__title {
color: var(--mint-text, #1e293b) !important;
}
// 选中态:以浅底+图标强化为主,文字保持中性色(对齐 fresh-mint demo)
.el-menu-item.is-active span {
color: var(--mint-primary-dark, #059669) !important;
font-weight: 600 !important;
color: var(--mint-text-muted, #334155) !important;
}
.el-sub-menu__icon-arrow {
color: var(--mint-text);
color: var(--mint-text-muted, #64748b);
}
}
@@ -248,24 +274,25 @@ $popup-menu-radius: 6px;
}
.el-menu-item.is-active {
background-color: var(--mint-primary-bg, #ecfdf5);
color: var(--mint-primary-dark, #059669) !important;
background-color: var(--primary, #10b981);
color: #fff !important;
font-weight: 600;
span {
color: var(--mint-primary-dark, #059669) !important;
span,
.menu-name {
color: #fff !important;
font-weight: 600 !important;
}
.art-svg-icon {
color: var(--mint-primary-dark, #059669) !important;
color: #fff !important;
}
}
@include menu-hover($hover-bg-color);
.el-sub-menu__icon-arrow {
color: var(--mint-text);
color: var(--mint-text-muted, #64748b);
}
}
}
@@ -290,6 +317,22 @@ $popup-menu-radius: 6px;
@include popup-menu-base(var(--art-gray-200), var(--art-gray-900), var(--art-gray-200));
}
.menu-left-design-popper,
.menu-left-light-popper {
.el-menu--popup {
.el-menu-item.is-active {
color: #fff !important;
background-color: var(--primary, #10b981) !important;
span,
.menu-name,
.art-svg-icon {
color: #fff !important;
}
}
}
}
// 暗黑模式菜单样式
.dark {
.el-menu--vertical,
@@ -304,8 +347,19 @@ $popup-menu-radius: 6px;
color: var(--art-gray-800) !important;
}
// 选中的文字颜色跟图标颜色
.el-menu-item.is-active {
// 选中的文字颜色跟图标颜色(design / light 为深绿底白字)
.el-menu-design,
.el-menu-light {
.el-menu-item.is-active {
span,
.menu-name,
.menu-icon .art-svg-icon {
color: #fff !important;
}
}
}
.el-menu-dark .el-menu-item.is-active {
span,
.menu-icon .art-svg-icon {
color: var(--theme-color) !important;
@@ -49,22 +49,25 @@
.portal-header {
box-sizing: border-box;
display: flex;
gap: 16px;
gap: 12px;
align-items: center;
width: 100%;
height: 72px;
padding: 0 20px;
height: 56px;
padding: 0 var(--mint-content-padding, 24px);
user-select: none;
background: var(--default-bg-color, #fff);
border-bottom: 1px solid var(--art-card-border, #d9e8e2);
background: var(--mint-surface, #fff);
border-bottom: 1px solid var(--mint-border, #d9e8e2);
}
.portal-header-brand {
display: flex;
flex-shrink: 0;
gap: 10px;
gap: 12px;
align-items: center;
margin-right: 12px;
padding-right: 16px;
cursor: pointer;
border-right: 1px solid var(--mint-border, #d9e8e2);
}
.portal-header-logo {
@@ -72,18 +75,19 @@
}
.portal-header-title {
max-width: 180px;
margin: 0;
font-size: 18px;
font-weight: 600;
line-height: 1.2;
font-size: 16px;
font-weight: 700;
line-height: 1.35;
color: var(--mint-text, #1e293b);
white-space: nowrap;
white-space: normal;
}
.portal-header-nav {
flex: 1;
min-width: 0;
margin-left: 24px;
margin-left: 8px;
}
.portal-header-actions {
@@ -95,9 +95,9 @@
.portal-top-nav-list {
display: flex;
flex-wrap: nowrap;
gap: 10px;
gap: 4px;
align-items: center;
min-height: 56px;
min-height: 48px;
padding: 4px 0;
}
@@ -106,11 +106,13 @@
display: inline-flex;
flex-direction: column;
flex-shrink: 0;
gap: 4px;
gap: 2px;
align-items: center;
justify-content: center;
min-width: 72px;
padding: 8px 12px;
min-width: 64px;
height: 48px;
padding: 4px 10px;
margin: 0 2px;
cursor: pointer;
background: transparent;
border: none;
@@ -120,27 +122,24 @@
color 0.2s ease;
&__icon {
font-size: 22px;
font-size: 18px;
line-height: 1;
color: var(--mint-text-muted, #64748b);
}
&__label {
max-width: 88px;
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
line-height: 1.3;
color: var(--mint-text, #1e293b);
font-size: 13px;
line-height: 1.2;
color: var(--mint-text-muted, #64748b);
text-align: center;
white-space: nowrap;
}
&:hover:not(.is-active) {
background: var(--primary-bg, #ecfdf5);
.portal-top-nav-card__icon,
.portal-top-nav-card__label {
color: var(--primary-dark, #059669);
}
}
&.is-active {
@@ -149,6 +148,7 @@
.portal-top-nav-card__icon,
.portal-top-nav-card__label {
color: #fff;
font-weight: 600;
}
}
}
@@ -480,7 +480,7 @@
<style scoped>
.worktab-strip {
position: relative;
padding: 0 24px 12px !important;
padding: 0 24px 4px !important;
background: var(--mint-surface);
overflow: visible !important;
}
@@ -495,7 +495,7 @@
z-index: 1;
max-width: 220px;
padding: 10px 16px !important;
margin-bottom: -11px;
margin-bottom: -7px;
overflow: hidden;
font-size: 13px;
font-weight: 600;
@@ -0,0 +1,39 @@
<template>
<div
class="filter-date-shortcuts list-toolbar-date-shortcuts"
role="group"
:aria-label="ariaLabel"
>
<el-button
v-for="item in shortcutItems"
:key="item.type"
size="small"
class="btn-ghost date-shortcut-btn"
:class="{ 'is-active': active === item.type }"
@click="emit('change', item.type)"
>
{{ item.label }}
</el-button>
</div>
</template>
<script setup lang="ts">
import type { DateShortcutType } from '@/composables/useListDateShortcut'
defineProps<{
active: DateShortcutType
ariaLabel?: string
}>()
const emit = defineEmits<{
change: [type: DateShortcutType]
}>()
const shortcutItems: Array<{ type: DateShortcutType; label: string }> = [
{ type: 'all', label: '全部' },
{ type: 'yesterday', label: '昨日' },
{ type: 'today', label: '今日' },
{ type: 'tomorrow', label: '明日' },
{ type: 'week', label: '本周' }
]
</script>
@@ -169,7 +169,7 @@
// 默认分页常量
const DEFAULT_PAGINATION_OPTIONS: PaginationOptions = {
pageSizes: [10, 20, 30, 50, 100],
align: 'center',
align: 'right',
background: true,
layout: layout.value,
hideOnSinglePage: false,