Release/test 合并上生产 #2

Merged
admin merged 736 commits from release/test into main 2026-09-17 11:50:56 +08:00
2 changed files with 29 additions and 15 deletions
Showing only changes of commit ebbb4bc459 - Show all commits
@@ -29,8 +29,11 @@ describe('OceanBookingDetailView interaction contract', () => {
expect(source).not.toContain("customerId: [{ required: true")
expect(source).toContain('placeholder="请选择船公司"')
expect(source).toContain('placeholder="请选择订舱代理"')
expect(source).toContain("selectPartner('shippingCompany'")
expect(source).toContain("selectPartner('bookingAgent'")
expect(source).toContain('listSuppliers({ page: 1, size: 200, category: \'BOOKING\', status: \'ACTIVE\' })')
expect(source).toContain('selectShippingCompany')
expect(source).toContain('selectBookingAgent')
expect(source).toContain('bookingAgentLabel')
expect(source).toContain('暂无启用的订舱供应商')
expect(source).not.toContain('label="客户 ID"')
expect(source).not.toContain('label="船公司 ID"')
expect(source).not.toContain('label="订舱代理 ID"')
@@ -49,6 +52,7 @@ describe('OceanBookingDetailView interaction contract', () => {
expect(source).toContain("form.data.shippingCompanyName || '船公司名称缺失'")
expect(source).toContain("form.data.bookingAgentName || '订舱代理名称缺失'")
expect(source).toContain("from '@/modules/master-data'")
expect(source).toContain("from '@/modules/suppliers/api/platformSuppliers'")
})
it('renders the translated status once in the detail heading', () => {
@@ -14,6 +14,8 @@ import DetailPageLayout from '@/shared/components/DetailPageLayout.vue'
import PageToolbar from '@/shared/components/PageToolbar.vue'
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
import { listPlatformPartners, type PlatformPartnerResource } from '@/modules/master-data'
import { listSuppliers } from '@/modules/suppliers/api/platformSuppliers'
import type { Supplier } from '@/modules/suppliers/types'
import { listPlatformWarehouses, type PlatformWarehouseResource } from '@/modules/warehouses'
import {
createOceanBooking,
@@ -73,6 +75,7 @@ const actionError = ref<ReturnType<typeof getApiErrorDetails> | null>(null)
const formRef = ref<FormInstance>()
const customers = ref<PlatformTenantResource[]>([])
const partners = ref<PlatformPartnerResource[]>([])
const bookingSuppliers = ref<Supplier[]>([])
const warehouses = ref<PlatformWarehouseResource[]>([])
const optionsLoading = ref(false)
const optionsError = ref('')
@@ -85,7 +88,9 @@ const selectableCustomers = computed(() => customers.value.filter((customer) =>
customer.status === 'ACTIVE' || String(customer.id) === String(form.data.customerId)
)))
const shippingCompanies = computed(() => partners.value.filter((partner) => partner.types.includes('CARRIER')))
const bookingAgents = computed(() => partners.value.filter((partner) => partner.types.some((type) => ['SUPPLIER', 'CUSTOMS_BROKER'].includes(type))))
const selectableBookingAgents = computed(() => bookingSuppliers.value.filter((supplier) => (
supplier.status === 'ACTIVE' || String(supplier.id) === String(form.data.bookingAgentId)
)))
const channelUnavailable = computed(() => Boolean(form.data.warehouseId) && !channelsLoading.value && !channelsError.value && channels.value.length === 0)
function blankParties(): OceanBookingParty[] {
@@ -127,16 +132,18 @@ async function loadOptions() {
optionsLoading.value = true
optionsError.value = ''
try {
const [customerResult, partnerResult, warehouseResult] = await Promise.all([
const [customerResult, partnerResult, supplierResult, warehouseResult] = await Promise.all([
listPlatformTenants({ page: 1, size: 200, status: 'ACTIVE' }),
listPlatformPartners({ page: 1, size: 200, status: 'ACTIVE' }),
listSuppliers({ page: 1, size: 200, category: 'BOOKING', status: 'ACTIVE' }),
listPlatformWarehouses({ page: 1, size: 200, warehouseType: 'DOMESTIC', status: 'ACTIVE' }),
])
customers.value = customerResult.records.filter((customer) => customer.status === 'ACTIVE')
partners.value = partnerResult.records
bookingSuppliers.value = supplierResult.records
warehouses.value = warehouseResult.records.filter((warehouse) => warehouse.status === 'ACTIVE' && warehouse.warehouseType === 'DOMESTIC')
} catch (cause) {
optionsError.value = getApiErrorDetails(cause, '客户及合作单位选项加载失败').message
optionsError.value = getApiErrorDetails(cause, '客户、船公司或订舱代理选项加载失败').message
} finally {
optionsLoading.value = false
}
@@ -184,15 +191,18 @@ function selectChannel(channelCode: string) {
form.data.channelCode = channelCode
selectedChannelName.value = channel?.channelName || ''
}
function selectPartner(kind: 'shippingCompany' | 'bookingAgent', partnerId: string) {
function selectShippingCompany(partnerId: string) {
const partner = partners.value.find((item) => String(item.id) === partnerId)
if (kind === 'shippingCompany') {
form.data.shippingCompanyId = partnerId || null
form.data.shippingCompanyName = partner?.partnerName || null
} else {
form.data.bookingAgentId = partnerId || null
form.data.bookingAgentName = partner?.partnerName || null
}
form.data.shippingCompanyId = partnerId || null
form.data.shippingCompanyName = partner?.partnerName || null
}
function selectBookingAgent(supplierId: string) {
const supplier = bookingSuppliers.value.find((item) => String(item.id) === supplierId)
form.data.bookingAgentId = supplierId || null
form.data.bookingAgentName = supplier?.name || null
}
function bookingAgentLabel(supplier: Supplier) {
return `${supplier.name}(${supplier.scope === 'INTERNATIONAL' ? '国外' : '国内'})`
}
function applyDetail(value: OceanBookingDetail) {
detail.value = value
@@ -371,8 +381,8 @@ onMounted(() => { void load(); void loadOptions() })
<el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="form.data.warehouseId" filterable placeholder="请选择装柜仓库" :loading="optionsLoading" style="width:100%" @update:model-value="selectWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item>
<el-form-item label="物流渠道" prop="channelCode"><el-select :model-value="form.data.channelCode" filterable :disabled="!form.data.warehouseId || channelsLoading || !!channelsError || channelUnavailable" :loading="channelsLoading" :placeholder="form.data.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="该仓库暂无有效物流渠道" style="width:100%" @update:model-value="selectChannel(String($event || ''))"><el-option v-if="form.data.channelCode && !channels.some((channel) => channel.channelCode === form.data.channelCode)" :label="selectedChannelName || form.data.channelCode" :value="form.data.channelCode" /><el-option v-for="channel in channels" :key="channel.channelCode" :label="channel.channelName" :value="channel.channelCode"><span>{{ channel.channelName }}</span><small class="channel-code">{{ channel.channelCode }}</small></el-option></el-select><div v-if="channelsError" class="field-error"><span>{{ channelsError }}</span><el-button link type="primary" :loading="channelsLoading" @click="loadChannels(form.data.warehouseId)">重新加载</el-button></div><div v-else-if="channelUnavailable" class="field-hint">该仓库暂无有效物流渠道,请更换仓库或联系管理员。</div></el-form-item>
<el-form-item label="提单号" prop="billOfLadingNo"><el-input v-model="form.data.billOfLadingNo" maxlength="128" placeholder="请输入提单号" /></el-form-item>
<el-form-item label="船公司"><el-select :model-value="form.data.shippingCompanyId" filterable clearable placeholder="请选择船公司" :loading="optionsLoading" style="width:100%" @update:model-value="selectPartner('shippingCompany', String($event || ''))"><el-option v-if="form.data.shippingCompanyId && !shippingCompanies.some((partner) => String(partner.id) === String(form.data.shippingCompanyId))" :label="form.data.shippingCompanyName || '船公司名称缺失'" :value="String(form.data.shippingCompanyId)" /><el-option v-for="partner in shippingCompanies" :key="String(partner.id)" :label="partner.partnerName" :value="String(partner.id)" /></el-select></el-form-item>
<el-form-item label="订舱代理"><el-select :model-value="form.data.bookingAgentId" filterable clearable placeholder="请选择订舱代理" :loading="optionsLoading" style="width:100%" @update:model-value="selectPartner('bookingAgent', String($event || ''))"><el-option v-if="form.data.bookingAgentId && !bookingAgents.some((partner) => String(partner.id) === String(form.data.bookingAgentId))" :label="form.data.bookingAgentName || '订舱代理名称缺失'" :value="String(form.data.bookingAgentId)" /><el-option v-for="partner in bookingAgents" :key="String(partner.id)" :label="partner.partnerName" :value="String(partner.id)" /></el-select></el-form-item>
<el-form-item label="船公司"><el-select :model-value="form.data.shippingCompanyId" filterable clearable placeholder="请选择船公司" :loading="optionsLoading" style="width:100%" @update:model-value="selectShippingCompany(String($event || ''))"><el-option v-if="form.data.shippingCompanyId && !shippingCompanies.some((partner) => String(partner.id) === String(form.data.shippingCompanyId))" :label="form.data.shippingCompanyName || '船公司名称缺失'" :value="String(form.data.shippingCompanyId)" /><el-option v-for="partner in shippingCompanies" :key="String(partner.id)" :label="partner.partnerName" :value="String(partner.id)" /></el-select></el-form-item>
<el-form-item label="订舱代理"><el-select :model-value="form.data.bookingAgentId" filterable clearable placeholder="请选择订舱代理" :loading="optionsLoading" no-data-text="暂无启用的订舱供应商" style="width:100%" @update:model-value="selectBookingAgent(String($event || ''))"><el-option v-if="form.data.bookingAgentId && !selectableBookingAgents.some((supplier) => String(supplier.id) === String(form.data.bookingAgentId))" :label="form.data.bookingAgentName || '订舱代理名称缺失'" :value="String(form.data.bookingAgentId)" /><el-option v-for="supplier in selectableBookingAgents" :key="String(supplier.id)" :label="bookingAgentLabel(supplier)" :value="String(supplier.id)" /></el-select></el-form-item>
</div>
</section>
<section class="booking-group" aria-label="航线船期">