Explorar el Código

feat(s0): S0 制造 factory-only/domain 组公司/工厂前台无感化(前处理要素参数/SOP文件类型/SOP维护)

契约核实:3 页后端均为 domain-only(Domain [Required]、无 companyRefId/factoryRefId)。按页治理:

- 隐藏工厂输入控件;openCreate 用 getDefaultS0OrgScope 补默认工厂(1329900200002)使 resolveDomain 派生 domain=S0-F001。
- submit domain 兜底:resolveDomain 为空时取默认 domainCode=S0-F001,保证 domain 非空、杜绝 Domain Required 400。
- 不向 domain-only DTO 强加 companyRefId/factoryRefId(SopMaintenance 因既有 {...form,domain} 结构仍含 factoryRefId,后端 DTO 无此字段自动忽略、保存 200、未引入 companyRefId)。
- 移除工厂用户必填 rules;保留业务必填(要素/参数编码、imageTypeID/descr、itemNum)。
- Preprocess/SopMaintenance 补 applyDefaultQueryScope(对齐 SopFileType HEAD 既有做法),工厂查询隐藏后列表仍按默认 domain 加载。
- 仅前端 3 页,未改 helper、未改后端;WorkOrderControlParams 本批排除(单页 load-by-domain singleton 编辑器,无 build-and-delete 安全冒烟路径)。
- 不做 legacy↔SysOrg 域映射、不回填历史数据。

chore: bump version Web 2.4.241
YY968XX hace 14 horas
padre
commit
eb5bb02a62

+ 1 - 1
Web/package.json

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

+ 24 - 6
Web/src/views/aidop/s0/manufacturing/PreprocessElementParamList.vue

@@ -45,7 +45,8 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="640px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="130px">
 				<el-row :gutter="12">
-					<el-col :span="12">
+					<!-- 工厂已降级为系统后台归属字段:前台隐藏输入控件,domain 由 openCreate 补默认 / submit 兜底维护。 -->
+					<el-col :span="12" v-if="false">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%">
 								<el-option
@@ -102,7 +103,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
 import AidopDemoShell from '../../components/AidopDemoShell.vue';
-import { useS0MfgOrgScope } from '../composables/useS0MfgOrgScope';
+import { useS0MfgOrgScope, getDefaultS0OrgScope } from '../composables/useS0MfgOrgScope';
 import { s0MfgPreprocessElementParamsApi } from '../api/s0ManufacturingApi';
 
 const route = useRoute();
@@ -126,6 +127,14 @@ const query = reactive({
 	pageSize: 20,
 });
 
+// 列表按工厂域(domain)查询:查询区工厂隐藏,按默认组织自动确定 domain 范围
+// (与新增/编辑归属同口径,复用 getDefaultS0OrgScope)。
+function applyDefaultQueryScope() {
+	const d = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value);
+	query.companyRefId = d.companyRefId;
+	query.factoryRefId = d.factoryRefId;
+}
+
 const loading = ref(false);
 const rows = ref<Row[]>([]);
 const total = ref(0);
@@ -163,7 +172,7 @@ watch(
 );
 
 const rules: FormRules = {
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
+	// 工厂已前台隐藏并由默认组织自动补齐,移除 factoryRefId 必填校验;保留业务字段必填。
 	deviceNumber: [{ required: true, message: '请填写要素编码', trigger: 'blur' }],
 	messageCode: [{ required: true, message: '请填写参数编码', trigger: 'blur' }],
 };
@@ -195,9 +204,9 @@ async function loadList() {
 
 function resetQuery() {
 	query.keyword = '';
-	query.companyRefId = undefined;
-	query.factoryRefId = undefined;
 	query.page = 1;
+	// 重置后恢复默认工厂/域,避免清空导致空查询
+	applyDefaultQueryScope();
 	void loadList();
 }
 
@@ -221,6 +230,9 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认工厂(使 resolveDomain 派生 domain=S0-F001),用户无需选择工厂。
+	const __scope = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value);
+	Object.assign(form, { factoryRefId: __scope.factoryRefId });
 	dialogTitle.value = '新增前处理要素参数';
 	dialogVisible.value = true;
 }
@@ -250,7 +262,11 @@ async function submitForm() {
 	await formRef.value?.validate();
 	saving.value = true;
 	try {
-		const domain = resolveDomain(form.factoryRefId);
+		// 工厂控件前台隐藏:优先按 form.factoryRefId 派生 domain;未解析出时兜底为默认组织的 domainCode(=S0-F001)。
+		let domain = resolveDomain(form.factoryRefId);
+		if (!domain) {
+			domain = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value).domainCode ?? '';
+		}
 		if (!domain) throw new Error('domain is required');
 		const payload = {
 			domain,
@@ -291,6 +307,8 @@ function onDelete(row: Row) {
 
 onMounted(async () => {
 	await loadOrgs();
+	// 查询区工厂隐藏,按默认组织自动确定 domain 范围
+	applyDefaultQueryScope();
 	await loadList();
 });
 </script>

+ 11 - 3
Web/src/views/aidop/s0/manufacturing/SopFileTypeList.vue

@@ -36,7 +36,8 @@
 
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="520px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="88px">
-				<el-form-item label="工厂" prop="factoryRefId">
+				<!-- 工厂已降级为系统后台归属字段:前台隐藏输入控件,domain 由 openCreate 补默认 / submit 兜底维护。 -->
+				<el-form-item v-if="false" label="工厂" prop="factoryRefId">
 					<el-select v-model="form.factoryRefId" filterable style="width: 100%">
 						<el-option v-for="item in formFactories" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
 					</el-select>
@@ -108,8 +109,8 @@ watch(
 	},
 );
 
+// 工厂已降级为系统后台归属字段(新增自动补默认),不再作为用户前台必填项。
 const rules: FormRules = {
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
 	imageTypeID: [{ required: true, message: '请填写编码', trigger: 'blur' }],
 	descr: [{ required: true, message: '请填写描述', trigger: 'blur' }],
 };
@@ -165,6 +166,9 @@ function resetForm() {
 
 function openCreate() {
 	resetForm();
+	// 新增:自动补默认工厂(使 resolveDomain 派生 domain=S0-F001),用户无需选择工厂。
+	const __scope = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value);
+	Object.assign(form, { factoryRefId: __scope.factoryRefId });
 	dialogTitle.value = '新增 SOP 类型';
 	dialogVisible.value = true;
 }
@@ -186,7 +190,11 @@ async function submitForm() {
 	await formRef.value?.validate();
 	saving.value = true;
 	try {
-		const domain = resolveDomain(form.factoryRefId);
+		// domain 兜底:隐藏工厂后仍保证 domain 非空(默认 S0-F001)。
+		let domain = resolveDomain(form.factoryRefId);
+		if (!domain) {
+			domain = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value).domainCode ?? '';
+		}
 		if (!domain) throw new Error('domain is required');
 		const payload = { domain, imageTypeID: form.imageTypeID, descr: form.descr };
 		if (editingId.value) {

+ 24 - 6
Web/src/views/aidop/s0/manufacturing/SopMaintenanceList.vue

@@ -43,7 +43,8 @@
 		<el-dialog v-model="dialogVisible" :title="dialogTitle" width="640px" destroy-on-close @closed="resetForm">
 			<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
 				<el-row :gutter="12">
-					<el-col :span="12">
+					<!-- 工厂已降级为系统后台归属字段:前台隐藏输入控件,domain 由 openCreate 补默认 / submit 兜底维护。 -->
+					<el-col :span="12" v-if="false">
 						<el-form-item label="工厂" prop="factoryRefId">
 							<el-select v-model="form.factoryRefId" filterable style="width: 100%">
 								<el-option v-for="item in formFactories" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
@@ -73,7 +74,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
 import AidopDemoShell from '../../components/AidopDemoShell.vue';
-import { useS0MfgOrgScope } from '../composables/useS0MfgOrgScope';
+import { useS0MfgOrgScope, getDefaultS0OrgScope } from '../composables/useS0MfgOrgScope';
 import { s0MfgSopDocumentsApi } from '../api/s0ManufacturingApi';
 
 const route = useRoute();
@@ -131,10 +132,18 @@ watch(
 );
 
 const rules: FormRules = {
-	factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
+	// 工厂已降级为后台归属字段(domain 由默认化维护):移除 factoryRefId 必填校验,保留业务必填。
 	itemNum: [{ required: true, message: '请填写物料编码', trigger: 'blur' }],
 };
 
+// 列表按工厂域(domain)查询:接口必传 Domain。查询栏不暴露工厂选择,
+// 统一由系统按 S0 示范组织默认化(与新增/编辑归属同口径,复用 getDefaultS0OrgScope)。
+function applyDefaultQueryScope() {
+	const d = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value);
+	query.companyRefId = d.companyRefId;
+	query.factoryRefId = d.factoryRefId;
+}
+
 async function loadList() {
 	loading.value = true;
 	try {
@@ -162,9 +171,9 @@ async function loadList() {
 
 function resetQuery() {
 	query.keyword = '';
-	query.companyRefId = undefined;
-	query.factoryRefId = undefined;
 	query.page = 1;
+	// 重置后恢复默认工厂/域,避免清空导致列表不发请求
+	applyDefaultQueryScope();
 	void loadList();
 }
 
@@ -186,6 +195,9 @@ function resetForm() {
 
 async function openCreate() {
 	resetForm();
+	// 新增:自动补默认工厂(使 resolveDomain 派生 domain=S0-F001),用户无需选择工厂。
+	const __scope = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value);
+	Object.assign(form, { factoryRefId: __scope.factoryRefId });
 	dialogTitle.value = '新增 SOP 文档';
 	dialogVisible.value = true;
 }
@@ -213,7 +225,11 @@ async function submitForm() {
 	await formRef.value?.validate();
 	saving.value = true;
 	try {
-		const domain = resolveDomain(form.factoryRefId);
+		// domain 兜底:隐藏工厂后仍保证 domain 非空(默认 S0-F001)。
+		let domain = resolveDomain(form.factoryRefId);
+		if (!domain) {
+			domain = getDefaultS0OrgScope(companyOptions.value, factoryOptions.value).domainCode ?? '';
+		}
 		if (!domain) throw new Error('domain is required');
 		const payload = { ...form, domain };
 		if (editingId.value) {
@@ -242,6 +258,8 @@ function onDelete(row: Row) {
 
 onMounted(async () => {
 	await loadOrgs();
+	// 组织加载完成后按 S0 示范组织默认化查询归属,确保首屏即发列表请求
+	applyDefaultQueryScope();
 	await loadList();
 });
 </script>