fix(mobile-oa-h5): align presign and freight tags with registry mirror
Use info for draft; full payMode codes; receptionSource/transportType colors. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
7ba336169a
commit
2b5f2f939c
7 files changed
+86
-63
No files matched your search
@@ -75,7 +75,6 @@
|
||||
v-if="can('submit')"
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="passed"
|
||||
:loading="busyAction === 'submit-transfer'"
|
||||
:disabled="busy"
|
||||
@click="$emit('submit-transfer', modelValue)"
|
||||
@@ -85,7 +84,6 @@
|
||||
type="warning"
|
||||
plain
|
||||
size="small"
|
||||
icon="revoke"
|
||||
:loading="busyAction === 'withdraw-transfer'"
|
||||
:disabled="busy"
|
||||
@click="$emit('withdraw-transfer', modelValue)"
|
||||
@@ -97,7 +95,6 @@
|
||||
type="danger"
|
||||
plain
|
||||
size="small"
|
||||
icon="delete-o"
|
||||
:disabled="busy"
|
||||
@click="$emit('remove', modelValue)"
|
||||
>删除</van-button>
|
||||
@@ -110,6 +107,7 @@ import { computed } from 'vue'
|
||||
import OaDatePicker from '../../oa/components/OaDatePicker.vue'
|
||||
import OaMoneyField from '../../oa/components/OaMoneyField.vue'
|
||||
import { removeMarketAttachmentAt } from '../attachment-upload-state.js'
|
||||
import { resolveStatusTag, payStatus } from '../status-tag-registry.js'
|
||||
import PresignAttachmentUploader from './PresignAttachmentUploader.vue'
|
||||
import PresignSelectField from './PresignSelectField.vue'
|
||||
|
||||
@@ -142,21 +140,11 @@ const canDelete = computed(() => !props.disabled && (newRow.value || actionSet.v
|
||||
const busy = computed(() => Boolean(props.busyAction) || props.uploading)
|
||||
const showActions = computed(() => canDelete.value || can('submit') || can('withdraw'))
|
||||
|
||||
const statusLabel = computed(() => ({
|
||||
dfj: '已付款',
|
||||
jfqrz: '付款确认中',
|
||||
yjf: '付款完成',
|
||||
tfqrz: '退费确认中',
|
||||
ytf: '已退费'
|
||||
}[String(props.modelValue.payStatus || 'dfj')] || '已付款'))
|
||||
|
||||
const statusTone = computed(() => ({
|
||||
dfj: 'default',
|
||||
jfqrz: 'warning',
|
||||
yjf: 'success',
|
||||
tfqrz: 'warning',
|
||||
ytf: 'default'
|
||||
}[String(props.modelValue.payStatus || 'dfj')] || 'default'))
|
||||
const statusTag = computed(() =>
|
||||
resolveStatusTag(payStatus, props.modelValue.payStatus || 'dfj')
|
||||
)
|
||||
const statusLabel = computed(() => statusTag.value.label)
|
||||
const statusTone = computed(() => statusTag.value.tagType)
|
||||
|
||||
function can(action) {
|
||||
return !props.disabled && actionSet.value.has(action)
|
||||
|
||||
@@ -5,7 +5,9 @@ import {
|
||||
payMode,
|
||||
protocolStatus,
|
||||
donationStatus,
|
||||
paymentChaseStatus
|
||||
paymentChaseStatus,
|
||||
receptionSource,
|
||||
transportType
|
||||
} from './status-tag-registry.js'
|
||||
|
||||
const SEARCH_PLACEHOLDERS = Object.freeze({
|
||||
@@ -298,10 +300,12 @@ function freightSampleBlock(row, index) {
|
||||
const title = sampleCode
|
||||
? `样本 ${index + 1} · ${sampleCode}`
|
||||
: `样本 ${index + 1}`
|
||||
const source = resolveStatusTag(receptionSource, row?.sampleSource)
|
||||
return {
|
||||
key: String(row?.id || row?.sampleId || `${sampleCode || 'sample'}-${index}`),
|
||||
title,
|
||||
status: label(SOURCE_LABELS, row?.sampleSource),
|
||||
status: source.label,
|
||||
statusTone: source.tagType,
|
||||
fields: [
|
||||
field('协议号', row?.protocolNo, { wide: true }),
|
||||
field('母亲姓名', row?.motherName),
|
||||
@@ -312,18 +316,30 @@ function freightSampleBlock(row, index) {
|
||||
}
|
||||
}
|
||||
|
||||
function freightTransportDisplay(item) {
|
||||
const code = String(item?.transportMode || '').trim()
|
||||
const provided = String(item?.transportModeLabel || '').trim()
|
||||
if (provided && provided !== code) return provided
|
||||
if (!code && !provided) return '—'
|
||||
if (!code) return provided
|
||||
return resolveStatusTag(transportType, code).label
|
||||
}
|
||||
|
||||
function freightCard(role, item) {
|
||||
const rows = Array.isArray(item.items) ? item.items : []
|
||||
const first = rows[0] || {}
|
||||
const transportMode = label({}, item.transportModeLabel || item.transportMode)
|
||||
const source = label(SOURCE_LABELS, first.sampleSource || item.sourceLabel)
|
||||
const transportCode = String(item.transportMode || '').trim()
|
||||
const transportTag = resolveStatusTag(transportType, transportCode)
|
||||
const transportMode = freightTransportDisplay(item)
|
||||
const source = resolveStatusTag(receptionSource, first.sampleSource || item.sourceLabel)
|
||||
const sampleCount = Number(item.visibleItemCount ?? rows.length) || 0
|
||||
return {
|
||||
title: text(item.freightNo),
|
||||
subtitle: `${transportMode} · ${money(item.freightAmount)}`,
|
||||
status: source,
|
||||
status: source.label,
|
||||
statusTone: source.tagType,
|
||||
fields: [
|
||||
field('运输方式', transportMode, { tag: true }),
|
||||
field('运输方式', transportMode, { tag: true, tagType: transportTag.tagType }),
|
||||
field('运费金额', money(item.freightAmount), { money: true }),
|
||||
field('关联数', String(sampleCount)),
|
||||
field('创建人', personName(item.creatorName || item.createByName, item.createBy)),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
const SOURCE_LABELS = Object.freeze({ cell_storage: '细胞存储', research_donation: '科研捐赠' })
|
||||
import { resolveStatusTag, receptionSource, transportType } from '../status-tag-registry.js'
|
||||
|
||||
function dictionaryLabel(map, code, providedLabel) {
|
||||
const label = String(providedLabel || '').trim()
|
||||
function transportDisplay(code, providedLabel) {
|
||||
const key = String(code || '').trim()
|
||||
const label = String(providedLabel || '').trim()
|
||||
if (label && label !== key) return label
|
||||
return map[key] || (key ? '未知' : '—')
|
||||
if (!key) return '—'
|
||||
return resolveStatusTag(transportType, key).label
|
||||
}
|
||||
|
||||
function person(name, id) {
|
||||
@@ -24,29 +25,39 @@ export default {
|
||||
key: 'freight',
|
||||
resource: 'freights',
|
||||
actions: {
|
||||
specialist: ['view', 'create', 'edit', 'link', 'unlink'],
|
||||
manager: ['view', 'create', 'edit', 'link', 'unlink']
|
||||
specialist: ['view', 'create', 'edit', 'delete', 'link', 'unlink'],
|
||||
manager: ['view', 'create', 'edit', 'delete', 'link', 'unlink']
|
||||
},
|
||||
listParams: ({ status } = {}) => ({ transportMode: status || '', includeItems: true }),
|
||||
statusOptions: [{ text: '全部运输方式', value: '' }],
|
||||
filterFields: [
|
||||
{ key: 'transportMode', label: '运输方式', type: 'select', optionKey: 'transportModes' },
|
||||
// 运费列表用搜索下方 van-dropdown-menu(对齐预签约),不走筛选弹层
|
||||
filterFields: [],
|
||||
inlineDropdownFilters: [
|
||||
{ key: 'transportMode', allText: '全部运输方式', optionKey: 'transportModes' },
|
||||
{
|
||||
key: 'sampleSource', label: '样本来源', type: 'select', options: [
|
||||
key: 'sampleSource',
|
||||
allText: '全部样本来源',
|
||||
options: [
|
||||
{ text: '细胞存储', value: 'cell_storage' },
|
||||
{ text: '科研捐赠', value: 'research_donation' }
|
||||
]
|
||||
},
|
||||
{ key: 'createTimeRange', label: '创建时间', type: 'date-range' }
|
||||
}
|
||||
],
|
||||
detailSections(detail) {
|
||||
const transportCode = String(detail?.transportMode || '').trim()
|
||||
const transportTag = resolveStatusTag(transportType, transportCode)
|
||||
return [
|
||||
{
|
||||
key: 'base',
|
||||
title: '运费信息',
|
||||
fields: [
|
||||
{ label: '批次号', value: detail?.freightNo || '—' },
|
||||
{ label: '运输方式', value: dictionaryLabel({}, detail?.transportMode, detail?.transportModeLabel), tag: true, tagType: 'primary' },
|
||||
{
|
||||
label: '运输方式',
|
||||
value: transportDisplay(transportCode, detail?.transportModeLabel),
|
||||
tag: true,
|
||||
tagType: transportTag.tagType
|
||||
},
|
||||
{ label: '运费金额', value: money(detail?.freightAmount) },
|
||||
{ label: '关联数', value: String(detail?.visibleItemCount ?? detail?.items?.length ?? 0) },
|
||||
{ label: '创建人', value: person(detail?.creatorName || detail?.createByName, detail?.createBy) },
|
||||
@@ -60,19 +71,23 @@ export default {
|
||||
key: 'items',
|
||||
title: '关联样本',
|
||||
fields: [],
|
||||
cards: (detail?.items || []).map((item, index) => ({
|
||||
cards: (detail?.items || []).map((item, index) => {
|
||||
const source = resolveStatusTag(receptionSource, item?.sampleSource)
|
||||
return {
|
||||
key: String(item?.id || `item-${index}`),
|
||||
title: item?.sampleCode || `样本 ${index + 1}`,
|
||||
statusText: dictionaryLabel(SOURCE_LABELS, item?.sampleSource),
|
||||
statusText: source.label,
|
||||
statusTone: source.tagType,
|
||||
fields: [
|
||||
{ label: '来源', value: dictionaryLabel(SOURCE_LABELS, item?.sampleSource) },
|
||||
{ label: '来源', value: source.label, tag: true, tagType: source.tagType },
|
||||
{ label: '协议单号', value: item?.protocolNo || '—' },
|
||||
{ label: '样本编码', value: item?.sampleCode || '—' },
|
||||
{ label: '样本类型', value: item?.sampleTypeName || '—' },
|
||||
{ label: '母亲姓名', value: item?.motherName || '—' },
|
||||
{ label: '子女姓名', value: item?.newbornName || '—' }
|
||||
]
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -83,8 +98,13 @@ export default {
|
||||
if (action === 'unlink') return Array.isArray(detailItems) ? detailItems : []
|
||||
return Array.isArray(optionRows) ? optionRows : []
|
||||
},
|
||||
formSections: [{ key: 'base', title: '运费批次', fields: [
|
||||
formSections: [{
|
||||
key: 'base',
|
||||
title: '运费批次',
|
||||
fieldsLayout: 'grid-2',
|
||||
fields: [
|
||||
{ key: 'transportMode', label: '运输方式', type: 'select', optionKey: 'transportModes', required: true },
|
||||
{ key: 'freightAmount', label: '运费金额', type: 'number', required: true }
|
||||
] }]
|
||||
]
|
||||
}]
|
||||
}
|
||||
@@ -6,14 +6,8 @@ import {
|
||||
presignStatusLabel,
|
||||
presignStatusTone
|
||||
} from '../presign/presign-presenter.js'
|
||||
import { resolveStatusTag, payMode, payStatus } from '../status-tag-registry.js'
|
||||
|
||||
const paymentStatus = Object.freeze({
|
||||
dfj: { label: '已付款', tone: 'default' },
|
||||
jfqrz: { label: '付款确认中', tone: 'warning' },
|
||||
yjf: { label: '付款完成', tone: 'success' },
|
||||
tfqrz: { label: '退费确认中', tone: 'warning' },
|
||||
ytf: { label: '已退费', tone: 'default' }
|
||||
})
|
||||
const transferTypeLabels = Object.freeze({
|
||||
wxzz: '微信转账', wx: '微信转账', wechat: '微信转账',
|
||||
zzbzz: '支付宝转账', zfb: '支付宝转账', alipay: '支付宝转账',
|
||||
@@ -51,6 +45,12 @@ function displayValue(value) {
|
||||
return value && value !== '-' ? value : '—'
|
||||
}
|
||||
|
||||
function payModeLabel(value) {
|
||||
const key = String(value || '').trim()
|
||||
if (!key) return '—'
|
||||
return resolveStatusTag(payMode, key).label
|
||||
}
|
||||
|
||||
export default {
|
||||
key: 'presign',
|
||||
resource: 'presign-orders',
|
||||
@@ -85,13 +85,12 @@ export default {
|
||||
detailSections(detail) {
|
||||
const status = String(detail?.orderStatus || '')
|
||||
const transfers = (detail?.transfers || []).map((transfer, index) => {
|
||||
const paymentCode = String(transfer?.payStatus || 'dfj')
|
||||
const payment = paymentStatus[paymentCode] || { label: '未知', tone: 'default' }
|
||||
const payment = resolveStatusTag(payStatus, transfer?.payStatus || 'dfj')
|
||||
return {
|
||||
...transfer,
|
||||
title: `意向金转账 ${index + 1}`,
|
||||
statusLabel: payment.label,
|
||||
statusTone: payment.tone,
|
||||
statusTone: payment.tagType,
|
||||
transferAmount: formatPresignMoney(transfer?.transferAmount),
|
||||
transferTime: formatPresignDateTime(transfer?.transferTime)
|
||||
}
|
||||
@@ -110,7 +109,7 @@ export default {
|
||||
{ label: '采集专员', value: person(detail?.collectorUserName, detail?.collectorUserId) },
|
||||
{ label: '采集经理', value: person(detail?.regionManagerUserName, detail?.regionManagerUserId) },
|
||||
{ label: '采集时间', value: displayValue(formatPresignDateTime(detail?.sampleCollectTime)) },
|
||||
{ label: '缴费方式', value: dictionaryLabel({ fq: '分期', dj: '趸交' }, detail?.payMode) },
|
||||
{ label: '缴费方式', value: payModeLabel(detail?.payMode) },
|
||||
{
|
||||
label: '样本类型',
|
||||
value: Array.isArray(detail?.sampleTypeNames) && detail.sampleTypeNames.length
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { intersectAllowedActions } from '../action-policy.js'
|
||||
import { resolveStatusTag, payMode } from '../status-tag-registry.js'
|
||||
import {
|
||||
formatPresignDate,
|
||||
formatPresignDateTime,
|
||||
@@ -9,7 +10,6 @@ import {
|
||||
} from './presign-presenter.js'
|
||||
|
||||
const CARD_ACTIONS = new Set(['edit', 'convert', 'delete'])
|
||||
const PAY_MODE_LABELS = Object.freeze({ dj: '趸交', fq: '分期', fgd: '分改趸', djfq: '趸交+分期' })
|
||||
|
||||
function displayText(value) {
|
||||
return String(value ?? '').trim() || '-'
|
||||
@@ -21,7 +21,8 @@ function actionCode(action) {
|
||||
|
||||
function payModeLabel(value) {
|
||||
const key = String(value || '').trim()
|
||||
return PAY_MODE_LABELS[key] || (key ? '未知' : '-')
|
||||
if (!key) return '-'
|
||||
return resolveStatusTag(payMode, key).label
|
||||
}
|
||||
|
||||
export function buildPresignListParams({ keyword = '', orderStatus = '', page = 1, pageSize = 10 } = {}) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
const PRESIGN_STATUS = Object.freeze({
|
||||
draft: Object.freeze({ label: '草稿', tone: 'default' }),
|
||||
active: Object.freeze({ label: '进行中', tone: 'warning' }),
|
||||
converted: Object.freeze({ label: '已转正式', tone: 'success' }),
|
||||
void: Object.freeze({ label: '已作废', tone: 'danger' })
|
||||
})
|
||||
import { resolveStatusTag, presignOrderStatus } from '../status-tag-registry.js'
|
||||
|
||||
function validDateParts(year, month, day) {
|
||||
const date = new Date(Date.UTC(year, month - 1, day))
|
||||
@@ -83,11 +78,13 @@ export function formatPresignMoney(value) {
|
||||
export function presignStatusLabel(value) {
|
||||
const code = String(value ?? '').trim()
|
||||
if (!code) return '-'
|
||||
return PRESIGN_STATUS[code]?.label || '未知'
|
||||
return resolveStatusTag(presignOrderStatus, code).label
|
||||
}
|
||||
|
||||
export function presignStatusTone(value) {
|
||||
return PRESIGN_STATUS[String(value ?? '').trim()]?.tone || 'default'
|
||||
const code = String(value ?? '').trim()
|
||||
if (!code) return 'info'
|
||||
return resolveStatusTag(presignOrderStatus, code).tagType
|
||||
}
|
||||
|
||||
export function presignCardIndex(page, pageSize, position) {
|
||||
|
||||
@@ -40,6 +40,8 @@ test('uses the Web presign status labels and mobile semantic tones', () => {
|
||||
assert.equal(presignStatusLabel('active'), '进行中')
|
||||
assert.equal(presignStatusLabel('converted'), '已转正式')
|
||||
assert.equal(presignStatusLabel('void'), '已作废')
|
||||
assert.equal(presignStatusTone('draft'), 'info')
|
||||
assert.notEqual(presignStatusTone('draft'), 'default')
|
||||
assert.equal(presignStatusTone('converted'), 'success')
|
||||
assert.equal(presignStatusTone('void'), 'danger')
|
||||
assert.equal(presignStatusLabel('custom'), '未知')
|
||||
|
||||
Reference in new issue
Block a user