fix: 第一版错误修改后的存档。

This commit is contained in:
c
2026-03-17 15:23:31 +08:00
parent 0c4e4679b3
commit 88aef44583
17 changed files with 283 additions and 67 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Teek Design Vue3</title>
<title>牛安管理系统</title>
</head>
<body>
<div id="app"></div>

View File

@@ -90,7 +90,7 @@ export default {
remark: "Remark",
startdate: "Start Date",
enddate: "End Date",
searchCode: "Doc No/Name/Remark",
searchCode: "Doc No / Remark",
},
warehouse: {
warehouse: {
@@ -233,6 +233,7 @@ export default {
productCount: "Count",
productMark: "Remark",
createDate: "Create Date",
searchCode: "Form Code/Name/Remark",
},
finishedproductreceipt: {
totalValue: "Receipt Count",
@@ -255,6 +256,7 @@ export default {
remark: "Remark",
createDate: "Create Date",
keyAccountId: "Customer",
searchCode: "Form Code/Name/Remark",
},
},
purchase: {
@@ -268,6 +270,7 @@ export default {
baseTitle: "Purchase Plan Basic Info",
tableTitle: "Purchase Details",
generateOrder: "Generate Purchase Order",
showItem: "Purchase Details",
model: "Model",
defaultVendor: "Default Vendor",
demandQuantity: "Demand Qty",
@@ -276,6 +279,7 @@ export default {
unitPrice: "Unit Price",
totalPrice: "Total Price",
purchaseStatus: "Purchase Status",
searchCode: "Plan No/Name/Remark",
},
purchase_plan_item: {
partNumber: "Part Number",
@@ -343,6 +347,7 @@ export default {
sendCount: "Out Count",
surplusCount: "Remaining",
saleMark: "Remark",
searchCode: "Form Code/Name/Remark",
},
devicesn: {
softVersion: "Software Version",
@@ -691,6 +696,10 @@ export default {
outstock_success: "Outstock success",
outstock_fail: "Outstock failed",
input_outstock_mark: "Please enter outstock remark",
duplicate_productSn: "Duplicate SN: {value}",
duplicate_mac: "Duplicate MAC Address: {value}",
duplicate_serialNum: "Duplicate Serial Number: {value}",
validate_failed: "Device validation failed",
},
},
purchase: {
@@ -715,6 +724,7 @@ export default {
},
purchaseorder: {
delete_message: "Delete Order",
part_number_not_exists: "Part number does not exist",
},
finishedproductshipment: {
select_storeId: "Please select store",
@@ -819,6 +829,7 @@ export default {
stocktransferorder: {
add: "Add Transfer",
edit: "Edit Transfer",
stock_check_failed: "Stock check failed",
},
warehousereceipt: {
add: "Add Receipt",
@@ -845,6 +856,10 @@ export default {
},
production_issue: {
returnDialog: "Return Edit",
showItem: "Issue Details",
},
production_return: {
showItem: "Return Details",
},
finishedproductreceipt: {
add: "Add Receipt",

View File

@@ -90,7 +90,7 @@ export default {
remark: "备注",
startdate: "开始时间",
enddate: "结束时间",
searchCode: "单据编号/名称/备注",
searchCode: "单据编号 / 备注",
},
warehouse: {
warehouse: {
@@ -233,6 +233,7 @@ export default {
productCount: "数量",
productMark: "备注",
createDate: "创建时间",
searchCode: "单据编号/名称/备注",
},
finishedproductreceipt: {
totalValue: "入库数量",
@@ -255,6 +256,7 @@ export default {
remark: "备注",
createDate: "创建时间",
keyAccountId: "客户",
searchCode: "单据编号/名称/备注",
},
},
purchase: {
@@ -268,6 +270,7 @@ export default {
baseTitle: "采购计划基本信息",
tableTitle: "采购明细",
generateOrder: "生成采购订单",
showItem: "采购明细",
model: "型号",
defaultVendor: "默认供应商",
demandQuantity: "需求量",
@@ -276,14 +279,15 @@ export default {
unitPrice: "单价",
totalPrice: "总价",
purchaseStatus: "采购状态",
searchCode: "计划号/名称/备注",
},
purchase_plan_item: {
partNumber: "商品编号",
partNumber: "物料编号",
purchaseCount: "计划数量",
completeCount: "已完成数量",
price: "单价",
currentCount: "本次采购数量",
input_partNumber: "请输入商品编号",
input_partNumber: "请输入物料编号",
input_purchaseCount: "请输入计划数量",
input_price: "请输入单价",
input_currentCount: "请输入本次采购数量",
@@ -343,6 +347,7 @@ export default {
sendCount: "出库数量",
surplusCount: "剩余量",
saleMark: "备注",
searchCode: "单据编号/名称/备注",
},
devicesn: {
softVersion: "软件版本",
@@ -699,6 +704,10 @@ export default {
outstock_success: "出货成功",
outstock_fail: "出货失败",
input_outstock_mark: "请输入出货备注",
duplicate_productSn: "SN码重复{value}",
duplicate_mac: "MAC地址重复{value}",
duplicate_serialNum: "序列号重复:{value}",
validate_failed: "验证设备失败",
},
finishedproductshipment: {
select_storeId: "请选择仓库",
@@ -763,6 +772,7 @@ export default {
input_partNumber: "请输入物料编号",
input_purchaseCount: "请输入采购数量",
input_price: "请输入单价",
part_number_not_exists: "物料编号不存在",
},
finishedproductshipment: {
select_storeId: "请选择仓库",
@@ -917,6 +927,7 @@ export default {
showItem: "调拨明细",
baseTitle: "调拨单基本信息",
tableTitle: "调拨明细",
stock_check_failed: "库存检测失败",
},
warehousereceipt: {
add: "添加入库单",
@@ -951,6 +962,9 @@ export default {
returnDialog: "退料编辑",
showItem: "发料明细",
},
production_return: {
showItem: "退料明细",
},
finishedproductreceipt: {
add: "添加成品入库单",
edit: "编辑成品入库单",

View File

@@ -82,7 +82,7 @@ export const useStatus = () => {
};
const getPurchasePlanItemStatusLabel = (code: number | null): string => {
if (code === null || code === undefined) return "";
if (code === null || code === undefined) return t("_base_info.purchase.purchase_plan_item.no_start");
const key = purchasePlanItemStatusKeyMap[code];
return key ? t(key) : t(unknown);
};

View File

@@ -78,7 +78,7 @@ watch(() => parentParamValue.value, loadData);
}
.item-dialog {
--el-dialog-width: fit-content !important;
--el-dialog-width: 1400px !important;
--el-dialog-padding-primary: 20px;
}

View File

@@ -11,6 +11,7 @@ const props = defineProps({
label: String,
url: String,
data: Array<Record<string, string | number>>,
parse: Function,
});
const optionData = ref<OptionData[]>([]);
@@ -37,10 +38,13 @@ defineExpose({
const option = optionData.value.find(item => item.value === model.value);
return option?.label;
},
getOptions: () => {
return optionData.value;
},
});
</script>
<template>
<el-select :name="name || ''" v-model="model">
<el-option v-for="o in optionData" :key="o.value" :value="o.value" :label="o.label" />
<el-option v-for="o in parse ? parse(optionData) : optionData" :key="o.value" :value="o.value" :label="o.label" />
</el-select>
</template>

View File

@@ -59,11 +59,13 @@ function reset() {
display: flex;
padding-right: 20px;
}
.searcher-box {
padding-left: 5px;
padding-right: 5px;
padding-left: 5px;
}
.searcher {
width: 285px;
width: 400px;
}
</style>

View File

@@ -32,8 +32,7 @@ const saveOutstockUrl = "/production/finishedproductreceipt/saveOutstock";
const getKeyAccountSelectListUrl = "/sys/keyaccount/getKeyAccountSelectList";
const itemArrayName = "deviceItems";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductreceipt.formCode") },
{ name: "formName", type: "text" as const, placeholder: $t("_prop.production.finishedproductreceipt.formName") },
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductreceipt.searchCode") },
];
const rules = reactive<FormRules>({
formCode: [
@@ -58,6 +57,56 @@ const rules = reactive<FormRules>({
},
],
});
const validateDeviceDuplicates = (deviceItems: any[]): string | null => {
const productSns = new Set<string>();
const macs = new Set<string>();
const serialNums = new Set<string>();
for (const item of deviceItems) {
if (item.productSn) {
if (productSns.has(item.productSn)) {
return $t("_message.production.finishedproductreceipt.duplicate_productSn", { value: item.productSn });
}
productSns.add(item.productSn);
}
if (item.mac) {
if (macs.has(item.mac)) {
return $t("_message.production.finishedproductreceipt.duplicate_mac", { value: item.mac });
}
macs.add(item.mac);
}
if (item.serialNum) {
if (serialNums.has(item.serialNum)) {
return $t("_message.production.finishedproductreceipt.duplicate_serialNum", { value: item.serialNum });
}
serialNums.add(item.serialNum);
}
}
return null;
};
const validateDevicesWithBackend = async (deviceItems: any[]): Promise<string | null> => {
const validateUrl = "/sale/device/validateDevices";
const devices = deviceItems.map((item: any) => ({
productSn: item.productSn || "",
mac: item.mac || "",
serialNum: item.serialNum || "",
}));
try {
const res = await post(validateUrl, { devices });
if (res.code === 0 && res.data) {
if (!res.data.valid) {
return res.data.message;
}
}
return null;
} catch (error) {
console.error("验证设备失败:", error);
return $t("_message.production.finishedproductreceipt.validate_failed");
}
};
/**
* 基本不变通用变量
*/
@@ -160,7 +209,7 @@ const mappingConfig: FieldMappingConfig = {
const add = () => {
form.value = {};
title.value = "_title.production.finishedproductreceipt.add";
form.value["formCode"] = generateDucumentNo("CPRK");
form.value["formCode"] = generateDucumentNo("RK");
visible.value = true;
formType.value = false;
};
@@ -258,13 +307,26 @@ const showItem = (row: any) => {
itemParentId.value = row.id;
itemVisible.value = true;
};
const submit = (form: any, formRef: FormInstance | undefined) => {
const submit = async (formData: any, formRef: FormInstance | undefined) => {
setName();
if (formRef !== undefined) {
const deviceItems = formData.deviceItems || [];
const localDuplicateError = validateDeviceDuplicates(deviceItems);
if (localDuplicateError) {
ElMessage.error(localDuplicateError);
return;
}
const backendDuplicateError = await validateDevicesWithBackend(deviceItems);
if (backendDuplicateError) {
ElMessage.error(backendDuplicateError);
return;
}
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
if (formType.value) useEdit(editUrl, formData, visible);
else useAdd(addUrl, formData, visible);
}
});
}
@@ -304,7 +366,7 @@ const setName = () => {
form.value["storeName"] = warehouseSelectRef.value?.getLabel();
};
const handleReset = () => {
form.value["formCode"] = generateDucumentNo("CPRK");
form.value["formCode"] = generateDucumentNo("RK");
};
</script>
<template>

View File

@@ -30,8 +30,7 @@ const getDetailUrl = "/production/finishedproductshipment/getFinishedProductShip
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
const itemArrayName = "shipmentItems";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductshipment.formCode") },
{ name: "formName", type: "text" as const, placeholder: $t("_prop.production.finishedproductshipment.formName") },
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductshipment.searchCode") },
];
const rules = reactive<FormRules>({
formCode: [
@@ -240,12 +239,12 @@ const operateButtonClick = (eventName: string, row: any) => {
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
// 已审核(formStatus=1)时不显示审核按钮,显示反审按钮
// 未审核(formStatus=0)时显示审核按钮,不显示反审按钮
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
// 已审核(status=1)时不显示审核按钮,显示反审按钮
// 未审核(status=0)时显示审核按钮,不显示反审按钮
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
// 已审核后不能编辑和删除
if (row.formStatus === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
if (row.status === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
return true;
};
@@ -282,7 +281,7 @@ const handleReset = () => {
<el-table-column :label="$t('_prop.production.finishedproductshipment.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn
status-param-name="formStatus"
status-param-name="status"
:status-label-mapping="getFormStatusLabel"
:tag-type-mapping="getFormStatusTagType"
/>

View File

@@ -24,6 +24,7 @@ const getItemUrl = "/production/productionissue/getProductionIssueItemList";
const approveUrl = "/production/productionissue/approvingProductionIssue";
const rejectUrl = "/production/productionissue/rejectProductionIssue";
const generateProductionReturnUrl = "/production/productionissue/productionReturn";
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.common.searchCode") }];
/**
* 基本不变通用变量
*/
@@ -178,6 +179,7 @@ const generateProductionReturn = async () => {
<ExpandablePageableTable
:url="getPageUrl"
ref="tableRef"
:searchers="searchers"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="issueId"

View File

@@ -65,6 +65,7 @@ const dialogTableData = ref([]);
const dialogSelectable = ref(false);
const transferWarehouse = ref();
const issueDialogVisible = ref(false);
const productionPlanStoreNo = ref();
/**
* 可以自定义的变量
*/
@@ -140,6 +141,8 @@ const viewMaterialShortage = async () => {
const rows = validateSelection(true); // 需要校验状态为 0
if (!rows) return;
productionPlanStoreNo.value = rows[0].storeNo;
const params = new URLSearchParams();
rows.forEach(({ id }) => params.append("ids", id));
@@ -514,7 +517,12 @@ const handleReset = () => {
<template #attachment="{ checkPermission }">
<div v-if="checkPermission('generateTransferOrder')" style="display: flex; align-items: center">
<span style="width: 200px; padding-right: 20px">{{ $t("_prop.production.production_plan.outStoreNo") }}</span>
<BaseSelect v-model="transferWarehouse" :url="getWarehouseSelectListUrl" ref="transferWarehouseSelectRef" />
<BaseSelect
v-model="transferWarehouse"
:url="getWarehouseSelectListUrl"
:parse="(options: any) => options.filter((w: any) => w.value !== productionPlanStoreNo)"
ref="transferWarehouseSelectRef"
/>
</div>
</template>
</BaseTableForm>

View File

@@ -18,6 +18,7 @@ const getPageUrl = "/production/productionreturn/getProductionReturnPage";
const getItemUrl = "/production/productionreturn/getProductionReturnItemList";
const approveUrl = "/production/productionreturn/approvingProductionReturn";
const rejectUrl = "/production/productionreturn/rejectProductionReturn";
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.common.searchCode") }];
/**
* 基本不变通用变量
*/
@@ -79,6 +80,7 @@ const getFormStatusTagType = (code: number | null): string => {
<ExpandablePageableTable
:url="getPageUrl"
ref="tableRef"
:searchers="searchers"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="returnId"

View File

@@ -16,6 +16,8 @@ import type { FieldMappingConfig } from "@/components/base/base-form-with-table/
import { ref } from "vue";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import Decimal from "decimal.js";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
/**
* 必须要的变量
@@ -27,8 +29,9 @@ const editUrl = "/purchase/purchaseplan/updatePurchasePlan";
const removeUrl = "/purchase/purchaseplan/deletePurchasePlan";
const getItemsUrl = "/purchase/purchaseplan/getPurchasePlanItemsWithVendorSuggestions";
const generateOrderUrl = "/purchase/purchaseplan/generatePurchaseOrder";
const getItemUrl = "/purchase/purchaseplan/getPurchasePlanItems";
const searchers = [
{ name: "vendorName", type: "text" as const, placeholder: $t("_prop.purchase.purchase_plan.vendorName") },
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.purchase.purchase_plan.searchCode") },
];
const { getPurchasePlanStatusLabel, getPurchasePlanItemStatusLabel } = useStatus();
@@ -53,9 +56,9 @@ const itemArrayName = "planItems";
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
const generateOrderVisible = ref(false);
const generateOrderForm = reactive({
@@ -86,6 +89,10 @@ const edit = (row: any) => {
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.purchase.purchase_plan.delete_message");
};
const showItem = (row: any) => {
itemParentId.value = row.id;
itemVisible.value = true;
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
@@ -132,6 +139,9 @@ const operateButtonClick = (eventName: string, row: any) => {
case "generatePurchaseOrder":
showGenerateOrderDialog(row);
break;
case "showItem":
showItem(row);
break;
}
};
@@ -333,7 +343,7 @@ const generatePurchaseOrder = async () => {
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "商品编号",
sourceKey: "物料编号",
defaultValue: "",
},
@@ -366,24 +376,49 @@ const mappingConfig: FieldMappingConfig = {
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<ExpandablePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="planId"
item-field-name="planItems"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column :label="$t('_prop.purchase.purchase_plan.planNo')" prop="planNo" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.planNo')" prop="planNo" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName" width="180" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeName" width="150" />
<DefaultStatusSwitchColumn
status-param-name="planStatus"
:status-label-mapping="getPurchasePlanStatusLabel"
:tag-type-mapping="getPurchasePlanStatusTagType"
/>
<el-table-column :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask" width="200" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" width="150" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template>
</BasePageableTable>
<template #item-content="{ itemData }">
<el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
<el-table-column
:label="$t('_prop.purchase.purchase_plan_item.purchaseCount')"
prop="purchaseCount"
width="120"
/>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" prop="price" width="120" />
<el-table-column
:label="$t('_prop.purchase.purchase_plan_item.currentCount')"
prop="currentCount"
width="120"
/>
</el-table>
</template>
</ExpandablePageableTable>
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@@ -594,4 +629,23 @@ const mappingConfig: FieldMappingConfig = {
</el-button>
</template>
</BaseTableForm>
<BaseItemDialog
:title="$t('_title.purchase.purchase_plan.showItem')"
v-model:visible="itemVisible"
:url="getItemUrl"
parent-param-name="planId"
v-model:parent-param-value="itemParentId"
>
<template #columns>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
<el-table-column
:label="$t('_prop.purchase.purchase_plan_item.purchaseCount')"
prop="purchaseCount"
width="120"
/>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" prop="price" width="120" />
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.currentCount')" prop="currentCount" width="120" />
</template>
</BaseItemDialog>
</template>

View File

@@ -25,21 +25,37 @@ const approveUrl = "/sale/saleorder/approveSaleOrder";
const rejectUrl = "/sale/saleorder/unapproveSaleOrder";
const itemUrl = "/sale/saleorder/getSaleOrderItemList";
const keyAccountSelectUrl = "/sys/keyaccount/getKeyAccountSelectList";
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const searchers = [
{
name: "customerName",
type: "text" as const,
placeholder: $t("_prop.sale.saleorder.customerName"),
clearable: true,
},
];
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.saleorder.searchCode") }];
const rules = reactive<FormRules>({
formCode: [{ required: true, message: $t("_message.sale.saleorder.input_formCode"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.sale.saleorder.input_formName"), trigger: "blur" }],
customerId: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
customerName: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
partNumber: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
callback($t("_message.sale.saleorder.input_partNumber"));
}
(async () => {
try {
const isExists = await get(partNumberExistsUrl, { partNumber: value }).then(res => res.data);
if (isExists) {
callback();
}
callback($t("_message.purchase.purchase_order.part_number_not_exists"));
} catch (err: any) {
callback(new Error(err));
}
})();
},
trigger: "blur",
},
],
saleOrderItems: [
{
required: true,
@@ -96,7 +112,7 @@ const generateFormCode = () => {
String(now.getHours()).padStart(2, "0") +
String(now.getMinutes()).padStart(2, "0") +
String(now.getSeconds()).padStart(2, "0");
return "SO" + dateStr;
return "PO" + dateStr;
};
// 监听客户选择变化,同步更新客户名称

View File

@@ -7,7 +7,8 @@ import type { FormInstance, FormItemRule, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import { get } from "@/common/http/request";
import { get, post } from "@/common/http/request";
import { ElMessage } from "element-plus";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
@@ -28,6 +29,7 @@ const approveUrl = "/warehouse/stocktransferorder/approveStockTransferOrder";
const rejectUrl = "/warehouse/stocktransferorder/rejectStockTransferOrder";
const warehouseSelectUrl = "/warehouse/warehouse/getWarehouseSelectList";
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const checkStockUrl = "/warehouse/stock/checkStock";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.stocktransferorder.searchCode") },
{ name: "partNumber", type: "text" as const, placeholder: $t("_prop.warehouse.stocktransferorder.partNumber") },
@@ -96,6 +98,31 @@ const rules = reactive<FormRules>({
trigger: "change",
},
],
stockCheck: [
{
validator: (rule, value, callback) => {
const items = form.value.transferOrderItems || [];
const partCountMap: Record<string, number> = {};
items.forEach((item: any) => {
if (item.partNumber) {
partCountMap[item.partNumber] = (partCountMap[item.partNumber] || 0) + (item.productCount || 0);
}
});
const stockCheckItems = Object.keys(partCountMap).map(partNumber => ({
partNumber,
requiredCount: partCountMap[partNumber],
}));
post(checkStockUrl, { storeNo: form.value.outStoreNo, items: stockCheckItems })
.then(() => {
callback();
})
.catch((err: any) => {
callback(new Error(err));
});
},
trigger: "submit",
},
],
});
const itemArrayName = "transferOrderItems";
@@ -226,8 +253,11 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
if (targetRef !== undefined) {
targetRef.validate((valid: any) => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
if (formType.value) {
useEdit(editUrl, form, visible);
} else {
useAdd(addUrl, form, visible);
}
}
});
}
@@ -262,8 +292,8 @@ const operateButtonClick = (eventName: string, row: any) => {
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
return true;
};
</script>
@@ -288,7 +318,7 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn
status-param-name="formStatus"
status-param-name="status"
:status-label-mapping="getFormStatusLabel"
:tag-type-mapping="getFormStatusTagType"
/>

View File

@@ -156,9 +156,9 @@ const operateButtonClick = (eventName: string, row: any) => {
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
if (row.formStatus === 1 && button.eventName === "edit") return false;
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
if (row.status === 1 && button.eventName === "edit") return false;
return true;
};
@@ -216,7 +216,7 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn
status-param-name="formStatus"
status-param-name="status"
:status-label-mapping="getFormStatusLabel"
:tag-type-mapping="getFormStatusTagType"
/>

View File

@@ -11,15 +11,18 @@ import { formatDate } from "@/common/utils/format-utils";
/**
* 必须要的变量
*/
// defineOptions({
// name: "store",
// });
const getPageUrl = "/warehouse/warehouse/getWarehousePage";
const addUrl = "/warehouse/warehouse/addWarehouse";
const editUrl = "/warehouse/warehouse/updateWarehouse";
const removeUrl = "/warehouse/warehouse/deleteWarehouse";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehouse.searchCode") },
];
const rules = reactive<FormRules>({});
const searchers = [{ name: "storeName", type: "text" as const, placeholder: $t("_prop.systemset.store.storeName") }];
const rules = reactive<FormRules>({
storeName: [{ required: true, message: $t("_message.systemset.store.input_storeName"), trigger: "blur" }],
storeMark: [{ required: false, message: $t("_message.systemset.store.input_storeMark"), trigger: "blur" }],
});
/**
* 基本不变通用变量
*/
@@ -32,18 +35,18 @@ const { title, visible, formType, form } = useGeneralPageRef();
const add = () => {
form.value = {};
title.value = "_title.warehouse.warehouse.add";
title.value = "_title.systemset.store.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.warehouse.edit";
title.value = "_title.systemset.store.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.warehouse.delete_message");
useRemove(removeUrl, row.id, "_message.systemset.store.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
@@ -79,9 +82,8 @@ const operateButtonClick = (eventName: string, row: any) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.warehouse.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.warehouse.storeMark')" prop="storeMark" />
<el-table-column :label="$t('_prop.systemset.store.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.systemset.store.storeMark')" prop="storeMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
@@ -89,6 +91,12 @@ const operateButtonClick = (eventName: string, row: any) => {
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.systemset.store.storeName')" prop="storeName">
<el-input v-model="form.storeName" :placeholder="$t('_message.systemset.store.input_storeName')" />
</el-form-item>
<el-form-item :label="$t('_prop.systemset.store.storeMark')" prop="storeMark">
<el-input v-model="form.storeMark" :placeholder="$t('_message.systemset.store.input_storeMark')" />
</el-form-item>
</template>
</BaseForm>
</template>