20260706001
This commit is contained in:
@@ -5,6 +5,7 @@ import { loadGoodsInScenes, sceneValuesObjectFromRaw } from '@/utils/rfSceneGood
|
||||
import {
|
||||
pickGoodsCategoryEntry,
|
||||
pickGoodsDisplayName,
|
||||
pickGoodsNameFromListedRow,
|
||||
resolveGoodsCategoryCode,
|
||||
} from '@/utils/goodsCategorys'
|
||||
|
||||
@@ -571,7 +572,15 @@ function parseStableSupply(v) {
|
||||
/** @param {unknown} row */
|
||||
export function normalizeCollectionGoodsRow(row) {
|
||||
if (!row || typeof row !== 'object') return null
|
||||
const r = row
|
||||
const embedded = row.raw && typeof row.raw === 'object' ? row.raw : null
|
||||
const r = embedded
|
||||
? {
|
||||
...embedded,
|
||||
...row,
|
||||
goods_categorys: row.goods_categorys ?? embedded.goods_categorys,
|
||||
goods: row.goods ?? embedded.goods,
|
||||
}
|
||||
: row
|
||||
const nested = r.goods && typeof r.goods === 'object' ? r.goods : null
|
||||
const goods_code = String(
|
||||
r.goods_code
|
||||
@@ -600,7 +609,8 @@ export function normalizeCollectionGoodsRow(row) {
|
||||
).trim()
|
||||
const name = pickGoodsDisplayName(r, category_code, { allowTopLevelName: true })
|
||||
|| String(
|
||||
r.goods_name
|
||||
r.name
|
||||
|| r.goods_name
|
||||
|| r.goodsName
|
||||
|| r.product_name
|
||||
|| r.material_name
|
||||
@@ -671,15 +681,22 @@ export function pickCollectionGoodsPreferredTax(row) {
|
||||
export function pickCollectionGoodsPickFields(row) {
|
||||
const normalized = normalizeCollectionGoodsRow(row) || (row && typeof row === 'object' ? row : null)
|
||||
if (!normalized) return null
|
||||
const raw = normalized.raw || row
|
||||
const sourceRow = normalized.raw || row
|
||||
const goods_code = String(normalized.goods_code || '').trim()
|
||||
if (!goods_code) return null
|
||||
const payRaw = raw?.payment_price ?? ''
|
||||
const payRaw = sourceRow?.payment_price ?? row?.payment_price ?? ''
|
||||
const payment_price = payRaw !== '' && payRaw != null ? Number(payRaw) : null
|
||||
const bill_tax = pickCollectionGoodsPreferredTax(row)
|
||||
const bill_tax = pickCollectionGoodsPreferredTax(sourceRow)
|
||||
const nameCandidates = [
|
||||
String(row?.name || '').trim(),
|
||||
String(normalized.name || '').trim(),
|
||||
pickGoodsNameFromListedRow(sourceRow),
|
||||
pickGoodsNameFromListedRow(row),
|
||||
].filter(Boolean)
|
||||
const name = nameCandidates.find((n) => n !== goods_code) || nameCandidates[0] || goods_code
|
||||
return {
|
||||
goods_code,
|
||||
name: String(normalized.name || goods_code).trim(),
|
||||
name,
|
||||
payment_price: Number.isFinite(payment_price) ? payment_price : null,
|
||||
bill_tax,
|
||||
raw: normalized,
|
||||
|
||||
@@ -186,6 +186,23 @@ export async function allocAttrListed(body = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/warehouse/alloc/attr/search — 按商品/RDC/FDC 检索配货属性编码 */
|
||||
export async function allocAttrSearch(body = {}) {
|
||||
const payload = buildListedPayload({
|
||||
goods_code: str(body.goods_code) || undefined,
|
||||
rdc_warehouse_code: str(body.rdc_warehouse_code) || undefined,
|
||||
fdc_warehouse_code: str(body.fdc_warehouse_code) || undefined,
|
||||
page: body.page,
|
||||
limit: body.limit,
|
||||
})
|
||||
const res = await request.post('/api/warehouse/alloc/attr/search', payload)
|
||||
const { list, total } = unwrapListed(res)
|
||||
return {
|
||||
list: list.map(normalizeAllocAttrRow).filter(Boolean),
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/warehouse/alloc/logs/listed */
|
||||
export async function allocLogsListed(body = {}) {
|
||||
const res = await request.post('/api/warehouse/alloc/logs/listed', buildListedPayload(body))
|
||||
|
||||
@@ -198,6 +198,83 @@ export async function wasteLogsAdd(body) {
|
||||
return res?.data ?? res
|
||||
}
|
||||
|
||||
function normalizeWasteShareRow(raw) {
|
||||
if (!raw || typeof raw !== 'object') return null
|
||||
const wh = pickRdcFdcPair(raw)
|
||||
const goods = pickGoodsFields(raw)
|
||||
const goods_code = goods.goods_code
|
||||
if (!goods_code && !wh.rdc_warehouse_code) return null
|
||||
const waste_count = num(
|
||||
raw.waste_count
|
||||
?? raw.rdc_waste_count
|
||||
?? raw.rdc_waste
|
||||
?? raw.waste_num,
|
||||
)
|
||||
const rdc_in_count = num(
|
||||
raw.rdc_in_count
|
||||
?? raw.total_rdc_in
|
||||
?? raw.rdc_inbound_count
|
||||
?? raw.in_count,
|
||||
)
|
||||
const share_total_amount = num(
|
||||
raw.total_amount
|
||||
?? raw.share_total_amount
|
||||
?? raw.share_amount,
|
||||
)
|
||||
return {
|
||||
...raw,
|
||||
...wh,
|
||||
...goods,
|
||||
goods_display_name: pickGoodsNameFromListedRow(raw) || goods.goods_name,
|
||||
waste_count,
|
||||
rdc_in_count,
|
||||
ratio: num(raw.ratio ?? raw.share_ratio ?? raw.waste_ratio),
|
||||
pre_price: num(raw.pre_price ?? raw.price ?? raw.cost_price),
|
||||
unit_amount: num(raw.unit_amount ?? raw.share_unit_amount ?? raw.unit_share_amount),
|
||||
share_total_amount,
|
||||
share_time: str(raw.share_time ?? raw.amortize_time ?? raw.ctime ?? raw.create_time),
|
||||
day_id: raw.day_id != null && raw.day_id !== '' ? Number(raw.day_id) : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/warehouse/waste/share/listed */
|
||||
export async function wasteShareListed(body = {}) {
|
||||
const payload = buildListedPayload({
|
||||
goods_code: str(body.goods_code) || undefined,
|
||||
rdc_warehouse_code: str(body.rdc_warehouse_code) || undefined,
|
||||
day_id: body.day_id != null && body.day_id !== '' ? Number(body.day_id) : undefined,
|
||||
page: body.page,
|
||||
limit: body.limit,
|
||||
})
|
||||
const res = await request.post('/api/warehouse/waste/share/listed', payload)
|
||||
const { list, total } = unwrapListed(res)
|
||||
return {
|
||||
list: list.map(normalizeWasteShareRow).filter(Boolean),
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/warehouse/waste/amortize */
|
||||
export async function wasteAmortize(body) {
|
||||
const payload = {
|
||||
start_time: str(body?.start_time),
|
||||
end_time: str(body?.end_time),
|
||||
}
|
||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
||||
const res = await request.post('/api/warehouse/waste/amortize', payload, { skipErrorNotify: true })
|
||||
return res?.data ?? res
|
||||
}
|
||||
|
||||
export function isBenignWasteAmortizeError(err) {
|
||||
const msg = pickApiErrorMessage(err, '')
|
||||
return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg)
|
||||
}
|
||||
|
||||
export function pickApiErrorMessage(err, fallback = '操作失败') {
|
||||
return String(err?.data?.message || err?.message || fallback).trim() || fallback
|
||||
return String(
|
||||
err?.data?.message
|
||||
?? err?.data?.data?.message
|
||||
?? err?.message
|
||||
?? fallback,
|
||||
).trim() || fallback
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"buildId": "20260703007",
|
||||
"generatedAt": "2026-07-03T09:28:11.726Z"
|
||||
"buildId": "20260706001",
|
||||
"generatedAt": "2026-07-06T04:43:39.914Z"
|
||||
}
|
||||
@@ -47,9 +47,49 @@ export const APP_VERSION = '0.7.029'
|
||||
|
||||
/** @type {ChangelogDay[]} */
|
||||
export const APP_CHANGELOG = [
|
||||
{
|
||||
date: '2026-07-06',
|
||||
items: [
|
||||
{
|
||||
icon: 'mdi:cart-outline',
|
||||
kind: 'fix',
|
||||
text: '「采购管理 → 新增采购订单」从统筹商品添加至明细后,物料列正确展示「名称(编码)」;修复二次归一化丢失 `goods_categorys` 物料名、明细仅显示编码的问题。',
|
||||
},
|
||||
{
|
||||
icon: 'mdi:package-variant-closed-minus',
|
||||
kind: 'change',
|
||||
text: '「仓库管理 → 损耗管理 → 新增记录」配货属性编码旁增加「搜索」按钮,弹窗内按物料编码、RDC/FDC 仓查询 `alloc/attr/search` 后点选;主表单展示编码及「物料 · RDC · FDC」说明。',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2026-07-05',
|
||||
items: [
|
||||
{
|
||||
icon: 'mdi:cog-outline',
|
||||
kind: 'change',
|
||||
text: '系统工程调整:变更说明按日归档,便于发版对照;仓库管理相关 API 封装与字段归一化逻辑补充,提升与后端联调时的数据一致性。',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2026-07-04',
|
||||
items: [
|
||||
{
|
||||
icon: 'mdi:tune-variant',
|
||||
kind: 'change',
|
||||
text: '系统交互与展示优化:仓库运维及分摊预估类页面统一「进页跑批 / 手动查询 / 重新跑批」职责划分;列表 loading 与空态提示对齐;数字列间距、除物料外仅展示名称等展示规则在各模块间进一步收敛。',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2026-07-03',
|
||||
items: [
|
||||
{
|
||||
icon: 'mdi:package-variant-closed-minus',
|
||||
kind: 'add',
|
||||
text: '「仓库管理 → 损耗分摊预估」新增页面(`WasteShareListed.vue`,路由 `/warehouse/waste-share`):进页自动 `waste/amortize` 跑批后拉 `waste/share/listed`;筛选分摊时间段、物料编码、RDC 仓库编码;展示损耗数、RDC 入库、占比、定价成本、分摊总额、单件分摊(`is-cols-share-waste`,9 列)。',
|
||||
},
|
||||
{
|
||||
icon: 'mdi:help-circle-outline',
|
||||
kind: 'change',
|
||||
|
||||
@@ -505,6 +505,16 @@ export const asyncRoutes = [
|
||||
powerKey: 'warehouse',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'waste-share',
|
||||
name: 'WarehouseWasteShare',
|
||||
component: () => import('@/views/base/WasteShareListed.vue'),
|
||||
meta: {
|
||||
title: '损耗分摊预估',
|
||||
icon: 'mdi:package-variant-closed-minus',
|
||||
powerKey: 'warehouse',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
/*
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
.wops-flex-table.is-cols-share-deploy {
|
||||
--wops-cols: 14fr 11fr 11fr 5fr 5fr 5fr 4fr 5fr 8fr;
|
||||
}
|
||||
/* 损耗分摊预估(9 列) */
|
||||
.wops-flex-table.is-cols-share-waste {
|
||||
--wops-cols: 14fr 11fr 5fr 5fr 4fr 5fr 5fr 5fr 8fr;
|
||||
}
|
||||
/* 公关费用(10 列):费用编码略窄,集团 / 组织各加半份 */
|
||||
.wops-flex-table.is-cols-pr-cost {
|
||||
--wops-cols: 7fr 10.5fr 10.5fr 7fr 8fr 8fr 6fr 9fr 6fr 8fr;
|
||||
@@ -191,6 +195,7 @@
|
||||
.wops-flex-table.is-cols-share-pr .wops-flex-row,
|
||||
.wops-flex-table.is-cols-share-alloc .wops-flex-row,
|
||||
.wops-flex-table.is-cols-share-deploy .wops-flex-row,
|
||||
.wops-flex-table.is-cols-share-waste .wops-flex-row,
|
||||
.wops-flex-table.is-cols-pr-cost .wops-flex-row,
|
||||
.wops-flex-table.is-cols-collect-whp .wops-flex-row,
|
||||
.wops-flex-table.is-cols-logs-whp .wops-flex-row,
|
||||
@@ -211,6 +216,8 @@
|
||||
.wops-flex-table.is-cols-share-alloc .wops-flex-head .wops-col--num,
|
||||
.wops-flex-table.is-cols-share-deploy .wops-col--num,
|
||||
.wops-flex-table.is-cols-share-deploy .wops-flex-head .wops-col--num,
|
||||
.wops-flex-table.is-cols-share-waste .wops-col--num,
|
||||
.wops-flex-table.is-cols-share-waste .wops-flex-head .wops-col--num,
|
||||
.wops-flex-table.is-cols-pr-cost .wops-col--num,
|
||||
.wops-flex-table.is-cols-pr-cost .wops-flex-head .wops-col--num,
|
||||
.wops-flex-table.is-cols-collect-whp .wops-col--num,
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
<template>
|
||||
<div class="wsl-page">
|
||||
<header class="wsl-header">
|
||||
<div class="wsl-header-main">
|
||||
<h2 class="wsl-title">损耗分摊预估</h2>
|
||||
<span class="wsl-total">{{ !loading && queried ? `共 ${total} 条` : '' }}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="wsl-filters">
|
||||
<el-date-picker
|
||||
v-model="batchRange.start_time"
|
||||
type="date"
|
||||
placeholder="分摊开始日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
size="small"
|
||||
clearable
|
||||
class="wsl-filter-date"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-model="batchRange.end_time"
|
||||
type="date"
|
||||
placeholder="分摊结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
size="small"
|
||||
clearable
|
||||
class="wsl-filter-date"
|
||||
/>
|
||||
<el-input
|
||||
v-model="filters.goods_code"
|
||||
placeholder="物料编码"
|
||||
clearable
|
||||
size="small"
|
||||
class="wsl-filter-item"
|
||||
@keyup.enter="doSearch"
|
||||
/>
|
||||
<el-input
|
||||
v-model="filters.rdc_warehouse_code"
|
||||
placeholder="RDC仓库编码"
|
||||
clearable
|
||||
size="small"
|
||||
class="wsl-filter-item"
|
||||
@keyup.enter="doSearch"
|
||||
/>
|
||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading" :element-loading-text="loadingText" class="wsl-body">
|
||||
<div class="wops-flex-table is-cols-share-waste">
|
||||
<div class="wops-flex-scroll">
|
||||
<div class="wops-flex-row wops-flex-head">
|
||||
<div
|
||||
v-for="col in SHARE_COLUMNS"
|
||||
:key="col.key"
|
||||
class="wops-col wsl-head-col"
|
||||
:class="[colHeadClass(col.key), colHeadColorClass(col.key)]"
|
||||
>
|
||||
{{ col.label }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && queried && !rows.length" class="wops-empty-wrap">
|
||||
<p class="wops-empty">暂无分摊结果</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(row, idx) in rows"
|
||||
:key="shareRowKey(row, idx)"
|
||||
class="wops-flex-row wops-flex-data"
|
||||
:class="{ 'is-stripe': idx % 2 === 1 }"
|
||||
>
|
||||
<WarehouseOpsNameCode
|
||||
:name="pickShareGoodsName(row)"
|
||||
:code="row.goods_code"
|
||||
/>
|
||||
<div class="wops-col wops-col--wh">
|
||||
<span class="wops-name wops-ellipsis">{{ row.rdc_warehouse_name || '—' }}</span>
|
||||
</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.waste_count) }}</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.rdc_in_count) }}</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.ratio, 4) }}</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.pre_price) }}</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.share_total_amount) }}</div>
|
||||
<div class="wops-col wops-col--num">{{ fmtNum(row.unit_amount) }}</div>
|
||||
<div class="wops-col wops-col--time">
|
||||
<span class="wops-ellipsis">{{ formatOpsLogTime(row.share_time || row.ctime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="queried && total > 0" class="wsl-footer">
|
||||
<el-pagination
|
||||
v-model:current-page="page"
|
||||
v-model:page-size="limit"
|
||||
:total="total"
|
||||
:page-sizes="[20, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
background
|
||||
small
|
||||
@current-change="loadPage"
|
||||
@size-change="onSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onActivated, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import WarehouseOpsNameCode from '@/components/warehouse/WarehouseOpsNameCode.vue'
|
||||
import { formatOpsLogTime } from '@/utils/warehouseOpsDisplay'
|
||||
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
||||
import {
|
||||
isBenignWasteAmortizeError,
|
||||
pickApiErrorMessage,
|
||||
wasteAmortize,
|
||||
wasteShareListed,
|
||||
} from '@/api/warehouseWaste'
|
||||
|
||||
defineOptions({ name: 'WasteShareListed' })
|
||||
|
||||
const SHARE_COLUMNS = [
|
||||
{ key: 'goods_name', label: '物料' },
|
||||
{ key: 'rdc_warehouse_name', label: 'RDC仓库' },
|
||||
{ key: 'waste_count', label: '损耗数' },
|
||||
{ key: 'rdc_in_count', label: 'RDC入库' },
|
||||
{ key: 'ratio', label: '占比' },
|
||||
{ key: 'pre_price', label: '定价成本' },
|
||||
{ key: 'share_total_amount', label: '分摊总额' },
|
||||
{ key: 'unit_amount', label: '单件分摊' },
|
||||
{ key: 'share_time', label: '分摊时间' },
|
||||
]
|
||||
|
||||
const NUM_KEYS = new Set([
|
||||
'waste_count',
|
||||
'rdc_in_count',
|
||||
'ratio',
|
||||
'pre_price',
|
||||
'share_total_amount',
|
||||
'unit_amount',
|
||||
])
|
||||
|
||||
function colHeadClass(key) {
|
||||
if (NUM_KEYS.has(key)) return 'wops-col--num'
|
||||
if (key === 'share_time') return 'wops-col--time'
|
||||
if (key === 'rdc_warehouse_name') return 'wops-col--wh'
|
||||
if (key === 'goods_name') return 'wops-col--goods'
|
||||
return 'wops-col--plain'
|
||||
}
|
||||
|
||||
function colHeadColorClass(key) {
|
||||
const map = {
|
||||
goods_name: 'wsl-head-col--goods',
|
||||
rdc_warehouse_name: 'wsl-head-col--rdc-wh',
|
||||
waste_count: 'wsl-head-col--waste',
|
||||
rdc_in_count: 'wsl-head-col--in',
|
||||
ratio: 'wsl-head-col--ratio',
|
||||
pre_price: 'wsl-head-col--price',
|
||||
share_total_amount: 'wsl-head-col--share-total',
|
||||
unit_amount: 'wsl-head-col--unit-amt',
|
||||
share_time: 'wsl-head-col--time',
|
||||
}
|
||||
return map[key] || 'wsl-head-col--plain'
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const loadingText = ref('加载中…')
|
||||
const queried = ref(false)
|
||||
const rows = ref([])
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const limit = ref(20)
|
||||
|
||||
const filters = reactive({
|
||||
goods_code: '',
|
||||
rdc_warehouse_code: '',
|
||||
})
|
||||
|
||||
function buildQueryBody() {
|
||||
return {
|
||||
page: page.value,
|
||||
limit: limit.value,
|
||||
goods_code: String(filters.goods_code || '').trim() || undefined,
|
||||
rdc_warehouse_code: String(filters.rdc_warehouse_code || '').trim() || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function pad2(n) {
|
||||
return String(n).padStart(2, '0')
|
||||
}
|
||||
|
||||
function fmtDate(d) {
|
||||
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
|
||||
}
|
||||
|
||||
function defaultBatchRange() {
|
||||
const now = new Date()
|
||||
const start = new Date(now.getFullYear(), 0, 1)
|
||||
return { start_time: fmtDate(start), end_time: fmtDate(now) }
|
||||
}
|
||||
|
||||
const batchRange = reactive(defaultBatchRange())
|
||||
|
||||
function pickShareGoodsName(row) {
|
||||
const label = String(row?.goods_display_name ?? '').trim()
|
||||
if (label) return label
|
||||
return pickGoodsNameFromListedRow(row) || ''
|
||||
}
|
||||
|
||||
function fmtNum(v, digits = 2) {
|
||||
if (v == null || v === '') return '—'
|
||||
const n = Number(v)
|
||||
return Number.isFinite(n) ? n.toFixed(digits) : String(v)
|
||||
}
|
||||
|
||||
function shareRowKey(row, idx) {
|
||||
return [
|
||||
row?.goods_code ?? '',
|
||||
row?.rdc_warehouse_code ?? '',
|
||||
row?.share_time ?? row?.ctime ?? '',
|
||||
row?.day_id ?? '',
|
||||
idx,
|
||||
].join(':')
|
||||
}
|
||||
|
||||
async function fetchShareList() {
|
||||
loadingText.value = '加载分摊结果…'
|
||||
const res = await wasteShareListed(buildQueryBody())
|
||||
rows.value = res.list
|
||||
total.value = res.total
|
||||
queried.value = true
|
||||
}
|
||||
|
||||
function loadPage() {
|
||||
if (loading.value) return
|
||||
search()
|
||||
}
|
||||
|
||||
function onSizeChange() {
|
||||
page.value = 1
|
||||
search()
|
||||
}
|
||||
|
||||
async function runBatchAndLoad() {
|
||||
const start_time = String(batchRange.start_time || '').trim()
|
||||
const end_time = String(batchRange.end_time || '').trim()
|
||||
if (!start_time || !end_time) {
|
||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
||||
return
|
||||
}
|
||||
if (start_time > end_time) {
|
||||
ElMessage.warning('开始日期不能晚于结束日期')
|
||||
return
|
||||
}
|
||||
|
||||
page.value = 1
|
||||
loading.value = true
|
||||
loadingText.value = '正在跑批中…'
|
||||
try {
|
||||
let amortizeHint = ''
|
||||
try {
|
||||
await wasteAmortize({ start_time, end_time })
|
||||
} catch (e) {
|
||||
if (!isBenignWasteAmortizeError(e)) {
|
||||
throw e
|
||||
}
|
||||
amortizeHint = pickApiErrorMessage(e, '')
|
||||
}
|
||||
|
||||
await fetchShareList()
|
||||
if (amortizeHint) {
|
||||
ElMessage.warning(amortizeHint)
|
||||
} else if (rows.value.length) {
|
||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function search() {
|
||||
loading.value = true
|
||||
loadingText.value = '加载中…'
|
||||
try {
|
||||
await fetchShareList()
|
||||
} catch (e) {
|
||||
ElMessage.error(pickApiErrorMessage(e, '查询失败'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
page.value = 1
|
||||
search()
|
||||
}
|
||||
|
||||
function resetFilters() {
|
||||
Object.assign(batchRange, defaultBatchRange())
|
||||
filters.goods_code = ''
|
||||
filters.rdc_warehouse_code = ''
|
||||
page.value = 1
|
||||
search()
|
||||
}
|
||||
|
||||
async function initPage() {
|
||||
await runBatchAndLoad()
|
||||
}
|
||||
|
||||
onMounted(initPage)
|
||||
onActivated(initPage)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.wsl-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.wsl-header {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.wsl-header-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 12px;
|
||||
}
|
||||
.wsl-title {
|
||||
font-size: calc(16px + var(--wh-fs-delta, 0px));
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0;
|
||||
}
|
||||
.wsl-total {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
min-width: 60px;
|
||||
display: inline-block;
|
||||
}
|
||||
.wsl-filters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.wsl-filter-item {
|
||||
width: 180px;
|
||||
}
|
||||
.wsl-filter-date {
|
||||
width: 150px;
|
||||
}
|
||||
.wsl-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wsl-body :deep(.wops-flex-head) {
|
||||
border-bottom: none;
|
||||
align-items: flex-end;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.wsl-body :deep(.wsl-head-col) {
|
||||
border-bottom: 2px solid;
|
||||
padding-bottom: 7px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.wsl-body :deep(.wsl-head-col--goods) { border-bottom-color: #409eff; }
|
||||
.wsl-body :deep(.wsl-head-col--rdc-wh) { border-bottom-color: #67c23a; }
|
||||
.wsl-body :deep(.wsl-head-col--waste) { border-bottom-color: #e6a23c; }
|
||||
.wsl-body :deep(.wsl-head-col--in) { border-bottom-color: #36cfc9; }
|
||||
.wsl-body :deep(.wsl-head-col--ratio) { border-bottom-color: #6b8cba; }
|
||||
.wsl-body :deep(.wsl-head-col--price) { border-bottom-color: #909399; }
|
||||
.wsl-body :deep(.wsl-head-col--share-total) { border-bottom-color: #722ed1; }
|
||||
.wsl-body :deep(.wsl-head-col--unit-amt) { border-bottom-color: #13c2c2; }
|
||||
.wsl-body :deep(.wsl-head-col--time) { border-bottom-color: #606266; }
|
||||
.wsl-body :deep(.wops-col--wh) {
|
||||
justify-content: flex-start;
|
||||
padding-left: 12px;
|
||||
}
|
||||
.wsl-body :deep(.wsl-head-col--time) {
|
||||
text-align: center;
|
||||
}
|
||||
.wsl-body :deep(.wops-col--time) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.wsl-body :deep(.wops-col--time .wops-ellipsis) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.wsl-footer {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -481,8 +481,8 @@
|
||||
<div v-for="(g, idx) in orderForm.goods" :key="g.goods_code + '-' + idx" class="whp-order-goods-row">
|
||||
<span class="whp-og-seq">{{ idx + 1 }}</span>
|
||||
<div class="whp-og-code">
|
||||
<span class="whp-og-code-label" :title="g._name ? g._name + '(' + g.goods_code + ')' : g.goods_code">
|
||||
{{ g._name ? g._name + '(' + g.goods_code + ')' : g.goods_code }}
|
||||
<span class="whp-og-code-label" :title="formatOrderGoodsLabel(g)">
|
||||
{{ formatOrderGoodsLabel(g) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="whp-og-tax">
|
||||
@@ -631,6 +631,7 @@ import {
|
||||
expenseBillTabParts,
|
||||
normalizeFinanceBillType,
|
||||
} from '@/utils/financeBillTypes'
|
||||
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
||||
|
||||
defineOptions({ name: 'WhPurchase' })
|
||||
|
||||
@@ -760,6 +761,13 @@ function fmtOrderAmount(v) {
|
||||
return Number.isFinite(n) ? n.toFixed(2) : '0.00'
|
||||
}
|
||||
|
||||
function formatOrderGoodsLabel(g) {
|
||||
const code = String(g?.goods_code || '').trim()
|
||||
const name = String(g?._name || g?.goods_name || '').trim()
|
||||
if (name && name !== code) return `${name}(${code})`
|
||||
return code || '—'
|
||||
}
|
||||
|
||||
function resolveBillTaxRate(billCode) {
|
||||
const code = normBillCode(billCode)
|
||||
if (!code) return 0
|
||||
@@ -1181,13 +1189,18 @@ async function onOrderPurchaseOrgChange() {
|
||||
await refreshOrderCollectionOptions()
|
||||
}
|
||||
|
||||
function onOrderCatalogAdd({ goods_code, name, payment_price, bill_tax }) {
|
||||
function onOrderCatalogAdd({ goods_code, name, payment_price, bill_tax, raw }) {
|
||||
const code = String(goods_code || '').trim()
|
||||
if (!code) return
|
||||
if (orderForm.goods.some((g) => String(g.goods_code || '').trim() === code)) return
|
||||
const row = emptyOrderGoodsRow()
|
||||
row.goods_code = code
|
||||
row._name = String(name || '').trim()
|
||||
const source = raw?.raw || raw
|
||||
let displayName = String(name || '').trim()
|
||||
if (!displayName || displayName === code) {
|
||||
displayName = pickGoodsNameFromListedRow(source) || displayName
|
||||
}
|
||||
row._name = displayName !== code ? displayName : ''
|
||||
if (payment_price != null && Number.isFinite(payment_price)) {
|
||||
row.purchase_amount = payment_price
|
||||
}
|
||||
|
||||
+325
-25
@@ -135,25 +135,18 @@
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@opened="loadAllocAttrOptions"
|
||||
>
|
||||
<el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="120px" size="small">
|
||||
<el-form-item label="配货属性编码" prop="alloc_attr_code">
|
||||
<el-select
|
||||
v-model="addForm.alloc_attr_code"
|
||||
placeholder="选择配货属性编码"
|
||||
filterable
|
||||
clearable
|
||||
:loading="allocAttrLoading"
|
||||
style="width:100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in allocAttrOptions"
|
||||
:key="opt.alloc_attr_code"
|
||||
:label="opt.label"
|
||||
:value="opt.alloc_attr_code"
|
||||
<div class="whw-attr-code-row">
|
||||
<el-input
|
||||
v-model="addForm.alloc_attr_code"
|
||||
placeholder="请点击搜索选择"
|
||||
readonly
|
||||
/>
|
||||
</el-select>
|
||||
<el-button type="warning" plain @click="openAllocAttrPickDlg">搜索</el-button>
|
||||
</div>
|
||||
<p v-if="addFormAllocAttrLabel" class="whw-attr-picked-label">{{ addFormAllocAttrLabel }}</p>
|
||||
</el-form-item>
|
||||
<el-form-item label="RDC损耗数量" prop="rdc_count">
|
||||
<el-input-number v-model="addForm.rdc_count" :min="0" :controls="false" class="whw-form-num" />
|
||||
@@ -170,6 +163,106 @@
|
||||
<el-button type="primary" :loading="addSaving" @click="submitAdd">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="allocAttrPickVisible"
|
||||
title="搜索配货属性"
|
||||
width="760px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
class="whw-attr-pick-dlg"
|
||||
@opened="onAllocAttrPickOpened"
|
||||
>
|
||||
<div class="whw-attr-pick-filters">
|
||||
<el-input
|
||||
v-model="allocAttrQuery.goods_code"
|
||||
placeholder="物料编码"
|
||||
clearable
|
||||
size="small"
|
||||
class="whw-attr-pick-filter"
|
||||
@keyup.enter="searchAllocAttrPick(true)"
|
||||
/>
|
||||
<el-select
|
||||
v-model="allocAttrQuery.rdc_warehouse_code"
|
||||
placeholder="RDC仓"
|
||||
filterable
|
||||
clearable
|
||||
size="small"
|
||||
class="whw-attr-pick-filter"
|
||||
>
|
||||
<el-option
|
||||
v-for="w in warehouseOptions"
|
||||
:key="'pick-rdc-' + w.warehouse_code"
|
||||
:label="w.label"
|
||||
:value="w.warehouse_code"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-model="allocAttrQuery.fdc_warehouse_code"
|
||||
placeholder="FDC仓"
|
||||
filterable
|
||||
clearable
|
||||
size="small"
|
||||
class="whw-attr-pick-filter"
|
||||
>
|
||||
<el-option
|
||||
v-for="w in warehouseOptions"
|
||||
:key="'pick-fdc-' + w.warehouse_code"
|
||||
:label="w.label"
|
||||
:value="w.warehouse_code"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button type="primary" size="small" :loading="allocAttrLoading" @click="searchAllocAttrPick(true)">查询</el-button>
|
||||
</div>
|
||||
|
||||
<div class="whw-attr-pick-panel">
|
||||
<div v-loading="allocAttrLoading" element-loading-text="搜索中…" class="whw-attr-pick-body">
|
||||
<div
|
||||
v-if="!allocAttrLoading && allocAttrPickQueried && !allocAttrPickRows.length"
|
||||
class="whw-attr-pick-empty-wrap"
|
||||
>
|
||||
<p class="whw-attr-pick-empty">未找到匹配的配货属性</p>
|
||||
</div>
|
||||
<div v-else class="whw-attr-pick-scroll">
|
||||
<button
|
||||
v-for="opt in allocAttrPickRows"
|
||||
:key="opt.alloc_attr_code"
|
||||
type="button"
|
||||
class="whw-attr-pick-item"
|
||||
:class="{ 'is-active': allocAttrPickSelected === opt.alloc_attr_code }"
|
||||
@click="selectAllocAttrPick(opt)"
|
||||
>
|
||||
<span class="whw-attr-pick-code">{{ opt.alloc_attr_code }}</span>
|
||||
<span class="whw-attr-pick-meta">
|
||||
<span class="whw-attr-pick-tag">物料</span>
|
||||
<span>{{ opt.goodsText }}</span>
|
||||
<template v-if="opt.whText">
|
||||
<span class="whw-attr-pick-sep">·</span>
|
||||
<span>{{ opt.whText }}</span>
|
||||
</template>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="allocAttrPickQueried && allocAttrPickTotal > 0" class="whw-attr-pick-pager">
|
||||
<el-pagination
|
||||
v-model:current-page="allocAttrPickPage"
|
||||
:page-size="ALLOC_ATTR_PICK_PAGE_SIZE"
|
||||
:total="allocAttrPickTotal"
|
||||
layout="total, prev, pager, next"
|
||||
small
|
||||
background
|
||||
@current-change="loadAllocAttrPickPage"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="allocAttrPickVisible = false">取消</el-button>
|
||||
<el-button type="primary" :disabled="!allocAttrPickSelected" @click="confirmAllocAttrPick">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -178,7 +271,7 @@ import { onMounted, reactive, ref } from 'vue'
|
||||
import WarehouseOpsNameCode from '@/components/warehouse/WarehouseOpsNameCode.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { warehouseListed } from '@/api/warehouse'
|
||||
import { allocAttrListed, pickAllocAttrCode } from '@/api/warehouseAlloc'
|
||||
import { allocAttrSearch, pickAllocAttrCode } from '@/api/warehouseAlloc'
|
||||
import {
|
||||
pickApiErrorMessage,
|
||||
wasteCollectListed,
|
||||
@@ -189,6 +282,7 @@ import {
|
||||
enrichWarehouseOpsRows,
|
||||
formatOpsLogTime,
|
||||
} from '@/utils/warehouseOpsDisplay'
|
||||
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
||||
|
||||
defineOptions({ name: 'WhWaste' })
|
||||
|
||||
@@ -201,8 +295,21 @@ const page = ref(1)
|
||||
const limit = ref(20)
|
||||
|
||||
const warehouseOptions = ref([])
|
||||
const allocAttrOptions = ref([])
|
||||
const allocAttrLoading = ref(false)
|
||||
const allocAttrPickVisible = ref(false)
|
||||
const allocAttrPickQueried = ref(false)
|
||||
const allocAttrPickRows = ref([])
|
||||
const allocAttrPickSelected = ref('')
|
||||
const allocAttrPickSelectedOption = ref(null)
|
||||
const allocAttrPickPage = ref(1)
|
||||
const allocAttrPickTotal = ref(0)
|
||||
const ALLOC_ATTR_PICK_PAGE_SIZE = 50
|
||||
const addFormAllocAttrLabel = ref('')
|
||||
const allocAttrQuery = reactive({
|
||||
goods_code: '',
|
||||
rdc_warehouse_code: '',
|
||||
fdc_warehouse_code: '',
|
||||
})
|
||||
|
||||
const filters = reactive({
|
||||
alloc_attr_code: '',
|
||||
@@ -284,27 +391,52 @@ function onViewModeChange() {
|
||||
loadData()
|
||||
}
|
||||
|
||||
function allocAttrHint(row) {
|
||||
function formatPickGoodsText(row) {
|
||||
const code = String(row?.goods_code || '').trim()
|
||||
const name = String(
|
||||
row?.goods_name
|
||||
|| pickGoodsNameFromListedRow(row)
|
||||
|| '',
|
||||
).trim()
|
||||
if (name && name !== code) return `${name}(${code})`
|
||||
return code || '—'
|
||||
}
|
||||
|
||||
function formatPickWhText(row) {
|
||||
const parts = [
|
||||
row?.goods_name || row?.goods_code,
|
||||
row?.rdc_warehouse_name || row?.rdc_warehouse_code,
|
||||
row?.fdc_warehouse_name || row?.fdc_warehouse_code,
|
||||
].filter(Boolean)
|
||||
return parts.join(' · ')
|
||||
}
|
||||
|
||||
function allocAttrHint(row) {
|
||||
const parts = [formatPickGoodsText(row), formatPickWhText(row)].filter((v) => v && v !== '—')
|
||||
return parts.join(' · ')
|
||||
}
|
||||
|
||||
function mapAllocAttrOption(row) {
|
||||
const alloc_attr_code = pickAllocAttrCode(row)
|
||||
if (!alloc_attr_code) return null
|
||||
const goodsText = formatPickGoodsText(row)
|
||||
const whText = formatPickWhText(row)
|
||||
const hint = allocAttrHint(row)
|
||||
const label = hint ? `${alloc_attr_code}(${hint})` : alloc_attr_code
|
||||
return { alloc_attr_code, label }
|
||||
return { alloc_attr_code, label, hint, goodsText, whText }
|
||||
}
|
||||
|
||||
async function loadAllocAttrOptions() {
|
||||
async function searchAllocAttrPick(resetPage = false) {
|
||||
if (resetPage) allocAttrPickPage.value = 1
|
||||
allocAttrLoading.value = true
|
||||
allocAttrPickQueried.value = true
|
||||
try {
|
||||
const res = await allocAttrListed({ page: 1, limit: 50 })
|
||||
const res = await allocAttrSearch({
|
||||
goods_code: String(allocAttrQuery.goods_code || '').trim() || undefined,
|
||||
rdc_warehouse_code: String(allocAttrQuery.rdc_warehouse_code || '').trim() || undefined,
|
||||
fdc_warehouse_code: String(allocAttrQuery.fdc_warehouse_code || '').trim() || undefined,
|
||||
page: allocAttrPickPage.value,
|
||||
limit: ALLOC_ATTR_PICK_PAGE_SIZE,
|
||||
})
|
||||
const enriched = enrichWarehouseOpsRows(res.list || [], {
|
||||
warehouseOptions: warehouseOptions.value,
|
||||
})
|
||||
@@ -314,14 +446,64 @@ async function loadAllocAttrOptions() {
|
||||
if (!opt || map.has(opt.alloc_attr_code)) continue
|
||||
map.set(opt.alloc_attr_code, opt)
|
||||
}
|
||||
allocAttrOptions.value = [...map.values()]
|
||||
} catch {
|
||||
allocAttrOptions.value = []
|
||||
allocAttrPickRows.value = [...map.values()]
|
||||
allocAttrPickTotal.value = res.total || allocAttrPickRows.value.length
|
||||
} catch (e) {
|
||||
allocAttrPickRows.value = []
|
||||
allocAttrPickTotal.value = 0
|
||||
ElMessage.error(pickApiErrorMessage(e, '搜索失败'))
|
||||
} finally {
|
||||
allocAttrLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function loadAllocAttrPickPage() {
|
||||
void searchAllocAttrPick(false)
|
||||
}
|
||||
|
||||
function selectAllocAttrPick(opt) {
|
||||
allocAttrPickSelected.value = opt?.alloc_attr_code || ''
|
||||
allocAttrPickSelectedOption.value = opt || null
|
||||
}
|
||||
|
||||
function resetAllocAttrPick() {
|
||||
allocAttrQuery.goods_code = ''
|
||||
allocAttrQuery.rdc_warehouse_code = ''
|
||||
allocAttrQuery.fdc_warehouse_code = ''
|
||||
allocAttrPickRows.value = []
|
||||
allocAttrPickSelected.value = ''
|
||||
allocAttrPickSelectedOption.value = null
|
||||
allocAttrPickQueried.value = false
|
||||
allocAttrPickPage.value = 1
|
||||
allocAttrPickTotal.value = 0
|
||||
}
|
||||
|
||||
function openAllocAttrPickDlg() {
|
||||
resetAllocAttrPick()
|
||||
allocAttrPickSelected.value = String(addForm.alloc_attr_code || '').trim()
|
||||
allocAttrPickVisible.value = true
|
||||
}
|
||||
|
||||
function onAllocAttrPickOpened() {
|
||||
void searchAllocAttrPick(true)
|
||||
}
|
||||
|
||||
function confirmAllocAttrPick() {
|
||||
const code = String(allocAttrPickSelected.value || '').trim()
|
||||
if (!code) return
|
||||
const hit = allocAttrPickSelectedOption.value
|
||||
|| allocAttrPickRows.value.find((opt) => opt.alloc_attr_code === code)
|
||||
addForm.alloc_attr_code = code
|
||||
addFormAllocAttrLabel.value = hit?.label || code
|
||||
allocAttrPickVisible.value = false
|
||||
addFormRef.value?.validateField?.('alloc_attr_code')
|
||||
}
|
||||
|
||||
function resetAllocAttrSearch() {
|
||||
resetAllocAttrPick()
|
||||
addFormAllocAttrLabel.value = ''
|
||||
}
|
||||
|
||||
async function loadWarehouses() {
|
||||
try {
|
||||
const list = await warehouseListed({})
|
||||
@@ -341,9 +523,13 @@ async function loadWarehouses() {
|
||||
|
||||
function openAddDlg() {
|
||||
const preset = filters.alloc_attr_code || ''
|
||||
resetAllocAttrSearch()
|
||||
Object.assign(addForm, emptyAddForm(), {
|
||||
alloc_attr_code: preset,
|
||||
})
|
||||
if (preset) {
|
||||
addFormAllocAttrLabel.value = preset
|
||||
}
|
||||
addDlgVisible.value = true
|
||||
}
|
||||
|
||||
@@ -494,6 +680,120 @@ onMounted(async () => {
|
||||
.whw-form-num {
|
||||
width: 100%;
|
||||
}
|
||||
.whw-attr-code-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
.whw-attr-code-row :deep(.el-input) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.whw-attr-picked-label {
|
||||
margin: 6px 0 0;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
line-height: 1.4;
|
||||
word-break: break-all;
|
||||
}
|
||||
.whw-attr-pick-filters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.whw-attr-pick-filter {
|
||||
width: 180px;
|
||||
}
|
||||
.whw-attr-pick-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.whw-attr-pick-body {
|
||||
height: 320px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
.whw-attr-pick-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
.whw-attr-pick-pager {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.whw-attr-pick-empty-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.whw-attr-pick-empty {
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
.whw-attr-pick-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
background: #fff;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: background .12s;
|
||||
}
|
||||
.whw-attr-pick-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.whw-attr-pick-item:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
.whw-attr-pick-item.is-active {
|
||||
background: #ecf5ff;
|
||||
}
|
||||
.whw-attr-pick-code {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
font-family: ui-monospace, monospace;
|
||||
}
|
||||
.whw-attr-pick-code::before {
|
||||
content: '配货属性 ';
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
color: #909399;
|
||||
}
|
||||
.whw-attr-pick-meta {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.whw-attr-pick-tag {
|
||||
color: #909399;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.whw-attr-pick-sep {
|
||||
margin: 0 4px;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
.whw-form-num :deep(.el-input__inner) {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user