提交
This commit is contained in:
1 parent
d84f4b944c
commit
7c838cfb2d
249 files changed
+50600
-18556
No files matched your search
@@ -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,
|
||||
|
||||
@@ -181,7 +181,7 @@ watch(dialogVisible, (val) => {
|
||||
|
||||
const queryParams = ref<QuoteQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
quoteNo: undefined,
|
||||
quoteTitle: undefined,
|
||||
customerName: undefined,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user