Просмотр исходного кода

feat(s0): S0 销售/供应 A 类页公司/工厂前台无感化(客户/供应商/订单评审/产品设计/品类前置期/物料计划周期)

复用批次6 useS0MfgOrgScope helper,将 6 页公司/工厂从"用户前台选择字段"降级为"系统后台归属字段":

- 新增:applyDefaultOrgScopeForCreate 自动补默认 SysOrg 归属(S0示范公司/一工厂),用户无需选择公司/工厂。
- 编辑:preserveOrgScopeForEdit 保留接口返回的历史归属,不转雪花。
- 提交:normalizeOrgScopeForSubmit 确保 payload 稳定携带 companyRefId/factoryRefId/domainCode。
- watcher 走 shouldClearFactoryOnCompanyChange 守卫,隐藏字段/程序化载入不清空 legacy 工厂。
- 移除公司/工厂用户必填 rules(CustomerList 一并移除自定义 validateRequiredOrgField 及 selectedCompanyHasNoFactories 提交阻断)。
- 对话框隐藏公司/工厂输入控件(v-if=false),form 值与 payload 不变。
- 仅前端 6 页,未改 helper、未改后端;不做 legacy↔SysOrg 域映射、不回填历史数据。

chore: bump version Web 2.4.236
YY968XX 1 день назад
Родитель
Сommit
ce281e1b9a

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
   "name": "admin.net",
   "type": "module",
-  "version": "2.4.235",
+  "version": "2.4.236",
   "packageManager": "pnpm@10.32.1",
   "lastBuildTime": "2026.03.15",
   "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 19 - 27
Web/src/views/aidop/s0/sales/CustomerList.vue

@@ -78,14 +78,15 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="720px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
 				<el-row :gutter="16">
-					<el-col :span="12">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col v-if="false" :span="12">
 						<el-form-item label="公司" prop="companyRefId">
 							<el-select v-model="form.companyRefId" clearable filterable placeholder="请选择公司" style="width: 100%">
 								<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
+					<el-col v-if="false" :span="12">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select
 								v-model="form.factoryRefId"
@@ -214,6 +215,12 @@ import {
 	type S0CustMasterRow,
 	type S0CustMasterUpsert,
 } from '../api/s0SalesApi';
+import {
+	applyDefaultOrgScopeForCreate,
+	normalizeOrgScopeForSubmit,
+	preserveOrgScopeForEdit,
+	shouldClearFactoryOnCompanyChange,
+} from '../composables/useS0MfgOrgScope';
 
 const route = useRoute();
 const pageTitle = computed(() => (route.meta?.title as string) || '客户信息维护');
@@ -275,26 +282,8 @@ const form = reactive<CustomerFormModel>({
 	updateUser: '',
 });
 
-function validateRequiredOrgField(message: string) {
-	return (_rule: unknown, value: string | number | undefined | null, callback: (error?: Error) => void) => {
-		// 组织 ID 语义:已选=非空字符串(雪花 ID),未选=undefined/null/''
-		// 禁止 typeof === 'number' 假设,否则会拒绝合法的字符串雪花 ID
-		if (value == null) {
-			callback(new Error(message));
-			return;
-		}
-		const s = typeof value === 'string' ? value : String(value);
-		if (s === '' || s === '0') {
-			callback(new Error(message));
-			return;
-		}
-		callback();
-	};
-}
-
+// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 const rules: FormRules = {
-	companyRefId: [{ validator: validateRequiredOrgField('请选择公司'), trigger: 'change' }],
-	factoryRefId: [{ validator: validateRequiredOrgField('请选择工厂'), trigger: 'change' }],
 	cust: [{ required: true, message: '请填写客户编码', trigger: 'blur' }],
 	sortName: [{ required: true, message: '请填写客户简称', trigger: 'blur' }],
 };
@@ -374,7 +363,9 @@ function buildPayload(): S0CustMasterUpsert | null {
 watch(
 	() => form.companyRefId,
 	() => {
-		if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) {
+		// 公司/工厂为隐藏的后台归属字段,此变化均为程序化载入(openCreate 补默认 / openEdit 回填),
+		// 非用户主动切换,故 userInitiated=false,永不清空已载入的工厂/域值(保护 legacy 归属)。
+		if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) {
 			form.factoryRefId = undefined;
 			form.domainCode = '';
 		}
@@ -473,6 +464,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属(公司/工厂/domainCode),用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	dialogTitle.value = '新增客户';
 	dialogVisible.value = true;
 }
@@ -507,16 +500,15 @@ function openEdit(row: S0CustMasterRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 值不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	dialogVisible.value = true;
 }
 
 async function submitForm() {
-	if (selectedCompanyHasNoFactories.value) {
-		ElMessage.warning('所选公司下暂无可用工厂,请先维护组织数据或机构权限。');
-		return;
-	}
-
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(含 legacy),不做 legacy↔雪花映射。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload = buildPayload();

+ 12 - 5
Web/src/views/aidop/s0/sales/OrderReviewCycleList.vue

@@ -69,14 +69,15 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="130px">
 				<el-row :gutter="16">
-					<el-col :span="12">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col :span="12" v-if="false">
 						<el-form-item label="公司" prop="companyRefId">
 							<el-select v-model="form.companyRefId" filterable style="width: 100%">
 								<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
+					<el-col :span="12" v-if="false">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCode">
 								<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
@@ -148,6 +149,7 @@ import {
 	type S0OrderReviewCycleRow,
 	type S0OrderReviewCycleUpsert,
 } from '../api/s0SalesApi';
+import { applyDefaultOrgScopeForCreate, normalizeOrgScopeForSubmit, preserveOrgScopeForEdit, shouldClearFactoryOnCompanyChange } from '../composables/useS0MfgOrgScope';
 import DictDataMaintainPanel from './components/DictDataMaintainPanel.vue';
 
 const route = useRoute();
@@ -204,8 +206,7 @@ function emptyForm(): S0OrderReviewCycleUpsert {
 const form = reactive<S0OrderReviewCycleUpsert>(emptyForm());
 
 const rules: FormRules = {
-	companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
+	// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 	stdHours: [{ required: true, message: '请填写标准评审时长', trigger: 'blur' }],
 };
 
@@ -217,7 +218,7 @@ function syncDomainCode() {
 watch(
 	() => form.companyRefId,
 	() => {
-		if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) {
+		if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) {
 			form.factoryRefId = undefined;
 		}
 	}
@@ -289,6 +290,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属,用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	dialogTitle.value = '新增订单评审周期';
 	dialogVisible.value = true;
 }
@@ -308,11 +311,15 @@ function openEdit(row: S0OrderReviewCycleRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	dialogVisible.value = true;
 }
 
 async function submitForm() {
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(含 legacy),不做 legacy↔雪花映射。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload: S0OrderReviewCycleUpsert = { ...form };

+ 19 - 5
Web/src/views/aidop/s0/sales/ProductDesignCycleList.vue

@@ -72,14 +72,15 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="130px">
 				<el-row :gutter="16">
-					<el-col :span="12">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col v-if="false" :span="12">
 						<el-form-item label="公司" prop="companyRefId">
 							<el-select v-model="form.companyRefId" filterable style="width: 100%">
 								<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
+					<el-col v-if="false" :span="12">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCode">
 								<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
@@ -134,6 +135,12 @@ import {
 	type S0ProductDesignCycleRow,
 	type S0ProductDesignCycleUpsert,
 } from '../api/s0SalesApi';
+import {
+	applyDefaultOrgScopeForCreate,
+	normalizeOrgScopeForSubmit,
+	preserveOrgScopeForEdit,
+	shouldClearFactoryOnCompanyChange,
+} from '../composables/useS0MfgOrgScope';
 
 const route = useRoute();
 const pageTitle = computed(() => (route.meta?.title as string) || '产品设计周期');
@@ -188,9 +195,8 @@ function emptyForm(): S0ProductDesignCycleUpsert {
 
 const form = reactive<S0ProductDesignCycleUpsert>(emptyForm());
 
+// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 const rules: FormRules = {
-	companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
 	itemType: [{ required: true, message: '请选择物料类型', trigger: 'change' }],
 	ownerApplication: [{ required: true, message: '请选择物料属性', trigger: 'change' }],
 };
@@ -203,7 +209,9 @@ function syncDomainCode() {
 watch(
 	() => form.companyRefId,
 	() => {
-		if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) {
+		// 公司/工厂为隐藏的后台归属字段,此变化均为程序化载入(openCreate 补默认 / openEdit 回填),
+		// 非用户主动切换,故 userInitiated=false,永不清空已载入的工厂值(保护 legacy 归属)。
+		if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) {
 			form.factoryRefId = undefined;
 		}
 	}
@@ -273,6 +281,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属,用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	dialogTitle.value = '新增产品设计周期';
 	dialogVisible.value = true;
 }
@@ -292,11 +302,15 @@ function openEdit(row: S0ProductDesignCycleRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	dialogVisible.value = true;
 }
 
 async function submitForm() {
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(含 legacy),不做 legacy↔雪花映射。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload: S0ProductDesignCycleUpsert = { ...form };

+ 16 - 5
Web/src/views/aidop/s0/supply/CategoryLeadTimeList.vue

@@ -60,14 +60,15 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="680px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="130px">
 				<el-row :gutter="16">
-					<el-col :span="12">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col :span="12" v-if="false">
 						<el-form-item label="公司" prop="companyRefId">
 							<el-select v-model="form.companyRefId" filterable style="width: 100%">
 								<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
+					<el-col :span="12" v-if="false">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCode">
 								<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
@@ -131,6 +132,7 @@ import {
 	type S0CategoryLeadTimeRow,
 	type S0CategoryLeadTimeUpsert,
 } from '../api/s0SupplyApi';
+import { applyDefaultOrgScopeForCreate, normalizeOrgScopeForSubmit, preserveOrgScopeForEdit, shouldClearFactoryOnCompanyChange } from '../composables/useS0MfgOrgScope';
 
 const route = useRoute();
 const pageTitle = computed(() => (route.meta?.title as string) || '品类采购前置期');
@@ -170,9 +172,8 @@ const form = reactive<S0CategoryLeadTimeUpsert>({
 	updateUser: '',
 });
 
+// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 const rules: FormRules = {
-	companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
 	categoryCode: [{ required: true, message: '请填写品类编码', trigger: 'blur' }],
 	ownerApplication: [{ required: true, message: '请填写物料属性', trigger: 'blur' }],
 	leadTimeDays: [{ required: true, message: '请填写采购前置期', trigger: 'blur' }],
@@ -197,7 +198,11 @@ watch(
 watch(
 	() => form.companyRefId,
 	() => {
-		if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) form.factoryRefId = undefined;
+		// 公司/工厂为隐藏的后台归属字段,此变化均为程序化载入(openCreate 补默认 / openEdit 回填),
+		// 非用户主动切换,故 userInitiated=false,永不清空已载入的工厂值(保护 legacy 归属)。
+		if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) {
+			form.factoryRefId = undefined;
+		}
 	}
 );
 
@@ -264,6 +269,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属,用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	dialogTitle.value = '新增品类采购前置期';
 	dialogVisible.value = true;
 }
@@ -285,11 +292,15 @@ function openEdit(row: S0CategoryLeadTimeRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	dialogVisible.value = true;
 }
 
 async function submitForm() {
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(含 legacy),不做 legacy↔雪花映射。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload: S0CategoryLeadTimeUpsert = { ...form };

+ 12 - 5
Web/src/views/aidop/s0/supply/MaterialPlanCycleList.vue

@@ -55,12 +55,13 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="620px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="150px">
 				<el-row :gutter="16">
-					<el-col :span="12"><el-form-item label="公司" prop="companyRefId">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col v-if="false" :span="12"><el-form-item label="公司" prop="companyRefId">
 						<el-select v-model="form.companyRefId" filterable style="width: 100%">
 							<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 						</el-select>
 					</el-form-item></el-col>
-					<el-col :span="12"><el-form-item label="工厂" prop="factoryRefId">
+					<el-col v-if="false" :span="12"><el-form-item label="工厂" prop="factoryRefId">
 						<el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCode">
 							<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 						</el-select>
@@ -92,6 +93,7 @@ import {
 	type S0MaterialPlanCycleRow,
 	type S0MaterialPlanCycleUpsert,
 } from '../api/s0SupplyApi';
+import { applyDefaultOrgScopeForCreate, normalizeOrgScopeForSubmit, preserveOrgScopeForEdit, shouldClearFactoryOnCompanyChange } from '../composables/useS0MfgOrgScope';
 
 const route = useRoute();
 const pageTitle = computed(() => (route.meta?.title as string) || '物料计划周期');
@@ -136,14 +138,13 @@ const form = reactive<S0MaterialPlanCycleUpsert>({
 	updateUser: '',
 });
 
+// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 const rules: FormRules = {
-	companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
 	stdHours: [{ required: true, message: '请填写标准时长', trigger: 'blur' }],
 };
 
 watch(() => form.companyRefId, () => {
-	if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) form.factoryRefId = undefined;
+	if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) { form.factoryRefId = undefined; }
 });
 watch(() => query.companyRefId, () => {
 	if (!filteredFactoryOptions.value.some((item) => item.id === query.factoryRefId)) query.factoryRefId = undefined;
@@ -194,6 +195,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属,用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	dialogTitle.value = '新增物料计划周期';
 	dialogVisible.value = true;
 }
@@ -213,11 +216,15 @@ function openEdit(row: S0MaterialPlanCycleRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	dialogVisible.value = true;
 }
 
 async function submitForm() {
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(含 legacy),不做 legacy↔雪花映射。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload: S0MaterialPlanCycleUpsert = { ...form };

+ 12 - 5
Web/src/views/aidop/s0/supply/SupplierList.vue

@@ -90,14 +90,15 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="860px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
 				<el-row :gutter="16">
-					<el-col :span="12">
+					<!-- 公司/工厂已降级为系统后台归属字段:前台隐藏输入控件,form 值与 payload 仍由 openCreate 补默认 / openEdit 保值维护。 -->
+					<el-col v-if="false" :span="12">
 						<el-form-item label="公司" prop="companyRefId">
 							<el-select v-model="form.companyRefId" filterable style="width: 100%">
 								<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
+					<el-col v-if="false" :span="12">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCodeFromFactory">
 								<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
@@ -269,6 +270,7 @@ import {
 	type S0SuppMasterUpsert,
 } from '../api/s0SupplyApi';
 import { s0LocationsApi, type S0LocationOptionRow } from '../api/s0WarehouseApi';
+import { applyDefaultOrgScopeForCreate, normalizeOrgScopeForSubmit, preserveOrgScopeForEdit, shouldClearFactoryOnCompanyChange } from '../composables/useS0MfgOrgScope';
 
 type ApCyclePresetKey = 'none' | 'fullMonth' | 'firstHalf' | 'secondHalf' | 'dualHalf' | 'crossMonth' | 'custom';
 
@@ -385,9 +387,8 @@ const form = reactive<S0SuppMasterUpsert>({
 	updateUser: '',
 });
 
+// 公司/工厂已降级为系统后台归属字段(新增自动补默认、编辑保留原值),不再作为用户前台必填项。
 const rules: FormRules = {
-	companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
 	supp: [{ required: true, message: '请填写供应商编码', trigger: 'blur' }],
 };
 
@@ -410,7 +411,7 @@ function syncDomainCodeFromFactory() {
 watch(
 	() => form.companyRefId,
 	() => {
-		if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) {
+		if (shouldClearFactoryOnCompanyChange(formFactoryOptions.value, form.factoryRefId, false)) {
 			form.factoryRefId = undefined;
 		}
 	}
@@ -515,6 +516,8 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认 SysOrg 归属,用户无需选择公司/工厂。
+	applyDefaultOrgScopeForCreate(form, companyOptions.value, factoryOptions.value);
 	apCyclePreset.value = 'none';
 	dialogTitle.value = '新增供应商';
 	dialogVisible.value = true;
@@ -551,6 +554,8 @@ function openEdit(row: S0SuppMasterRow) {
 		createUser: row.createUser ?? '',
 		updateUser: row.updateUser ?? '',
 	});
+	// 编辑:保留接口返回的原归属(legacy 不转雪花)。
+	preserveOrgScopeForEdit(form, row);
 	apCyclePreset.value = identifyApPreset(row.apStartDay1, row.apEndDay1, row.apStartDay2, row.apEndDay2);
 	dialogVisible.value = true;
 	void loadLocationOptions(form.domainCode);
@@ -558,6 +563,8 @@ function openEdit(row: S0SuppMasterRow) {
 
 async function submitForm() {
 	await formRef.value?.validate();
+	// 提交前统一归属:缺则补默认、有则保留(legacy 不转雪花),用户无需选择公司/工厂。
+	normalizeOrgScopeForSubmit(form, editingId.value ? 'edit' : 'create', companyOptions.value, factoryOptions.value);
 	saving.value = true;
 	try {
 		const payload: S0SuppMasterUpsert = { ...form };