|
|
@@ -92,17 +92,28 @@
|
|
|
<el-row :gutter="16">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="公司" prop="companyRefId">
|
|
|
- <el-select v-model="form.companyRefId" filterable style="width: 100%">
|
|
|
+ <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-form-item label="工厂" prop="factoryRefId">
|
|
|
- <el-select v-model="form.factoryRefId" filterable style="width: 100%" @change="syncDomainCodeFromFactory">
|
|
|
+ <el-select
|
|
|
+ v-model="form.factoryRefId"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ placeholder="请选择工厂"
|
|
|
+ style="width: 100%"
|
|
|
+ :disabled="!form.companyRefId || selectedCompanyHasNoFactories"
|
|
|
+ @change="syncDomainCodeFromFactory"
|
|
|
+ >
|
|
|
<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
+ <div v-if="selectedCompanyHasNoFactories" class="form-help form-help--warning">
|
|
|
+ 该公司下暂无可用工厂,请先维护组织数据或机构权限。
|
|
|
+ </div>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="客户编码" prop="cust">
|
|
|
@@ -239,9 +250,14 @@ const companyOptions = ref<OrgOption[]>([]);
|
|
|
const factoryOptions = ref<OrgOption[]>([]);
|
|
|
const currencyOptions = ref<OptionItem[]>([]);
|
|
|
|
|
|
-const form = reactive<S0CustMasterUpsert>({
|
|
|
- companyRefId: 0,
|
|
|
- factoryRefId: 0,
|
|
|
+type CustomerFormModel = Omit<S0CustMasterUpsert, 'companyRefId' | 'factoryRefId'> & {
|
|
|
+ companyRefId: number | undefined;
|
|
|
+ factoryRefId: number | undefined;
|
|
|
+};
|
|
|
+
|
|
|
+const form = reactive<CustomerFormModel>({
|
|
|
+ companyRefId: undefined,
|
|
|
+ factoryRefId: undefined,
|
|
|
domainCode: '',
|
|
|
cust: '',
|
|
|
sortName: '',
|
|
|
@@ -265,9 +281,19 @@ const form = reactive<S0CustMasterUpsert>({
|
|
|
updateUser: '',
|
|
|
});
|
|
|
|
|
|
+function validateRequiredOrgField(message: string) {
|
|
|
+ return (_rule: unknown, value: number | undefined, callback: (error?: Error) => void) => {
|
|
|
+ if (typeof value !== 'number' || value <= 0) {
|
|
|
+ callback(new Error(message));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
const rules: FormRules = {
|
|
|
- companyRefId: [{ required: true, message: '请选择公司', trigger: 'change' }],
|
|
|
- factoryRefId: [{ required: true, message: '请选择工厂', trigger: 'change' }],
|
|
|
+ companyRefId: [{ validator: validateRequiredOrgField('请选择公司'), trigger: 'change' }],
|
|
|
+ factoryRefId: [{ validator: validateRequiredOrgField('请选择工厂'), trigger: 'change' }],
|
|
|
cust: [{ required: true, message: '请填写客户编码', trigger: 'blur' }],
|
|
|
sortName: [{ required: true, message: '请填写客户简称', trigger: 'blur' }],
|
|
|
};
|
|
|
@@ -282,16 +308,73 @@ const formFactoryOptions = computed(() => {
|
|
|
return factoryOptions.value.filter((item) => item.pid === form.companyRefId);
|
|
|
});
|
|
|
|
|
|
+const selectedCompanyHasNoFactories = computed(() => Boolean(form.companyRefId) && formFactoryOptions.value.length === 0);
|
|
|
+
|
|
|
function syncDomainCodeFromFactory() {
|
|
|
const f = factoryOptions.value.find((item) => item.id === form.factoryRefId);
|
|
|
form.domainCode = f?.code ?? '';
|
|
|
}
|
|
|
|
|
|
+function stringifyBusinessError(value: unknown): string | undefined {
|
|
|
+ if (!value) return undefined;
|
|
|
+ if (typeof value === 'string') {
|
|
|
+ const text = value.trim();
|
|
|
+ return text || undefined;
|
|
|
+ }
|
|
|
+ if (Array.isArray(value)) {
|
|
|
+ const parts = value.map((item) => stringifyBusinessError(item)).filter(Boolean);
|
|
|
+ return parts.length ? parts.join(';') : undefined;
|
|
|
+ }
|
|
|
+ if (typeof value === 'object') {
|
|
|
+ const parts = Object.values(value as Record<string, unknown>)
|
|
|
+ .map((item) => stringifyBusinessError(item))
|
|
|
+ .filter(Boolean);
|
|
|
+ return parts.length ? parts.join(';') : undefined;
|
|
|
+ }
|
|
|
+ return undefined;
|
|
|
+}
|
|
|
+
|
|
|
+function isRawTransportMessage(message: string | undefined): boolean {
|
|
|
+ if (!message) return true;
|
|
|
+ return /request failed with status code|network error|timeout|err_/i.test(message);
|
|
|
+}
|
|
|
+
|
|
|
+function getCustomerSaveErrorMessage(error: any): string {
|
|
|
+ const responseMessage =
|
|
|
+ stringifyBusinessError(error?.response?.data?.errors) ||
|
|
|
+ stringifyBusinessError(error?.response?.data?.message) ||
|
|
|
+ stringifyBusinessError(error?.response?.data?.title) ||
|
|
|
+ stringifyBusinessError(error?.response?.data?.detail);
|
|
|
+ if (responseMessage && !isRawTransportMessage(responseMessage)) {
|
|
|
+ return responseMessage;
|
|
|
+ }
|
|
|
+
|
|
|
+ const status = Number(error?.response?.status);
|
|
|
+ if (status === 400 || status === 422) {
|
|
|
+ return '客户保存失败,请检查公司、工厂和必填信息后重试。';
|
|
|
+ }
|
|
|
+
|
|
|
+ return '客户保存失败,请稍后重试。';
|
|
|
+}
|
|
|
+
|
|
|
+function buildPayload(): S0CustMasterUpsert | null {
|
|
|
+ if (!form.companyRefId || form.companyRefId <= 0 || !form.factoryRefId || form.factoryRefId <= 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...form,
|
|
|
+ companyRefId: form.companyRefId,
|
|
|
+ factoryRefId: form.factoryRefId,
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
watch(
|
|
|
() => form.companyRefId,
|
|
|
() => {
|
|
|
if (!formFactoryOptions.value.some((item) => item.id === form.factoryRefId)) {
|
|
|
- form.factoryRefId = 0;
|
|
|
+ form.factoryRefId = undefined;
|
|
|
+ form.domainCode = '';
|
|
|
}
|
|
|
}
|
|
|
);
|
|
|
@@ -311,8 +394,8 @@ async function loadOptions() {
|
|
|
loadOrgList('501'),
|
|
|
loadDictOptions('s0_currency'),
|
|
|
]);
|
|
|
- companyOptions.value = companies;
|
|
|
- factoryOptions.value = factories;
|
|
|
+ companyOptions.value = companies.filter((item) => item.id > 0);
|
|
|
+ factoryOptions.value = factories.filter((item) => item.id > 0);
|
|
|
currencyOptions.value = currencies;
|
|
|
|
|
|
if (!companies.length || !factories.length || !currencies.length) {
|
|
|
@@ -357,8 +440,8 @@ function resetQuery() {
|
|
|
function resetForm() {
|
|
|
editingId.value = null;
|
|
|
Object.assign(form, {
|
|
|
- companyRefId: 0,
|
|
|
- factoryRefId: 0,
|
|
|
+ companyRefId: undefined,
|
|
|
+ factoryRefId: undefined,
|
|
|
domainCode: '',
|
|
|
cust: '',
|
|
|
sortName: '',
|
|
|
@@ -423,19 +506,31 @@ function openEdit(row: S0CustMasterRow) {
|
|
|
}
|
|
|
|
|
|
async function submitForm() {
|
|
|
+ if (selectedCompanyHasNoFactories.value) {
|
|
|
+ ElMessage.warning('所选公司下暂无可用工厂,请先维护组织数据或机构权限。');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
await formRef.value?.validate();
|
|
|
saving.value = true;
|
|
|
try {
|
|
|
- const payload: S0CustMasterUpsert = { ...form };
|
|
|
+ const payload = buildPayload();
|
|
|
+ if (!payload) {
|
|
|
+ ElMessage.warning('请选择有效的公司和工厂后再保存。');
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (editingId.value) {
|
|
|
- await s0CustomersApi.update(editingId.value, payload);
|
|
|
+ await s0CustomersApi.update(editingId.value, payload, { headers: { 'X-Silent-Error': true } });
|
|
|
ElMessage.success('已保存');
|
|
|
} else {
|
|
|
- await s0CustomersApi.create(payload);
|
|
|
+ await s0CustomersApi.create(payload, { headers: { 'X-Silent-Error': true } });
|
|
|
ElMessage.success('已创建');
|
|
|
}
|
|
|
dialogVisible.value = false;
|
|
|
await loadList();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('[aidop/s0/sales/customer] save failed', error);
|
|
|
+ ElMessage.error(getCustomerSaveErrorMessage(error));
|
|
|
} finally {
|
|
|
saving.value = false;
|
|
|
}
|
|
|
@@ -483,4 +578,14 @@ onMounted(async () => {
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
}
|
|
|
+
|
|
|
+.form-help {
|
|
|
+ margin-top: -8px;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.form-help--warning {
|
|
|
+ color: var(--el-color-warning);
|
|
|
+}
|
|
|
</style>
|