修复纸质单据布局并统一退货单据样式
This commit is contained in:
parent
eb472ad455
commit
bca020554c
@ -49,4 +49,21 @@ describe("document form foundation", () => {
|
|||||||
assert.match(mainCss, /\.document-settle-panel/);
|
assert.match(mainCss, /\.document-settle-panel/);
|
||||||
assert.match(mainCss, /\.warehouse-paper-control-grid/);
|
assert.match(mainCss, /\.warehouse-paper-control-grid/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps the final paper layout contract after legacy warehouse grid rules", () => {
|
||||||
|
const legacyWarehouseGrid = mainCss.lastIndexOf(".warehouse-document-section-grid {");
|
||||||
|
const finalContract = mainCss.lastIndexOf("Final paper document layout contract");
|
||||||
|
const warehousePaperGrid = mainCss.lastIndexOf("body .warehouse-document-section-grid > .warehouse-paper-grid");
|
||||||
|
const genericWrappedWarehousePaperGrid = mainCss.lastIndexOf("body .document-section-grid > .warehouse-paper-grid");
|
||||||
|
const genericWrappedWarehouseMeta = mainCss.lastIndexOf("body .document-section-grid > .warehouse-document-meta-strip");
|
||||||
|
const genericDocumentGrid = mainCss.lastIndexOf("body .document-section-grid > .document-grid");
|
||||||
|
|
||||||
|
assert.ok(legacyWarehouseGrid > 0, "expected the legacy warehouse grid rule to exist");
|
||||||
|
assert.ok(finalContract > legacyWarehouseGrid, "expected final paper contract after legacy grid rules");
|
||||||
|
assert.ok(warehousePaperGrid > legacyWarehouseGrid, "expected warehouse paper grid full-width rule after legacy grid");
|
||||||
|
assert.ok(genericWrappedWarehousePaperGrid > legacyWarehouseGrid, "expected generic section wrapped warehouse paper grid rule after legacy grid");
|
||||||
|
assert.ok(genericWrappedWarehouseMeta > legacyWarehouseGrid, "expected generic section wrapped warehouse meta strip rule after legacy grid");
|
||||||
|
assert.ok(genericDocumentGrid > 0, "expected generic document grid full-width rule in final contract");
|
||||||
|
assert.match(mainCss.slice(finalContract), /grid-column: 1 \/ -1 !important;/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16282,6 +16282,14 @@ body .login-production-layout .login-security-foot p {
|
|||||||
background: rgba(255, 250, 240, 0.5);
|
background: rgba(255, 250, 240, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.document-grid-cell-wide {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.document-grid-cell-full {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
.document-grid-label,
|
.document-grid-label,
|
||||||
.document-grid-value {
|
.document-grid-value {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -16789,11 +16797,21 @@ body .login-production-layout .login-security-foot p {
|
|||||||
padding: 14px;
|
padding: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.document-section-grid > .document-grid,
|
||||||
|
.document-section-grid > .document-line-table,
|
||||||
.document-section-grid > .document-control-grid,
|
.document-section-grid > .document-control-grid,
|
||||||
.document-section-grid > .document-selector-panel,
|
.document-section-grid > .document-selector-panel,
|
||||||
.document-section-grid > .document-source-table,
|
.document-section-grid > .document-source-table,
|
||||||
.document-section-grid > .document-inline-summary,
|
.document-section-grid > .document-inline-summary,
|
||||||
.document-section-grid > .document-settle-panel,
|
.document-section-grid > .document-settle-panel,
|
||||||
|
.document-section-grid > .warehouse-document-meta-strip,
|
||||||
|
.document-section-grid > .warehouse-paper-grid,
|
||||||
|
.document-section-grid > .warehouse-paper-control-grid,
|
||||||
|
.document-section-grid > .warehouse-paper-source-lot-panel,
|
||||||
|
.document-section-grid > .warehouse-paper-source-lot-table,
|
||||||
|
.document-section-grid > .warehouse-paper-inline-summary,
|
||||||
|
.document-section-grid > .warehouse-paper-settle-panel,
|
||||||
|
.document-section-grid > .warehouse-paper-summary-grid,
|
||||||
.document-section-grid > .document-paper-field {
|
.document-section-grid > .document-paper-field {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -17036,6 +17054,11 @@ body .login-production-layout .login-security-foot p {
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.document-grid-cell-wide,
|
||||||
|
.document-grid-cell-full {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
.document-action-bar,
|
.document-action-bar,
|
||||||
.document-action-bar--with-state,
|
.document-action-bar--with-state,
|
||||||
.document-action-state,
|
.document-action-state,
|
||||||
@ -19250,7 +19273,56 @@ body .warehouse-document-action-bar {
|
|||||||
transform: none !important;
|
transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Final paper document layout contract: later legacy drawer grids must not squeeze formal document blocks. */
|
||||||
|
body .document-section-grid > .document-grid,
|
||||||
|
body .document-section-grid > .document-line-table,
|
||||||
|
body .document-section-grid > .document-control-grid,
|
||||||
|
body .document-section-grid > .document-selector-panel,
|
||||||
|
body .document-section-grid > .document-source-table,
|
||||||
|
body .document-section-grid > .document-inline-summary,
|
||||||
|
body .document-section-grid > .document-settle-panel,
|
||||||
|
body .document-section-grid > .document-paper-field,
|
||||||
|
body .document-section-grid > .warehouse-document-meta-strip,
|
||||||
|
body .document-section-grid > .warehouse-paper-grid,
|
||||||
|
body .document-section-grid > .warehouse-paper-control-grid,
|
||||||
|
body .document-section-grid > .warehouse-paper-source-lot-panel,
|
||||||
|
body .document-section-grid > .warehouse-paper-source-lot-table,
|
||||||
|
body .document-section-grid > .warehouse-paper-inline-summary,
|
||||||
|
body .document-section-grid > .warehouse-paper-settle-panel,
|
||||||
|
body .document-section-grid > .warehouse-paper-summary-grid,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-document-meta-strip,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-grid,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-control-grid,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-source-lot-panel,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-source-lot-table,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-inline-summary,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-settle-panel,
|
||||||
|
body .warehouse-document-section-grid > .warehouse-paper-summary-grid {
|
||||||
|
grid-column: 1 / -1 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .workflow-drawer.form-drawer:has(.document-form-shell) {
|
||||||
|
width: min(1280px, calc(100vw - 24px)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .workflow-drawer.form-drawer:has(.document-form-shell) .form-drawer-body {
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .document-action-bar {
|
||||||
|
position: relative !important;
|
||||||
|
right: auto !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
z-index: 1 !important;
|
||||||
|
margin: 0 0 0 auto !important;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 620px) {
|
@media (max-width: 620px) {
|
||||||
|
body .document-action-bar,
|
||||||
|
body .document-action-bar--with-state,
|
||||||
body .warehouse-document-action-bar,
|
body .warehouse-document-action-bar,
|
||||||
body .warehouse-document-action-bar--shared,
|
body .warehouse-document-action-bar--shared,
|
||||||
body .warehouse-document-action-bar--shared.warehouse-document-action-bar--with-state {
|
body .warehouse-document-action-bar--shared.warehouse-document-action-bar--with-state {
|
||||||
|
|||||||
50
frontend/src/views/ReturnManagementView.test.js
Normal file
50
frontend/src/views/ReturnManagementView.test.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { describe, it } from "node:test";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const source = readFileSync(join(__dirname, "ReturnManagementView.vue"), "utf8");
|
||||||
|
|
||||||
|
function drawerBlock(openBinding, nextMarker) {
|
||||||
|
const start = source.indexOf(`:open="${openBinding}"`);
|
||||||
|
assert.ok(start >= 0, `expected drawer ${openBinding} to exist`);
|
||||||
|
const end = source.indexOf(nextMarker, start + openBinding.length);
|
||||||
|
assert.ok(end > start, `expected drawer ${openBinding} to end before ${nextMarker}`);
|
||||||
|
return source.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("ReturnManagementView formal document layout", () => {
|
||||||
|
it("renders return registration as a formal paper document instead of a stack form", () => {
|
||||||
|
const block = drawerBlock("returnDrawerOpen", ':open="dispositionDrawerOpen"');
|
||||||
|
|
||||||
|
assert.match(block, /<DocumentFormShell[\s\S]*title="退货登记单"/);
|
||||||
|
assert.match(block, /<DocumentSection index="01" title="退货来源信息"/);
|
||||||
|
assert.match(block, /<DocumentSection index="02" title="退货明细"/);
|
||||||
|
assert.match(block, /<DocumentGrid :fields="returnDocumentHeaderFields"/);
|
||||||
|
assert.match(block, /<DocumentLineTable title="退货明细"/);
|
||||||
|
assert.match(block, /<DocumentActionBar>/);
|
||||||
|
assert.doesNotMatch(block, /<form class="stack-form"/);
|
||||||
|
assert.doesNotMatch(block, /order-item-card/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders return disposition as a formal paper document instead of a stack form", () => {
|
||||||
|
const block = drawerBlock("dispositionDrawerOpen", ':open="dispositionRecordsDrawerOpen"');
|
||||||
|
|
||||||
|
assert.match(block, /<DocumentFormShell[\s\S]*title="退货处置单"/);
|
||||||
|
assert.match(block, /<DocumentSection index="01" title="处置信息"/);
|
||||||
|
assert.match(block, /<DocumentSection index="02" title="处置对象预览"/);
|
||||||
|
assert.match(block, /<DocumentGrid :fields="dispositionDocumentHeaderFields"/);
|
||||||
|
assert.match(block, /<DocumentLineTable title="退货行明细"/);
|
||||||
|
assert.match(block, /<DocumentActionBar>/);
|
||||||
|
assert.doesNotMatch(block, /<form class="stack-form"/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps the formal document field definitions explicit", () => {
|
||||||
|
assert.match(source, /const returnDocumentHeaderFields = computed/);
|
||||||
|
assert.match(source, /const returnDocumentLineColumns = \[/);
|
||||||
|
assert.match(source, /const dispositionDocumentHeaderFields = computed/);
|
||||||
|
assert.match(source, /const dispositionDocumentLineColumns = \[/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -73,120 +73,116 @@
|
|||||||
wide
|
wide
|
||||||
@close="returnDrawerOpen = false"
|
@close="returnDrawerOpen = false"
|
||||||
>
|
>
|
||||||
<form class="stack-form" @submit.prevent="submitReturnOrder">
|
<DocumentFormShell
|
||||||
<div class="double-field">
|
class="return-document-form"
|
||||||
<label class="form-field">
|
title="退货登记单"
|
||||||
<span>客户</span>
|
document-no="提交后自动生成"
|
||||||
|
meta-label="售后联单"
|
||||||
|
:business-date="new Date()"
|
||||||
|
:signature-labels="['售后登记', '仓库接收', '质量复核', '制单人']"
|
||||||
|
tone="green"
|
||||||
|
@submit="submitReturnOrder"
|
||||||
|
>
|
||||||
|
<DocumentSection index="01" title="退货来源信息">
|
||||||
|
<DocumentGrid :fields="returnDocumentHeaderFields" columns="3">
|
||||||
|
<template #customer>
|
||||||
<select v-model.number="orderForm.customer_id" required>
|
<select v-model.number="orderForm.customer_id" required>
|
||||||
<option disabled value="">请选择客户</option>
|
<option disabled value="">请选择客户</option>
|
||||||
<option v-for="customer in customers" :key="customer.id" :value="customer.id">
|
<option v-for="customer in customers" :key="customer.id" :value="customer.id">
|
||||||
{{ customer.customer_name }}
|
{{ customer.customer_name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
<label class="form-field">
|
<template #sales_order>
|
||||||
<span>订单</span>
|
|
||||||
<select v-model.number="orderForm.sales_order_id">
|
<select v-model.number="orderForm.sales_order_id">
|
||||||
<option value="">不关联</option>
|
<option value="">不关联</option>
|
||||||
<option v-for="order in orders" :key="order.order_id" :value="order.order_id">
|
<option v-for="order in orders" :key="order.order_id" :value="order.order_id">
|
||||||
{{ order.order_no }}
|
{{ order.order_no }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
</div>
|
<template #delivery>
|
||||||
|
|
||||||
<div class="double-field">
|
|
||||||
<label class="form-field">
|
|
||||||
<span>发货单</span>
|
|
||||||
<select v-model.number="orderForm.delivery_id">
|
<select v-model.number="orderForm.delivery_id">
|
||||||
<option value="">不关联</option>
|
<option value="">不关联</option>
|
||||||
<option v-for="delivery in deliveries" :key="delivery.delivery_id" :value="delivery.delivery_id">
|
<option v-for="delivery in deliveries" :key="delivery.delivery_id" :value="delivery.delivery_id">
|
||||||
{{ delivery.delivery_no }} · {{ delivery.order_no }}
|
{{ delivery.delivery_no }} · {{ delivery.order_no }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
<label class="form-field">
|
<template #handler>
|
||||||
<span>处理人</span>
|
|
||||||
<select v-model.number="orderForm.handler_employee_id">
|
<select v-model.number="orderForm.handler_employee_id">
|
||||||
<option value="">请选择</option>
|
<option value="">请选择</option>
|
||||||
<option v-for="employee in employees" :key="employee.id" :value="employee.id">
|
<option v-for="employee in employees" :key="employee.id" :value="employee.id">
|
||||||
{{ employeeOptionLabel(employee) }}
|
{{ employeeOptionLabel(employee) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
</div>
|
<template #return_reason>
|
||||||
|
|
||||||
<label class="form-field">
|
|
||||||
<span>退货原因</span>
|
|
||||||
<textarea v-model.trim="orderForm.return_reason" rows="2"></textarea>
|
<textarea v-model.trim="orderForm.return_reason" rows="2"></textarea>
|
||||||
</label>
|
</template>
|
||||||
|
</DocumentGrid>
|
||||||
|
</DocumentSection>
|
||||||
|
|
||||||
<div class="subsection-head">
|
<DocumentSection index="02" title="退货明细">
|
||||||
<strong>退货明细</strong>
|
<DocumentLineTable title="退货明细" :columns="returnDocumentLineColumns">
|
||||||
|
<template #actions>
|
||||||
<button class="ghost-button" type="button" @click="addRow">增加一行</button>
|
<button class="ghost-button" type="button" @click="addRow">增加一行</button>
|
||||||
</div>
|
</template>
|
||||||
|
<tr v-for="(item, index) in orderForm.items" :key="index">
|
||||||
<div class="order-item-stack">
|
<td class="document-line-index">{{ index + 1 }}</td>
|
||||||
<article v-for="(item, index) in orderForm.items" :key="index" class="order-item-card">
|
<td>
|
||||||
<div class="subsection-head">
|
|
||||||
<strong>明细 {{ index + 1 }}</strong>
|
|
||||||
<button v-if="orderForm.items.length > 1" class="ghost-button danger-ghost" type="button" @click="removeRow(index)">
|
|
||||||
删除
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="form-field">
|
|
||||||
<span>订单行</span>
|
|
||||||
<select v-model.number="item.sales_order_item_id" @change="applyOrderItem(index)">
|
<select v-model.number="item.sales_order_item_id" @change="applyOrderItem(index)">
|
||||||
<option value="">手工选产品</option>
|
<option value="">手工选产品</option>
|
||||||
<option v-for="orderItem in orderItems" :key="orderItem.sales_order_item_id" :value="orderItem.sales_order_item_id">
|
<option v-for="orderItem in orderItems" :key="orderItem.sales_order_item_id" :value="orderItem.sales_order_item_id">
|
||||||
{{ orderItem.order_no }} · {{ orderItem.product_name }}
|
{{ orderItem.order_no }} · {{ orderItem.product_name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</td>
|
||||||
|
<td>
|
||||||
<div class="double-field">
|
|
||||||
<label class="form-field">
|
|
||||||
<span>产品</span>
|
|
||||||
<select v-model.number="item.product_item_id" required @change="recalculateReturnWeight(index)">
|
<select v-model.number="item.product_item_id" required @change="recalculateReturnWeight(index)">
|
||||||
<option disabled value="">请选择产品</option>
|
<option disabled value="">请选择产品</option>
|
||||||
<option v-for="product in products" :key="product.item_id" :value="product.item_id">
|
<option v-for="product in products" :key="product.item_id" :value="product.item_id">
|
||||||
{{ product.item_code }} · {{ product.item_name }}
|
{{ product.item_code }} · {{ product.item_name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</td>
|
||||||
<label class="form-field">
|
<td>
|
||||||
<span>来源批次</span>
|
|
||||||
<select v-model.number="item.source_lot_id">
|
<select v-model.number="item.source_lot_id">
|
||||||
<option value="">不指定</option>
|
<option value="">不指定</option>
|
||||||
<option v-for="lot in finishedLots" :key="lot.lot_id" :value="lot.lot_id">
|
<option v-for="lot in finishedLots" :key="lot.lot_id" :value="lot.lot_id">
|
||||||
{{ lot.lot_no }} · {{ lot.item_name }}
|
{{ lot.lot_no }} · {{ lot.item_name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
|
|
||||||
<div class="triple-field">
|
|
||||||
<label class="form-field">
|
|
||||||
<span>退货数量</span>
|
|
||||||
<input v-model.number="item.return_qty" type="number" min="0" step="1" @input="recalculateReturnWeight(index)" />
|
<input v-model.number="item.return_qty" type="number" min="0" step="1" @input="recalculateReturnWeight(index)" />
|
||||||
</label>
|
</td>
|
||||||
<label class="form-field">
|
<td>
|
||||||
<span>退货重量(kg)</span>
|
|
||||||
<input v-model.number="item.return_weight_kg" type="number" min="0" step="0.001" />
|
<input v-model.number="item.return_weight_kg" type="number" min="0" step="0.001" />
|
||||||
</label>
|
</td>
|
||||||
<label class="form-field">
|
<td>
|
||||||
<span>责任归属</span>
|
|
||||||
<input v-model.trim="item.responsibility_type" type="text" placeholder="内部 / 外部 / 客户" />
|
<input v-model.trim="item.responsibility_type" type="text" placeholder="内部 / 外部 / 客户" />
|
||||||
</label>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
</article>
|
<button
|
||||||
</div>
|
v-if="orderForm.items.length > 1"
|
||||||
|
class="ghost-button danger-ghost table-action-button"
|
||||||
|
type="button"
|
||||||
|
@click="removeRow(index)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</DocumentLineTable>
|
||||||
|
</DocumentSection>
|
||||||
|
|
||||||
|
<DocumentActionBar>
|
||||||
<button class="primary-button" type="submit" :disabled="submittingOrder">
|
<button class="primary-button" type="submit" :disabled="submittingOrder">
|
||||||
{{ submittingOrder ? "提交中..." : "创建退货单" }}
|
{{ submittingOrder ? "提交中..." : "创建退货单" }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</DocumentActionBar>
|
||||||
|
</DocumentFormShell>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|
||||||
<FormDrawer
|
<FormDrawer
|
||||||
@ -198,50 +194,70 @@
|
|||||||
wide
|
wide
|
||||||
@close="dispositionDrawerOpen = false"
|
@close="dispositionDrawerOpen = false"
|
||||||
>
|
>
|
||||||
<form class="stack-form" @submit.prevent="submitDisposition">
|
<DocumentFormShell
|
||||||
<label class="form-field">
|
class="return-document-form"
|
||||||
<span>待处置退货行</span>
|
title="退货处置单"
|
||||||
|
document-no="保存后自动生成"
|
||||||
|
meta-label="售后处置联单"
|
||||||
|
:business-date="new Date()"
|
||||||
|
:signature-labels="['售后确认', '仓库复核', '生产接收', '制单人']"
|
||||||
|
tone="green"
|
||||||
|
@submit="submitDisposition"
|
||||||
|
>
|
||||||
|
<DocumentSection index="01" title="处置信息">
|
||||||
|
<DocumentGrid :fields="dispositionDocumentHeaderFields" columns="3">
|
||||||
|
<template #return_item>
|
||||||
<select v-model.number="dispositionForm.return_item_id" required @change="applyDispositionItem">
|
<select v-model.number="dispositionForm.return_item_id" required @change="applyDispositionItem">
|
||||||
<option disabled value="">请选择退货行</option>
|
<option disabled value="">请选择退货行</option>
|
||||||
<option v-for="item in currentDispositionItems" :key="item.return_item_id" :value="item.return_item_id">
|
<option v-for="item in currentDispositionItems" :key="item.return_item_id" :value="item.return_item_id">
|
||||||
{{ item.return_no }} · {{ item.product_name }} · {{ formatQty(item.return_qty) }}
|
{{ item.return_no }} · {{ item.product_name }} · {{ formatQty(item.return_qty) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
|
<template #disposition_type>
|
||||||
<label class="form-field">
|
|
||||||
<span>处置方式</span>
|
|
||||||
<select v-model="dispositionForm.disposition_type" @change="applyDispositionType">
|
<select v-model="dispositionForm.disposition_type" @change="applyDispositionType">
|
||||||
<option value="REWORK">返工</option>
|
<option value="REWORK">返工</option>
|
||||||
<option value="SCRAP">报废</option>
|
<option value="SCRAP">报废</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</template>
|
||||||
|
<template #extra_cost_amount>
|
||||||
<label v-if="dispositionForm.disposition_type === 'REWORK'" class="form-field">
|
|
||||||
<span>额外人工成本</span>
|
|
||||||
<input v-model.number="dispositionForm.extra_cost_amount" type="number" min="0" step="0.01" />
|
<input v-model.number="dispositionForm.extra_cost_amount" type="number" min="0" step="0.01" />
|
||||||
</label>
|
</template>
|
||||||
|
<template #scrap_weight_kg>
|
||||||
<div v-if="dispositionForm.disposition_type === 'SCRAP'" class="double-field">
|
|
||||||
<label class="form-field">
|
|
||||||
<span>报废重量(kg)</span>
|
|
||||||
<input v-model.number="dispositionForm.scrap_weight_kg" type="number" min="0" step="0.001" />
|
<input v-model.number="dispositionForm.scrap_weight_kg" type="number" min="0" step="0.001" />
|
||||||
</label>
|
</template>
|
||||||
<label class="form-field">
|
<template #scrap_sale_amount>
|
||||||
<span>废料销售金额</span>
|
|
||||||
<input v-model.number="dispositionForm.scrap_sale_amount" type="number" min="0" step="0.01" />
|
<input v-model.number="dispositionForm.scrap_sale_amount" type="number" min="0" step="0.01" />
|
||||||
</label>
|
</template>
|
||||||
</div>
|
<template #remark>
|
||||||
|
|
||||||
<label class="form-field">
|
|
||||||
<span>备注</span>
|
|
||||||
<textarea v-model.trim="dispositionForm.remark" rows="2"></textarea>
|
<textarea v-model.trim="dispositionForm.remark" rows="2"></textarea>
|
||||||
</label>
|
</template>
|
||||||
|
</DocumentGrid>
|
||||||
|
</DocumentSection>
|
||||||
|
|
||||||
|
<DocumentSection index="02" title="处置对象预览">
|
||||||
|
<DocumentLineTable title="退货行明细" :columns="dispositionDocumentLineColumns">
|
||||||
|
<tr v-if="activeDispositionItem">
|
||||||
|
<td class="document-line-index">1</td>
|
||||||
|
<td>{{ activeDispositionItem.return_no || "-" }}</td>
|
||||||
|
<td>{{ activeDispositionItem.product_name || "-" }}</td>
|
||||||
|
<td>{{ activeDispositionItem.source_lot_no || "-" }}</td>
|
||||||
|
<td>{{ formatQty(activeDispositionItem.return_qty) }}</td>
|
||||||
|
<td>{{ formatWeight(activeDispositionItem.return_weight_kg) }}</td>
|
||||||
|
<td>{{ activeDispositionItem.responsibility_type || "-" }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-else>
|
||||||
|
<td colspan="7" class="empty-row">请选择待处置退货行</td>
|
||||||
|
</tr>
|
||||||
|
</DocumentLineTable>
|
||||||
|
</DocumentSection>
|
||||||
|
|
||||||
|
<DocumentActionBar>
|
||||||
<button class="primary-button" type="submit" :disabled="submittingDisposition">
|
<button class="primary-button" type="submit" :disabled="submittingDisposition">
|
||||||
{{ submittingDisposition ? "处理中..." : "提交处置" }}
|
{{ submittingDisposition ? "处理中..." : "提交处置" }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</DocumentActionBar>
|
||||||
|
</DocumentFormShell>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|
||||||
<FormDrawer
|
<FormDrawer
|
||||||
@ -287,6 +303,11 @@
|
|||||||
import { computed, onMounted, reactive, ref } from "vue";
|
import { computed, onMounted, reactive, ref } from "vue";
|
||||||
|
|
||||||
import DrawerDataTable from "../components/DrawerDataTable.vue";
|
import DrawerDataTable from "../components/DrawerDataTable.vue";
|
||||||
|
import DocumentActionBar from "../components/documentForms/DocumentActionBar.vue";
|
||||||
|
import DocumentFormShell from "../components/documentForms/DocumentFormShell.vue";
|
||||||
|
import DocumentGrid from "../components/documentForms/DocumentGrid.vue";
|
||||||
|
import DocumentLineTable from "../components/documentForms/DocumentLineTable.vue";
|
||||||
|
import DocumentSection from "../components/documentForms/DocumentSection.vue";
|
||||||
import FormDrawer from "../components/FormDrawer.vue";
|
import FormDrawer from "../components/FormDrawer.vue";
|
||||||
import PaginationBar from "../components/PaginationBar.vue";
|
import PaginationBar from "../components/PaginationBar.vue";
|
||||||
import TableControls from "../components/TableControls.vue";
|
import TableControls from "../components/TableControls.vue";
|
||||||
@ -330,6 +351,7 @@ const currentDispositionItems = computed(() => {
|
|||||||
}
|
}
|
||||||
return pendingItems.value.filter((item) => item.return_order_id === Number(selectedReturnOrderId.value));
|
return pendingItems.value.filter((item) => item.return_order_id === Number(selectedReturnOrderId.value));
|
||||||
});
|
});
|
||||||
|
const activeDispositionItem = computed(() => selectedDispositionItem());
|
||||||
const visibleDispositions = computed(() => {
|
const visibleDispositions = computed(() => {
|
||||||
const order = activeReturnOrder.value;
|
const order = activeReturnOrder.value;
|
||||||
if (!order) {
|
if (!order) {
|
||||||
@ -385,6 +407,48 @@ const dispositionDrawerColumns = computed(() => [
|
|||||||
{ key: "rework_work_order_no", label: "返工工单", detailOnly: true },
|
{ key: "rework_work_order_no", label: "返工工单", detailOnly: true },
|
||||||
{ key: "scrap_sale_amount", label: "废料销售金额", detailOnly: true, format: (value) => `¥${formatAmount(value)}` }
|
{ key: "scrap_sale_amount", label: "废料销售金额", detailOnly: true, format: (value) => `¥${formatAmount(value)}` }
|
||||||
]);
|
]);
|
||||||
|
const returnDocumentHeaderFields = computed(() => [
|
||||||
|
{ key: "customer", label: "客户" },
|
||||||
|
{ key: "sales_order", label: "订单" },
|
||||||
|
{ key: "delivery", label: "发货单" },
|
||||||
|
{ key: "handler", label: "处理人" },
|
||||||
|
{ key: "return_reason", label: "退货原因", class: "document-grid-cell-wide" }
|
||||||
|
]);
|
||||||
|
const returnDocumentLineColumns = [
|
||||||
|
{ key: "index", label: "序号", width: "58px" },
|
||||||
|
{ key: "sales_order_item", label: "订单行", width: "22%" },
|
||||||
|
{ key: "product", label: "产品", width: "20%" },
|
||||||
|
{ key: "source_lot", label: "来源批次", width: "18%" },
|
||||||
|
{ key: "return_qty", label: "退货数量", width: "104px" },
|
||||||
|
{ key: "return_weight_kg", label: "退货重量(kg)", width: "126px" },
|
||||||
|
{ key: "responsibility_type", label: "责任归属", width: "132px" },
|
||||||
|
{ key: "actions", label: "操作", width: "92px" }
|
||||||
|
];
|
||||||
|
const dispositionDocumentHeaderFields = computed(() => {
|
||||||
|
const fields = [
|
||||||
|
{ key: "return_item", label: "待处置退货行", class: "document-grid-cell-wide" },
|
||||||
|
{ key: "disposition_type", label: "处置方式" }
|
||||||
|
];
|
||||||
|
if (dispositionForm.disposition_type === "SCRAP") {
|
||||||
|
fields.push(
|
||||||
|
{ key: "scrap_weight_kg", label: "报废重量(kg)" },
|
||||||
|
{ key: "scrap_sale_amount", label: "废料销售金额" }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fields.push({ key: "extra_cost_amount", label: "额外人工成本" });
|
||||||
|
}
|
||||||
|
fields.push({ key: "remark", label: "备注", class: "document-grid-cell-wide" });
|
||||||
|
return fields;
|
||||||
|
});
|
||||||
|
const dispositionDocumentLineColumns = [
|
||||||
|
{ key: "index", label: "序号", width: "58px" },
|
||||||
|
{ key: "return_no", label: "退货单号", width: "18%" },
|
||||||
|
{ key: "product", label: "产品", width: "24%" },
|
||||||
|
{ key: "source_lot", label: "来源批次", width: "20%" },
|
||||||
|
{ key: "return_qty", label: "退货数量", width: "104px" },
|
||||||
|
{ key: "return_weight_kg", label: "退货重量", width: "112px" },
|
||||||
|
{ key: "responsibility_type", label: "责任归属", width: "120px" }
|
||||||
|
];
|
||||||
const {
|
const {
|
||||||
page: returnOrderPage,
|
page: returnOrderPage,
|
||||||
pageSize: returnOrderPageSize,
|
pageSize: returnOrderPageSize,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user