fix(web-admin): 补齐捐赠查看操作日志接线并保留审核动作语义
修复 DonationViewDialog 缺失的操作日志状态与加载调用,清理误插入的重置语句,并避免显式 audit 动作被状态映射覆盖。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
4a12d92631
commit
ac9db561a4
4 files changed
+92
-7
No files matched your search
@@ -61,12 +61,15 @@ def resolve_action_from_status(
|
||||
before_status: Optional[str] = None,
|
||||
after_status: Optional[str] = None,
|
||||
) -> str:
|
||||
"""状态流转优先映射为更具体的动作;否则沿用 default_action。"""
|
||||
"""仅对 update 默认动作按状态流转细化;显式动作(create/delete/audit 等)保持原值。"""
|
||||
action = (default_action or "").strip() or ACTION_UPDATE
|
||||
if action != ACTION_UPDATE:
|
||||
return action
|
||||
before = (before_status or "").strip()
|
||||
after = (after_status or "").strip()
|
||||
if after and after != before and after in _STATUS_ACTION_MAP:
|
||||
return _STATUS_ACTION_MAP[after]
|
||||
return default_action
|
||||
return action
|
||||
|
||||
|
||||
def _operator_name(db: Session, user_id: Optional[str]) -> str:
|
||||
|
||||
@@ -116,7 +116,9 @@ def test_record_cell_update_appends_before_after_and_maps_void_action():
|
||||
|
||||
def test_resolve_action_from_status_keeps_default_when_unchanged():
|
||||
from app.crud.protocol_operation_log import (
|
||||
ACTION_AUDIT,
|
||||
ACTION_UPDATE,
|
||||
ACTION_VOID,
|
||||
resolve_action_from_status,
|
||||
)
|
||||
|
||||
@@ -128,3 +130,19 @@ def test_resolve_action_from_status_keeps_default_when_unchanged():
|
||||
)
|
||||
== ACTION_UPDATE
|
||||
)
|
||||
assert (
|
||||
resolve_action_from_status(
|
||||
default_action=ACTION_UPDATE,
|
||||
before_status="sxz",
|
||||
after_status="yzf",
|
||||
)
|
||||
== ACTION_VOID
|
||||
)
|
||||
assert (
|
||||
resolve_action_from_status(
|
||||
default_action=ACTION_AUDIT,
|
||||
before_status="dsx",
|
||||
after_status="sxz",
|
||||
)
|
||||
== ACTION_AUDIT
|
||||
)
|
||||
@@ -2196,7 +2196,6 @@
|
||||
async function loadStatusChangeRecords() {
|
||||
if (!props.protocolId) {
|
||||
statusChangeRecords.value = []
|
||||
operationLogRecords.value = []
|
||||
return
|
||||
}
|
||||
statusChangeLoading.value = true
|
||||
@@ -2205,7 +2204,6 @@
|
||||
statusChangeRecords.value = res.list || []
|
||||
} catch {
|
||||
statusChangeRecords.value = []
|
||||
operationLogRecords.value = []
|
||||
} finally {
|
||||
statusChangeLoading.value = false
|
||||
}
|
||||
|
||||
@@ -636,9 +636,72 @@
|
||||
const loading = ref(false)
|
||||
const auditLoading = ref(false)
|
||||
const statusChangeLoading = ref(false)
|
||||
const operationLogLoading = ref(false)
|
||||
const bundle = ref<Record<string, any> | null>(null)
|
||||
const auditRecords = ref<Array<Record<string, unknown>>>([])
|
||||
const statusChangeRecords = ref<Array<Record<string, unknown>>>([])
|
||||
const operationLogRecords = ref<Array<Record<string, unknown>>>([])
|
||||
|
||||
const OPERATION_ACTION_LABEL: Record<string, string> = {
|
||||
create: '创建',
|
||||
update: '修改',
|
||||
delete: '删除',
|
||||
void: '作废',
|
||||
activate: '生效',
|
||||
expire: '过期',
|
||||
to_research: '转科研',
|
||||
to_storage: '转细胞存储',
|
||||
audit: '审核'
|
||||
}
|
||||
const OPERATION_ACTION_TAG: Record<
|
||||
string,
|
||||
'success' | 'warning' | 'danger' | 'primary' | 'info'
|
||||
> = {
|
||||
create: 'success',
|
||||
update: 'primary',
|
||||
delete: 'danger',
|
||||
void: 'danger',
|
||||
activate: 'success',
|
||||
expire: 'warning',
|
||||
to_research: 'primary',
|
||||
to_storage: 'primary',
|
||||
audit: 'info'
|
||||
}
|
||||
|
||||
function operationActionLabel(action: string) {
|
||||
return OPERATION_ACTION_LABEL[action] || action || '—'
|
||||
}
|
||||
function operationActionTagType(action: string) {
|
||||
return OPERATION_ACTION_TAG[action] || 'info'
|
||||
}
|
||||
function operationChannelLabel(channel: string) {
|
||||
if (channel === 'mini') return '小程序'
|
||||
if (channel === 'web') return 'Web'
|
||||
return channel || '—'
|
||||
}
|
||||
function operationSummary(row: Record<string, unknown>) {
|
||||
const before = (row.before || {}) as Record<string, any>
|
||||
const after = (row.after || {}) as Record<string, any>
|
||||
const beforeProto = (before.donation || before.protocol || {}) as Record<string, any>
|
||||
const afterProto = (after.donation || after.protocol || {}) as Record<string, any>
|
||||
const beforeParty = (before.party || before.partyCustomer || {}) as Record<string, any>
|
||||
const afterParty = (after.party || after.partyCustomer || {}) as Record<string, any>
|
||||
const parts: string[] = []
|
||||
const bs = String(beforeProto.donationStatus || beforeProto.protocolStatus || '')
|
||||
const as = String(afterProto.donationStatus || afterProto.protocolStatus || '')
|
||||
if (bs && as && bs !== as) parts.push(`状态 ${bs}→${as}`)
|
||||
else if (as) parts.push(`状态 ${as}`)
|
||||
for (const key of ['motherName', 'customerName', 'donorName', 'name']) {
|
||||
const b = String(beforeParty[key] || '').trim()
|
||||
const a = String(afterParty[key] || '').trim()
|
||||
if (b || a) {
|
||||
if (b && a && b !== a) parts.push(`姓名 ${b}→${a}`)
|
||||
else if (a && !b) parts.push(`姓名 ${a}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
return parts.join(';') || String(row.remark || '').trim() || '见前后快照'
|
||||
}
|
||||
|
||||
const STATUS_CHANGE_TYPE_LABEL: Record<string, string> = {
|
||||
activate: '生效',
|
||||
@@ -982,7 +1045,6 @@
|
||||
async function loadStatusChangeRecords() {
|
||||
if (!props.donationId) {
|
||||
statusChangeRecords.value = []
|
||||
operationLogRecords.value = []
|
||||
return
|
||||
}
|
||||
statusChangeLoading.value = true
|
||||
@@ -991,7 +1053,6 @@
|
||||
statusChangeRecords.value = res.list || []
|
||||
} catch {
|
||||
statusChangeRecords.value = []
|
||||
operationLogRecords.value = []
|
||||
} finally {
|
||||
statusChangeLoading.value = false
|
||||
}
|
||||
@@ -1045,7 +1106,11 @@
|
||||
const data = await fetchResearchDonationDetail(props.donationId)
|
||||
bundle.value = data as Record<string, any>
|
||||
await loadLookups(data as Record<string, any>)
|
||||
await Promise.all([loadAuditRecords(), loadStatusChangeRecords()])
|
||||
await Promise.all([
|
||||
loadAuditRecords(),
|
||||
loadStatusChangeRecords(),
|
||||
loadOperationLogRecords()
|
||||
])
|
||||
if (props.highlightSampleCode) {
|
||||
nextTick(() => {
|
||||
document
|
||||
@@ -1077,6 +1142,7 @@
|
||||
loading.value = false
|
||||
auditLoading.value = false
|
||||
statusChangeLoading.value = false
|
||||
operationLogLoading.value = false
|
||||
}
|
||||
|
||||
watch(
|
||||
|
||||
Reference in new issue
Block a user