chore: add the mobile market contract dependency closure.

This commit is contained in:
zlwu committed 2026-10-11 13:14:56 +08:00
1 parent 0c4a2408ee
commit 0927a514d2
9 files changed
+357

No files matched your search

@@ -0,0 +1,18 @@
import freight from './modules/freight.js'
import paymentChase from './modules/payment-chase.js'
import payment from './modules/payment.js'
import presign from './modules/presign.js'
import protocol from './modules/protocol.js'
import sample from './modules/sample.js'
const MODULES = Object.freeze({ presign, protocol, 'payment-chase': paymentChase, payment, sample, freight })
export function getMarketModule(module) {
const value = MODULES[module]
if (!value) throw new Error('市场页面配置无效')
return value
}
export function getMarketListParams(module, filters) {
return getMarketModule(module).listParams?.(filters) || {}
}
@@ -0,0 +1,21 @@
export default {
key: 'freight',
resource: 'freights',
actions: {
specialist: ['view', 'create', 'edit', 'link', 'unlink'],
manager: ['view', 'create', 'edit', 'link', 'unlink']
},
listParams: ({ status } = {}) => ({ transportMode: status || '' }),
statusOptions: [{ text: '全部运输方式', value: '' }],
usesPagedSampleOptions(action) {
return ['create', 'link'].includes(action)
},
sampleOptions(action, detailItems, optionRows) {
if (action === 'unlink') return Array.isArray(detailItems) ? detailItems : []
return (Array.isArray(optionRows) ? optionRows : []).filter((item) => !item.freightId)
},
formSections: [{ key: 'base', title: '运费批次', fields: [
{ key: 'transportMode', label: '运输方式', type: 'select', optionKey: 'transportModes', required: true },
{ key: 'freightAmount', label: '运费金额', type: 'number', required: true }
] }]
}
@@ -0,0 +1,19 @@
export default {
key: 'payment-chase',
resource: 'payment-chase',
readOnly: true,
actions: { specialist: ['view-payment'], manager: ['view-payment'] },
listParams: ({ status } = {}) => ({ chaseType: status || '' }),
statusOptions: [
{ text: '全部催缴', value: '' },
{ text: '已逾期', value: 'overdue' },
{ text: '未来 30 天', value: 'upcoming' }
],
detailTarget(item) {
return {
module: 'payment',
id: String(item?.samplePaymentId || ''),
query: item?.scheduleId ? { scheduleId: String(item.scheduleId) } : {}
}
}
}
@@ -0,0 +1,28 @@
export default {
key: 'payment',
resource: 'payments',
actions: {
specialist: ['view', 'register-transfer', 'edit-transfer', 'submit', 'withdraw'],
manager: ['view', 'register-transfer', 'edit-transfer', 'submit', 'withdraw']
},
listParams: ({ status } = {}) => ({ payMode: status || '' }),
statusOptions: [{ text: '全部缴费模式', value: '' }],
initialForm(detail, target = {}) {
const transfer = (detail?.schedules || [])
.flatMap((row) => row.transfers || [])
.find((row) => String(row.id || '') === String(target.transferId || '')) || {}
const fields = ['transferAmount', 'transferTime', 'transferType', 'transferAttachments', 'remark']
return {
transfer: Object.fromEntries(fields
.filter((key) => Object.prototype.hasOwnProperty.call(transfer, key))
.map((key) => [key, transfer[key]]))
}
},
transferFields: [
{ key: 'transferAmount', label: '转账金额', type: 'number', required: true },
{ key: 'transferTime', label: '转账时间', type: 'datetime' },
{ key: 'transferType', label: '转账方式', type: 'select', optionKey: 'transferTypes', required: true },
{ key: 'transferAttachments', label: '转账凭证', type: 'upload' },
{ key: 'remark', label: '备注', type: 'textarea' }
]
}
@@ -0,0 +1,42 @@
import { commonFields } from './shared.js'
export default {
key: 'presign',
resource: 'presign-orders',
actions: {
specialist: ['view', 'create', 'edit', 'convert'],
manager: ['view', 'create', 'edit', 'convert']
},
listParams: ({ status } = {}) => ({ orderStatus: status || '' }),
statusOptions: [
{ text: '全部状态', value: '' },
{ text: '预签约', value: 'yqy' },
{ text: '已转正式', value: 'yzs' }
],
formSections: [
{
key: 'base', title: '预签信息', fields: [
{ key: 'orderDate', label: '预签日期', type: 'date' },
{ key: 'protocolNo', label: '协议编号' },
{ key: 'motherName', label: '客户姓名', required: true },
{ key: 'expectedDeliveryDate', label: '预产期', type: 'date' },
{ key: 'regionId', label: '采集地区', type: 'select', optionKey: 'regions' },
{ key: 'hospitalId', label: '采集医院', type: 'select', optionKey: 'hospitals' },
{ key: 'sampleCollectTime', label: '采集时间', type: 'datetime' },
{ key: 'payMode', label: '缴费模式' },
{ key: 'sampleTypeIds', label: '样本类型', type: 'multi-select', optionKey: 'sampleTypes' },
{ key: 'contractAmount', label: '合同金额', type: 'number' },
{ key: 'remark', ...commonFields.remark }
]
},
{
key: 'transfers', title: '意向金', repeat: true, createOnly: true, fields: [
{ key: 'transferAmount', label: '转账金额', type: 'number' },
{ key: 'transferTime', label: '转账时间', type: 'datetime' },
{ key: 'transferType', label: '转账方式' },
{ key: 'transferAttachments', label: '转账附件', type: 'upload' },
{ key: 'remark', ...commonFields.remark }
]
}
]
}
@@ -0,0 +1,78 @@
import { section } from './shared.js'
const labels = {
protocolNo: '协议编号', donationNo: '捐赠编号', registerDate: '登记日期',
donationDate: '捐赠日期', motherName: '母亲姓名', motherPhone: '联系电话',
regionName: '采集地区', hospitalName: '采集医院', sampleCode: '样本编码',
payMode: '缴费模式', protocolAttachments: '协议附件'
}
export default {
key: 'protocol',
resource: 'protocols',
actions: { specialist: ['view', 'create', 'edit'], manager: ['view', 'create', 'edit'] },
listParams: ({ status } = {}) => ({ source: status || '' }),
statusOptions: [
{ text: '全部来源', value: '' },
{ text: '细胞存储', value: 'cell_storage' },
{ text: '科研捐赠', value: 'research_donation' }
],
detailSections(detail) {
if (Array.isArray(detail?.sections)) return detail.sections
const values = [
section('protocol', '协议信息', detail?.protocol || detail?.basic || detail, labels),
section('collection', '采集信息', detail?.collection, labels),
section('customer', '客户信息', detail?.customer, labels),
section('samples', '样本信息', { samples: detail?.samples }, labels)
]
if (detail?.source === 'cell_storage' || detail?.payment) {
values.push(section('payment', '缴费信息', detail?.payment, labels))
}
values.push(section('attachments', '附件信息', detail?.attachments, labels))
return values
},
formSections: [
{ key: 'protocol', title: '协议信息', fields: [
{ key: 'source', label: '业务来源', type: 'tabs', required: true, createOnly: true, options: [
{ text: '细胞存储', value: 'cell_storage' }, { text: '科研捐赠', value: 'research_donation' }
] },
{ key: 'protocolNo', label: '协议编号', source: 'cell_storage' },
{ key: 'donationNo', label: '捐赠编号', source: 'research_donation' },
{ key: 'registerDate', label: '登记日期', type: 'date', source: 'cell_storage' },
{ key: 'donationDate', label: '捐赠日期', type: 'date', source: 'research_donation' },
{ key: 'protocolTotalAmount', label: '协议总金额', type: 'number', source: 'cell_storage' },
{ key: 'remark', label: '备注', type: 'textarea' }
] },
{ key: 'collection', title: '采集信息', nested: true, fields: [
{ key: 'regionId', label: '采集地区', type: 'select', optionKey: 'regions' },
{ key: 'hospitalId', label: '采集医院', type: 'select', optionKey: 'hospitals' },
{ key: 'sampleCollectTime', label: '采集时间', type: 'datetime' }
] },
{ key: 'customer', title: '客户信息', nested: true, fields: [
{ key: 'motherName', label: '母亲姓名', required: true },
{ key: 'motherPhone', label: '联系电话', type: 'tel' },
{ key: 'motherIdCard', label: '证件号码' },
{ key: 'expectedDeliveryDate', label: '预产期', type: 'date' }
] },
{ key: 'samples', title: '样本信息', repeat: true, fields: [
{ key: 'sampleTypeId', label: '样本类型', type: 'select', optionKey: 'sampleTypes' },
{ key: 'sampleCode', label: '样本编码' },
{ key: 'storageYears', label: '存储年限', type: 'number', source: 'cell_storage' }
] },
{ key: 'payment', title: '缴费信息(只读)', nested: true, readOnly: true, editOnly: true, source: 'cell_storage', fields: [
{ key: 'payMode', label: '缴费模式', readOnly: true },
{ key: 'contractAmount', label: '合同金额', readOnly: true },
{ key: 'remark', label: '缴费备注', readOnly: true }
] },
{ key: 'attachments', title: '附件与确认', nested: true, fields: [
{ key: 'protocolAttachments', label: '协议附件', type: 'upload', source: 'cell_storage' },
{ key: 'consentFormUrls', label: '知情同意书', type: 'upload' },
{ key: 'healthSurveyFormUrls', label: '健康调查表', type: 'upload', source: 'cell_storage' },
{ key: 'attachmentUrls', label: '其他附件', type: 'upload', source: 'research_donation' },
{ key: 'infectiousDiseaseReportUrls', label: '传染病报告', type: 'upload', source: 'research_donation' }
] },
{ key: 'confirm', title: '提交确认', nested: true, uiOnly: true, fields: [
{ key: 'confirmed', label: '我已核对以上信息', type: 'checkbox', required: true }
] }
]
}
+30
View File
@@ -0,0 +1,30 @@
export default {
key: 'sample',
resource: 'samples',
readOnlySources: ['research_donation'],
actions: { specialist: ['view', 'storage-cert', 'insurance'], manager: ['view', 'storage-cert', 'insurance'] },
listParams: ({ status } = {}) => ({ status: status || '' }),
statusOptions: [{ text: '全部状态', value: '' }],
formOptionsParams(sampleId) {
return { sampleId: String(sampleId || '').trim() }
},
initialForm(detail, action) {
const handles = (detail?.sections || []).find((section) => section.key === 'market-handles') || {}
const handle = action === 'insurance' ? handles.insurance || {} : handles.storageCert || {}
const fields = ['handleTime', 'handlerUserId', 'attachments', 'remark']
return {
handle: Object.fromEntries(fields
.filter((key) => Object.prototype.hasOwnProperty.call(handle, key))
.map((key) => [key, handle[key]]))
}
},
detailSections(detail) {
return Array.isArray(detail?.sections) ? detail.sections : []
},
handleFields: [
{ key: 'handleTime', label: '办理时间', type: 'datetime' },
{ key: 'handlerUserId', label: '办理人员', type: 'select', optionKey: 'users' },
{ key: 'attachments', label: '附件', type: 'upload' },
{ key: 'remark', label: '备注', type: 'textarea' }
]
}
+13
View File
@@ -0,0 +1,13 @@
export function objectFields(source, labels = {}) {
return Object.entries(source || {})
.filter(([, value]) => value != null && typeof value !== 'object')
.map(([key, value]) => ({ label: labels[key] || key, value }))
}
export function section(key, title, value, labels) {
return { key, title, fields: objectFields(value, labels), raw: value }
}
export const commonFields = {
remark: { label: '备注', type: 'textarea' }
}
+108
View File
@@ -0,0 +1,108 @@
export const MARKET_MODULES = [
'presign',
'protocol',
'payment-chase',
'payment',
'sample',
'freight'
]
export const MARKET_ROLES = ['specialist', 'manager']
export const MARKET_MODULE_TITLES = Object.freeze({
presign: '预签约订单',
protocol: '协议单',
'payment-chase': '催缴信息',
payment: '缴费信息',
sample: '样本信息',
freight: '运费信息'
})
export const MARKET_ROLE_TITLES = Object.freeze({
specialist: '市场专员',
manager: '地区经理'
})
function isMarketRole(value) {
return MARKET_ROLES.includes(value)
}
function isMarketModule(value) {
return MARKET_MODULES.includes(value)
}
export function getMarketRouteContext(route) {
const marketRole = route?.meta?.marketRole
const module = route?.meta?.module
if (!isMarketRole(marketRole) || !isMarketModule(module)) {
throw new Error('市场页面配置无效')
}
return { marketRole, module }
}
export function shouldLoadMarketListAfterDetail({ previousDetailId, detailId }) {
return Boolean(String(previousDetailId || '').trim()) && !String(detailId || '').trim()
}
export function pickMarketNavigationQuery(query) {
const returnPath = String(query?.returnPath || '').trim()
return returnPath.startsWith('/pages/') && !returnPath.startsWith('//')
? { returnPath }
: {}
}
export function marketRecordNavigationQuery(module, item, query) {
const result = pickMarketNavigationQuery(query)
const source = String(item?.source || '').trim()
if (module === 'protocol' && ['cell_storage', 'research_donation'].includes(source)) {
result.source = source
}
return result
}
export function resolveMarketSavedDetailId(module, currentId, result, action) {
const current = String(currentId || '').trim()
if (module === 'freight' && action === 'unlink' && result?.disappeared === true) return ''
if (module === 'payment' && current) return current
return String(result?.id || current).trim()
}
const listComponent = () => import('../views/market/MarketModuleList.vue')
const detailComponent = () => import('../views/market/MarketModuleDetail.vue')
const formComponent = () => import('../views/market/MarketModuleForm.vue')
export const marketRoutes = MARKET_ROLES.flatMap((marketRole) =>
MARKET_MODULES.map((module) => {
const meta = {
marketRole,
module,
title: MARKET_MODULE_TITLES[module]
}
return {
path: `/market/${marketRole}/${module}`,
name: `market-${marketRole}-${module}`,
component: listComponent,
meta,
children: [
{
path: 'new',
name: `market-${marketRole}-${module}-new`,
component: formComponent,
meta: { ...meta, formMode: 'create' }
},
{
path: ':id/edit',
name: `market-${marketRole}-${module}-edit`,
component: formComponent,
meta: { ...meta, formMode: 'edit' }
},
{
path: ':id',
name: `market-${marketRole}-${module}-detail`,
component: detailComponent,
meta: { ...meta, detail: true }
}
]
}
})
)