2026-08-04 21:01:39 +08:00
< script setup lang = "ts" >
import { computed , onMounted , reactive , ref , watch } from 'vue'
import { ElMessage , ElMessageBox , type FormInstance , type FormRules } from 'element-plus'
import { Boxes , Eye , Pencil , Plus , Trash2 , Warehouse as WarehouseIcon } from '@lucide/vue'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration'
import { listPlatformTenants as listPlatformCustomers , type PlatformTenantResource as PlatformCustomerResource } from '@/modules/iam'
import { listPlatformWarehouses , type PlatformWarehouseResource } from '@/modules/warehouses'
import { getApiErrorDetails , type ApiErrorDetails } from '@/shared/api/http'
import DataTable , { type DataTableColumn } from '@/shared/components/DataTable.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import QueryToolbar , { type QueryField , type QueryModel } from '@/shared/components/QueryToolbar.vue'
import {
createPlatformPallet ,
deletePlatformPallet ,
getPlatformPallet ,
listPlatformPallets ,
updatePlatformPallet ,
type PlatformPalletResource ,
type SavePlatformPalletRequest ,
} from '../api/platformPallets'
const access = useAccessPreviewStore ()
const customers = ref < PlatformCustomerResource [] >([])
const customerLoading = ref ( false )
const customerError = ref < ApiErrorDetails | null >( null )
const warehouses = ref < PlatformWarehouseResource [] >([])
const warehouseLoading = ref ( false )
const warehouseError = ref < ApiErrorDetails | null >( null )
const rows = ref < PlatformPalletResource [] >([])
const loading = ref ( false )
const loadError = ref < ApiErrorDetails | null >( null )
const page = ref ( 1 )
const pageSize = ref ( 20 )
const total = ref ( 0 )
const editorOpen = ref ( false )
const detailOpen = ref ( false )
const detail = ref < PlatformPalletResource | null >( null )
const detailLoading = ref ( false )
const saving = ref ( false )
const deletingIds = ref ( new Set < string >())
const formRef = ref < FormInstance >()
let warehouseSequence = 0
let palletSequence = 0
2026-08-05 15:54:59 +08:00
type PalletFilters = QueryModel & { warehouseId : string ; palletCode : string ; palletType : string }
type AppliedPalletFilters = Pick < PalletFilters , ' warehouseId ' | ' palletCode ' | ' palletType ' >
const filters = ref < PalletFilters >({ warehouseId : '' , palletCode : '' , palletType : '' })
const appliedFilters = ref < AppliedPalletFilters >({ warehouseId : '' , palletCode : '' , palletType : '' })
2026-08-04 21:01:39 +08:00
const palletTypeOptions = [ '木托盘' , '塑料托盘' , '金属托盘' , '纸托盘' , '免熏蒸托盘' ]
const queryFields = computed < QueryField [] >(() => [
{
key : 'warehouseId' ,
type : 'select' ,
2026-08-05 15:54:59 +08:00
width : 300 ,
2026-08-04 21:01:39 +08:00
placeholder : warehouseLoading . value ? '正在加载所属仓库' : warehouseError . value ? '所属仓库加载失败' : '全部仓库' ,
options : warehouses . value . map (( warehouse ) => ({
label : ` ${ warehouse . warehouseName } ( ${ warehouse . warehouseCode } ) `,
value : String ( warehouse . id ),
})),
props : {
filterable : true ,
2026-08-05 15:54:59 +08:00
disabled : contextLocked . value || warehouseLoading . value || Boolean ( warehouseError . value ),
2026-08-04 21:01:39 +08:00
'aria-label' : '所属仓库' ,
},
},
{ key : 'palletCode' , type : 'input' , width : 240 , placeholder : '托盘编码(模糊查询)' , props : { maxlength : 50 , 'aria-label' : '托盘编码' } },
{
key : 'palletType' ,
type : 'select' ,
width : 180 ,
placeholder : '全部托盘类型' ,
options : palletTypeOptions . map (( value ) => ({ label : value , value })),
props : { filterable : true , allowCreate : true , defaultFirstOption : true , 'aria-label' : '托盘类型' },
},
])
const emptyForm = () => ({ id : '' , customerId : '' , warehouseId : '' , palletCode : '' , palletType : '' , capacityCbm : null as number | null , remark : '' })
const form = reactive ( emptyForm ())
const rules : FormRules < typeof form > = {
2026-08-05 15:54:59 +08:00
warehouseId : [{ required : true , message : '请选择所属仓库' , trigger : 'change' }],
2026-08-04 21:01:39 +08:00
palletCode : [
{ required : true , message : '请输入托盘编码' , trigger : 'blur' },
{ max : 50 , message : '托盘编码不能超过 50 个字符' , trigger : 'blur' },
],
palletType : [
{ required : true , message : '请输入托盘类型' , trigger : 'blur' },
{ max : 32 , message : '托盘类型不能超过 32 个字符' , trigger : 'blur' },
],
capacityCbm : [{
validator : ( _rule , value , callback ) => {
if ( typeof value !== 'number' || ! Number . isFinite ( value ) || value <= 0 ) callback ( new Error ( '请输入大于 0 的托盘容积' ))
else callback ()
},
trigger : 'change' ,
}],
remark : [{ max : 500 , message : '备注不能超过 500 个字符' , trigger : 'blur' }],
}
const editorWarehouse = computed (() => warehouses . value . find (( item ) => String ( item . id ) === form . warehouseId ) || null )
const editorTitle = computed (() => form . id ? '编辑托盘' : '新增托盘' )
const editorPermission = computed (() => form . id ? 'platform:pallet:edit' : 'platform:pallet:create' )
const contextLocked = computed (() => editorOpen . value || detailOpen . value || saving . value || deletingIds . value . size > 0 )
const filtered = computed (() => Object . values ( appliedFilters . value ). some (( value ) => String ( value || '' ). trim ()))
const { captureBaseline } = useUnsavedWorkRegistration ({
key : 'pallet-editor' ,
label : editorTitle ,
isOpen : editorOpen ,
model : form ,
requiredPermission : editorPermission ,
})
const columns : DataTableColumn [] = [
{ key : 'actions' , label : '操作' , minWidth : 224 , fixed : 'left' , slotName : 'actions' },
{ key : 'pallet' , label : '托盘编码' , minWidth : 190 , slotName : 'pallet' },
{ prop : 'palletType' , label : '托盘类型' , minWidth : 140 },
{ key : 'capacity' , label : '托盘容积(m³)' , minWidth : 160 , slotName : 'capacity' },
{ key : 'warehouse' , label : '所属仓库' , minWidth : 210 , slotName : 'warehouse' },
{ key : 'remark' , label : '备注' , minWidth : 220 , slotName : 'remark' },
{ prop : 'updatedAt' , label : '更新时间' , minWidth : 160 , formatter : ( row : PlatformPalletResource ) => formatDateTime ( row . updatedAt ) },
]
function apiId ( value : string ) {
const numeric = Number ( value )
return Number . isSafeInteger ( numeric ) ? numeric : value
}
function formatDateTime ( value ?: string | null ) {
return value ? . replace ( 'T' , ' ' ). slice ( 0 , 16 ) || '—'
}
function formatCapacity ( value : number | string ) {
const numeric = Number ( value )
if ( ! Number . isFinite ( numeric )) return String ( value )
return ` ${ numeric . toLocaleString ( 'zh-CN' , { maximumFractionDigits : 6 } )} m³`
}
function warehouseFor ( warehouseId : number | string ) {
return warehouses . value . find (( item ) => String ( item . id ) === String ( warehouseId )) || null
}
function customerLabel ( customerId : number | string ) {
const customer = customers . value . find (( item ) => String ( item . id ) === String ( customerId ))
return customer ? ` ${ customer . tenantName } ( ${ customer . tenantCode || customer . id } ) ` : '—'
}
function errorMessage ( details : ApiErrorDetails ) {
return details . requestId ? ` ${ details . message } ( requestId: ${ details . requestId } ) ` : details . message
}
async function loadCustomers () {
customerLoading . value = true
customerError . value = null
try {
const records : PlatformCustomerResource [] = []
let currentPage = 1
let pages = 1
do {
const result = await listPlatformCustomers ({ page : currentPage , size : 200 })
records . push (... result . records )
pages = Math . max ( 1 , result . pages )
currentPage += 1
} while ( currentPage <= pages )
customers . value = records
} catch ( error ) {
customers . value = []
customerError . value = getApiErrorDetails ( error , '所属企业列表加载失败,请稍后重试' )
} finally {
customerLoading . value = false
}
}
2026-08-05 15:54:59 +08:00
async function loadWarehouses () {
2026-08-04 21:01:39 +08:00
const sequence = ++ warehouseSequence
warehouses . value = []
warehouseError . value = null
warehouseLoading . value = true
try {
2026-08-05 15:54:59 +08:00
const result = await listPlatformWarehouses ( undefined , 1 , 200 )
2026-08-04 21:01:39 +08:00
if ( sequence !== warehouseSequence ) return
warehouses . value = result . records
} catch ( error ) {
if ( sequence !== warehouseSequence ) return
warehouseError . value = getApiErrorDetails ( error , '仓库列表加载失败,请稍后重试' )
} finally {
if ( sequence === warehouseSequence ) warehouseLoading . value = false
}
}
async function loadPallets () {
const sequence = ++ palletSequence
rows . value = []
total . value = 0
loadError . value = null
loading . value = true
try {
const result = await listPlatformPallets ({
page : page . value ,
size : pageSize . value ,
2026-08-05 15:54:59 +08:00
...( appliedFilters . value . warehouseId ? { warehouseId : apiId ( appliedFilters . value . warehouseId ) } : {}),
2026-08-04 21:01:39 +08:00
...( appliedFilters . value . palletCode ? { palletCode : appliedFilters . value . palletCode } : {}),
...( appliedFilters . value . palletType ? { palletType : appliedFilters . value . palletType } : {}),
})
if ( sequence !== palletSequence ) return
rows . value = result . records
total . value = result . total
} catch ( error ) {
if ( sequence !== palletSequence ) return
loadError . value = getApiErrorDetails ( error , '托盘列表加载失败,请稍后重试' )
} finally {
if ( sequence === palletSequence ) loading . value = false
}
}
function applyFilters ( model : QueryModel ) {
2026-08-05 15:54:59 +08:00
appliedFilters . value = {
warehouseId : String ( model . warehouseId || '' ),
palletCode : String ( model . palletCode || '' ),
palletType : String ( model . palletType || '' ),
}
2026-08-04 21:01:39 +08:00
if ( page . value === 1 ) void loadPallets ()
else page . value = 1
}
function resetFilters () {
2026-08-05 15:54:59 +08:00
appliedFilters . value = { warehouseId : '' , palletCode : '' , palletType : '' }
2026-08-04 21:01:39 +08:00
if ( page . value === 1 ) void loadPallets ()
else page . value = 1
}
function openCreate () {
Object . assign ( form , emptyForm ())
2026-08-05 15:54:59 +08:00
form . warehouseId = filters . value . warehouseId
form . customerId = editorWarehouse . value ? String ( editorWarehouse . value . tenantId ) : ''
2026-08-04 21:01:39 +08:00
editorOpen . value = true
captureBaseline ()
void formRef . value ? . clearValidate ()
}
function assignForm ( resource : PlatformPalletResource ) {
Object . assign ( form , {
id : String ( resource . id ),
customerId : String ( resource . tenantId ),
warehouseId : String ( resource . warehouseId ),
palletCode : resource . palletCode ,
palletType : resource . palletType ,
capacityCbm : Number ( resource . capacityCbm ),
remark : resource . remark || '' ,
})
editorOpen . value = true
captureBaseline ()
void formRef . value ? . clearValidate ()
}
async function fetchDetail ( row : PlatformPalletResource ) {
return getPlatformPallet ( apiId ( String ( row . tenantId )), apiId ( String ( row . warehouseId )), row . id )
}
async function openDetail ( row : PlatformPalletResource ) {
detailLoading . value = true
detailOpen . value = true
detail . value = null
try {
detail . value = await fetchDetail ( row )
} catch ( error ) {
detailOpen . value = false
ElMessage . error ( errorMessage ( getApiErrorDetails ( error , '托盘详情加载失败,请稍后重试' )))
} finally {
detailLoading . value = false
}
}
async function openEdit ( row : PlatformPalletResource ) {
try {
assignForm ( await fetchDetail ( row ))
} catch ( error ) {
ElMessage . error ( errorMessage ( getApiErrorDetails ( error , '托盘详情加载失败,请稍后重试' )))
}
}
async function savePallet () {
2026-08-05 15:54:59 +08:00
if ( ! await formRef . value ? . validate (). catch (() => false ) || form . capacityCbm === null ) return
const warehouse = editorWarehouse . value
if ( ! warehouse ) {
ElMessage . error ( '所选仓库已不存在,请重新选择' )
return
}
form . customerId = String ( warehouse . tenantId )
2026-08-04 21:01:39 +08:00
saving . value = true
const payload : SavePlatformPalletRequest = {
warehouseId : apiId ( form . warehouseId ),
palletCode : form . palletCode . trim (),
palletType : form . palletType . trim (),
capacityCbm : form . capacityCbm ,
remark : form . remark . trim () || null ,
}
try {
const customerId = apiId ( form . customerId )
if ( form . id ) await updatePlatformPallet ( customerId , apiId ( form . warehouseId ), form . id , payload )
else await createPlatformPallet ( customerId , payload )
ElMessage . success ( form . id ? '托盘已更新' : '托盘已新增' )
editorOpen . value = false
await loadPallets ()
} catch ( error ) {
ElMessage . error ( errorMessage ( getApiErrorDetails ( error , '托盘保存失败,请稍后重试' )))
} finally {
saving . value = false
}
}
async function removePallet ( row : PlatformPalletResource ) {
try {
await ElMessageBox . confirm (
`确定删除托盘“ ${ row . palletCode } ”吗?已预占或已占用的托盘无法删除。` ,
'删除托盘' ,
{ confirmButtonText : '删除' , cancelButtonText : '取消' , type : 'warning' , confirmButtonClass : 'el-button--danger' },
)
} catch {
return
}
const id = String ( row . id )
deletingIds . value = new Set ([... deletingIds . value , id ])
try {
await deletePlatformPallet ( apiId ( String ( row . tenantId )), apiId ( String ( row . warehouseId )), row . id )
ElMessage . success ( '托盘已删除' )
if ( rows . value . length === 1 && page . value > 1 ) page . value -= 1
else await loadPallets ()
} catch ( error ) {
ElMessage . error ( errorMessage ( getApiErrorDetails ( error , '托盘删除失败,请稍后重试' )))
} finally {
const next = new Set ( deletingIds . value )
next . delete ( id )
deletingIds . value = next
}
}
watch ([ page , pageSize ], ([ nextPage , nextSize ], [ previousPage , previousSize ]) => {
if ( nextPage === previousPage && nextSize === previousSize ) return
void loadPallets ()
})
watch (() => access . can ( editorPermission . value ), ( canWrite ) => {
if ( ! canWrite && editorOpen . value ) editorOpen . value = false
}, { flush : 'sync' })
onMounted (() => {
void loadCustomers ()
2026-08-05 15:54:59 +08:00
void loadWarehouses ()
2026-08-04 21:01:39 +08:00
void loadPallets ()
})
</ script >
< template >
< section class = "pallet-page" >
< LoadErrorState
v-if = "customerError"
2026-08-05 15:54:59 +08:00
title = "客户列表暂时无法加载"
2026-08-04 21:01:39 +08:00
:message = "customerError.message"
:loading = "customerLoading"
@retry ="loadCustomers"
/>
< QueryToolbar
v-model = "filters"
class = "surface-panel pallet-filter-toolbar"
ariaLabel = "托盘筛选"
:fields = "queryFields"
:search-on-reset = "false"
@search ="applyFilters"
@reset ="resetFilters"
/>
< LoadErrorState
v-if = "warehouseError"
title = "仓库列表暂时无法加载"
:message = "warehouseError.message"
:loading = "warehouseLoading"
2026-08-05 15:54:59 +08:00
@retry ="loadWarehouses"
2026-08-04 21:01:39 +08:00
/>
< LoadErrorState
v-if = "loadError"
title = "托盘列表暂时无法加载"
:message = "loadError.message"
:loading = "loading"
@retry ="loadPallets"
/>
< section class = "table-panel surface-panel" aria -label =" 托盘列表区域 " >
< div class = "panel-heading" >
2026-08-05 15:54:59 +08:00
< div >< h2 > 托盘列表 </ h2 >< p > 共 {{ total }} 个托盘 </ p ></ div >
< el-button v-if = "access.can('platform:pallet:create')" type="primary" @click="openCreate"><Plus :size="16" /> 新增托盘 </ el-button >
2026-08-04 21:01:39 +08:00
</ div >
< DataTable
v -model:page = "page"
v -model:page-size = "pageSize"
:data = "rows"
:columns = "columns"
: loading = "loading || warehouseLoading"
:total = "total"
row -key =" id "
2026-08-05 15:54:59 +08:00
: empty -text =" filtered ? ' 暂无符合筛选条件的托盘 ' : ' 暂无托盘数据 '"
2026-08-04 21:01:39 +08:00
aria -label =" 托盘列表 "
>
< template # actions = "{ row }" >
< div class = "table-actions pallet-row-actions" >
< el-button link type = "primary" title = "查看托盘" @click ="openDetail(row as PlatformPalletResource)" >< Eye :size = "15" /> 查看 </ el-button >
< el-button v-if = "access.can('platform:pallet:edit')" link type="primary" title="编辑托盘" @click="openEdit(row as PlatformPalletResource)"><Pencil :size="15" /> 编辑 </ el-button >
< el-button
v-if = "access.can('platform:pallet:delete')"
link
type = "danger"
title = "删除托盘"
: loading = "deletingIds.has(String((row as PlatformPalletResource).id))"
@click ="removePallet(row as PlatformPalletResource)"
>< Trash2 :size = "15" /> 删除 </ el-button >
</ div >
</ template >
< template # pallet = "{ row }" >
< div class = "pallet-cell" >< span >< Boxes :size = "18" /></ span >< strong >{{ ( row as PlatformPalletResource ). palletCode }}</ strong ></ div >
</ template >
< template # capacity = "{ row }" >< strong >{{ formatCapacity (( row as PlatformPalletResource ). capacityCbm ) }}</ strong ></ template >
< template # warehouse = "{ row }" >< span >{{ warehouseFor (( row as PlatformPalletResource ). warehouseId ) ? . warehouseName || '—' }}</ span ></ template >
< template # remark = "{ row }" >< span class = "remark-text" >{{ ( row as PlatformPalletResource ). remark || '—' }}</ span ></ template >
</ DataTable >
</ section >
< el-drawer v-model = "detailOpen" title="托盘详情" size="520px" class="business-drawer" >
< div v-loading = "detailLoading" class="detail-body" >
< template v-if = "detail" >
< div class = "detail-hero" >< span >< Boxes :size = "22" /></ span >< div >< h2 >{{ detail . palletCode }}</ h2 >< p >{{ detail . palletType }}</ p ></ div ></ div >
< h3 class = "detail-section-title" > 归属信息 </ h3 >
< el-descriptions :column = "1" border >
< el-descriptions-item label = "所属企业" >{{ customerLabel ( detail . tenantId ) }}</ el-descriptions-item >
< el-descriptions-item label = "所属仓库" >{{ warehouseFor ( detail . warehouseId ) ? . warehouseName || '—' }} ( {{ warehouseFor ( detail . warehouseId ) ? . warehouseCode || '—' }} ) </ el-descriptions-item >
</ el-descriptions >
< h3 class = "detail-section-title" > 托盘规格 </ h3 >
< el-descriptions :column = "1" border >
< el-descriptions-item label = "托盘编码" >{{ detail . palletCode }}</ el-descriptions-item >
< el-descriptions-item label = "托盘类型" >{{ detail . palletType }}</ el-descriptions-item >
< el-descriptions-item label = "托盘容积" >{{ formatCapacity ( detail . capacityCbm ) }}</ el-descriptions-item >
< el-descriptions-item label = "备注" >{{ detail . remark || '—' }}</ el-descriptions-item >
</ el-descriptions >
< h3 class = "detail-section-title" > 记录信息 </ h3 >
< el-descriptions :column = "1" border >
< el-descriptions-item label = "创建时间" >{{ formatDateTime ( detail . createdAt ) }}</ el-descriptions-item >
< el-descriptions-item label = "更新时间" >{{ formatDateTime ( detail . updatedAt ) }}</ el-descriptions-item >
</ el-descriptions >
</ template >
</ div >
< template # footer >< el-button @click ="detailOpen = false" > 关闭 </ el -button ></ template >
</ el-drawer >
< el-drawer v-model = "editorOpen" :title="editorTitle" size="520px" class="business-drawer" :close-on-click-modal="false" >
2026-08-05 15:54:59 +08:00
< div v-if = "form.id" class="editor-context" >
2026-08-04 21:01:39 +08:00
< WarehouseIcon :size = "18" />
2026-08-05 15:54:59 +08:00
< div >< strong >{{ editorWarehouse ? . warehouseName || '当前仓库' }} ( {{ editorWarehouse ? . warehouseCode || form . warehouseId }} ) </ strong >< span > 客户 {{ customerLabel ( form . customerId ) }} · 托盘保存后不可跨仓移动 </ span ></ div >
2026-08-04 21:01:39 +08:00
</ div >
< el-form ref = "formRef" :model = "form" :rules = "rules" label -position =" top " class = "editor-form" >
2026-08-05 15:54:59 +08:00
< el-form-item v-if = "!form.id" label="所属仓库" prop="warehouseId" required >
< el-select v-model = "form.warehouseId" filterable placeholder="请选择所属仓库" :loading="warehouseLoading" >
< el-option
v-for = "warehouse in warehouses"
:key = "String(warehouse.id)"
:label = "`${warehouse.warehouseName}( ${warehouse.warehouseCode}) `"
:value = "String(warehouse.id)"
/>
</ el-select >
</ el-form-item >
2026-08-04 21:01:39 +08:00
< el-form-item label = "托盘编码" prop = "palletCode" required >
< el-input v-model = "form.palletCode" maxlength="50" show-word-limit placeholder="例如 TP-001" />
</ el-form-item >
< el-form-item label = "托盘类型" prop = "palletType" required >
< el-select
v-model = "form.palletType"
filterable
allow -create
default -first-option
placeholder = "请选择或输入托盘类型"
aria -label =" 编辑托盘类型 "
>
< el-option v-for = "type in palletTypeOptions" :key="type" :label="type" :value="type" />
</ el-select >
</ el-form-item >
< el-form-item label = "托盘容积(m³)" prop = "capacityCbm" required >
< el-input-number v-model = "form.capacityCbm" :min="0.000001" :max="999999999999.999999" :precision="6" :step="0.1" controls-position="right" aria-label="标准容积" />
< p class = "field-help" > 用于服务端按总体积计算所需托盘数量 ; 请输入托盘实际可用容积 。 </ p >
</ el-form-item >
< el-form-item label = "备注" prop = "remark" >
< el-input v-model = "form.remark" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="可填写规格、材质或现场识别说明" />
</ el-form-item >
</ el-form >
< template # footer >
< div class = "drawer-footer" >< el-button :disabled = "saving" @click ="editorOpen = false" > 取消 </ el -button >< el-button type = "primary" :loading = "saving" @click ="savePallet" > 保存托盘 </ el -button ></ div >
</ template >
</ el-drawer >
</ section >
</ template >
< style scoped >
. pallet - page { display : grid ; min - width : 0 ; gap : 16 px ; }
. surface - panel { overflow : hidden ; border : 1 px solid var ( -- cc - border ); border - radius : 8 px ; background : # fff ; }
. table - panel { min - width : 0 ; }
. panel - heading { display : flex ; align - items : center ; justify - content : space - between ; gap : 20 px ; padding : 14 px 18 px ; border - bottom : 1 px solid var ( -- cc - border ); }
. panel - heading h2 { margin : 0 ; font - size : 16 px ; }
. panel - heading p { margin : 4 px 0 0 ; color : var ( -- cc - muted ); font - size : 12 px ; }
. context - empty { padding : 56 px 20 px ; color : var ( -- cc - muted ); text - align : center ; }
. pallet - row - actions { gap : 8 px ; white - space : nowrap ; }
. pallet - row - actions : deep (. el - button + . el - button ) { margin - left : 0 ; }
. pallet - cell { display : flex ; align - items : center ; gap : 10 px ; }
. pallet - cell > span , . detail - hero > span { display : inline - flex ; align - items : center ; justify - content : center ; flex : 0 0 auto ; border - radius : 8 px ; background : var ( -- el - color - primary - light - 9 ); color : var ( -- cc - primary ); }
. pallet - cell > span { width : 34 px ; height : 34 px ; }
. remark - text { display : - webkit - box ; overflow : hidden ; - webkit - box - orient : vertical ; - webkit - line - clamp : 2 ; line - height : 1.55 ; }
. detail - body { min - height : 180 px ; }
. detail - hero { display : flex ; align - items : center ; gap : 12 px ; margin - bottom : 20 px ; }
. detail - hero > span { width : 46 px ; height : 46 px ; }
. detail - hero h2 , . detail - hero p { margin : 0 ; }
. detail - hero h2 { font - size : 18 px ; }
. detail - hero p { margin - top : 4 px ; color : var ( -- cc - muted ); font - size : 13 px ; }
. detail - section - title { margin : 20 px 0 8 px ; color : var ( -- cc - text ); font - size : 14 px ; }
. detail - section - title : first - of - type { margin - top : 0 ; }
. editor - context { display : flex ; align - items : center ; gap : 10 px ; margin - bottom : 20 px ; padding : 12 px ; border : 1 px solid var ( -- el - color - primary - light - 7 ); border - radius : 8 px ; background : var ( -- el - color - primary - light - 9 ); color : var ( -- cc - primary ); }
. editor - context div { display : grid ; gap : 2 px ; }
. editor - context span { color : var ( -- cc - muted ); font - size : 12 px ; }
. editor - form : deep (. el - input - number ), . editor - form : deep (. el - select ) { width : 100 % ; }
. field - help { margin : 6 px 0 0 ; color : var ( -- cc - muted ); font - size : 12 px ; line - height : 1.5 ; }
. drawer - footer { display : flex ; justify - content : flex - end ; gap : 8 px ; }
. drawer - footer : deep (. el - button + . el - button ) { margin - left : 0 ; }
@ media ( max - width : 720 px ) {
. panel - heading { align - items : stretch ; flex - direction : column ; }
. panel - heading > . el - button { width : 100 % ; min - height : 44 px ; }
. pallet - row - actions : deep (. el - button ) { min - height : 36 px ; padding - inline : 5 px ; }
. drawer - footer { display : grid ; grid - template - columns : 1 fr 1 fr ; }
. drawer - footer : deep (. el - button ) { min - height : 44 px ; margin - left : 0 ; }
}
@ media ( max - width : 768 px ) {
. pallet - filter - toolbar : deep (. query - toolbar__filters ) { width : 100 % ; flex - direction : column ; }
. pallet - filter - toolbar : deep (. query - toolbar__filters . el - input ),
. pallet - filter - toolbar : deep (. query - toolbar__filters . el - select ),
. pallet - filter - toolbar : deep (. query - toolbar__filters . el - date - editor ) { width : 100 % ! important ; }
}
</ style >