|
|
@@ -259,7 +259,6 @@
|
|
|
</template>
|
|
|
<script>
|
|
|
import TuiListCell from "@/components/plugin/list-cell";
|
|
|
-const form = require("@/utils/formValidation.js");
|
|
|
import { getClass } from "@/api/category";
|
|
|
import { getGoodsDetail, updateGoodsData, createSn, useCaseList } from "@/api/goods";
|
|
|
import { delImages } from "@/api/pic-text";
|
|
|
@@ -603,50 +602,86 @@ export default {
|
|
|
spec.stock = status === '0' ? 9999 : '';
|
|
|
this.$set(this.form.specList, index, { ...spec });
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 校验单个数值字段。空值按 required 决定是否报错;exclusiveMin 时必须大于 min。
|
|
|
+ * @param {*} value 表单原始值
|
|
|
+ * @param {{label:string, required?:boolean, min?:number, exclusiveMin?:boolean}} options 校验配置
|
|
|
+ * @returns {string} 错误文案,空字符串表示通过
|
|
|
+ */
|
|
|
+ validateNumberField(value, options) {
|
|
|
+ const label = options.label;
|
|
|
+ const required = !!options.required;
|
|
|
+ const min = options.min !== undefined ? options.min : 0;
|
|
|
+ const exclusiveMin = !!options.exclusiveMin;
|
|
|
+ const isEmpty = value === '' || value === null || value === undefined;
|
|
|
+ if (isEmpty) {
|
|
|
+ return required ? `请输入${label}` : '';
|
|
|
+ }
|
|
|
+ const num = parseFloat(value);
|
|
|
+ if (isNaN(num)) {
|
|
|
+ return `${label}必须是数字`;
|
|
|
+ }
|
|
|
+ if (exclusiveMin && num <= min) {
|
|
|
+ return `${label}必须是大于${min}的数字`;
|
|
|
+ }
|
|
|
+ if (!exclusiveMin && num < min) {
|
|
|
+ return `${label}必须是大于等于${min}的数字`;
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 校验一组商品数值字段。单规格与规格组共用,避免两套规则不一致。
|
|
|
+ * 有价格时价格必填且 >0;自定义库存时库存必填且 >=0;花支数/重量/已售选填,填了必须 >=0。
|
|
|
+ * @param {Object} data 单规格 form 或某个规格组
|
|
|
+ * @param {string} prefix 错误文案前缀,如「规格组1」
|
|
|
+ * @returns {string} 第一条错误文案
|
|
|
+ */
|
|
|
+ validateGoodsNumberFields(data, prefix) {
|
|
|
+ prefix = prefix || '';
|
|
|
+ const withPrefix = (label) => prefix ? `${prefix}${label}` : label;
|
|
|
+ const rules = [];
|
|
|
+ if (String(data.priceType) === '1') {
|
|
|
+ rules.push({ key: 'price', label: withPrefix('价格'), required: true, min: 0, exclusiveMin: true });
|
|
|
+ }
|
|
|
+ if (String(data.stockSet) === '1') {
|
|
|
+ rules.push({ key: 'stock', label: withPrefix('库存数量'), required: true, min: 0 });
|
|
|
+ }
|
|
|
+ rules.push(
|
|
|
+ { key: 'flowerNum', label: withPrefix('花支数'), required: false, min: 0 },
|
|
|
+ { key: 'weight', label: withPrefix('重量'), required: false, min: 0 },
|
|
|
+ { key: 'sold', label: withPrefix('已售数量'), required: false, min: 0 }
|
|
|
+ );
|
|
|
+ for (let i = 0; i < rules.length; i++) {
|
|
|
+ const rule = rules[i];
|
|
|
+ const msg = this.validateNumberField(data[rule.key], rule);
|
|
|
+ if (msg) {
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 多规格开启时校验规格列表。返回错误文案,空字符串表示通过。
|
|
|
+ */
|
|
|
validateSpecList() {
|
|
|
- if (this.form.specEnabled != 1) return true;
|
|
|
+ if (this.form.specEnabled != 1) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
if (!this.form.specList.length) {
|
|
|
- this.$msg('请至少添加一个规格组');
|
|
|
- return false;
|
|
|
+ return '请至少添加一个规格组';
|
|
|
}
|
|
|
for (let i = 0; i < this.form.specList.length; i++) {
|
|
|
const spec = this.form.specList[i];
|
|
|
const name = `规格组${i + 1}`;
|
|
|
if (!spec.specName || !String(spec.specName).trim()) {
|
|
|
- this.$msg(`请输入${name}名称`);
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (String(spec.priceType) === '1') {
|
|
|
- const price = parseFloat(spec.price);
|
|
|
- if (spec.price === '' || isNaN(price) || price <= 0) {
|
|
|
- this.$msg(`${name}价格必须是大于0的数字`);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- if (String(spec.stockSet) === '1') {
|
|
|
- const stock = parseFloat(spec.stock);
|
|
|
- if (spec.stock === '' || isNaN(stock) || stock < 0) {
|
|
|
- this.$msg(`${name}库存数量必须是大于等于0的数字`);
|
|
|
- return false;
|
|
|
- }
|
|
|
+ return `请输入${name}名称`;
|
|
|
}
|
|
|
- const flowerNum = parseFloat(spec.flowerNum || 0);
|
|
|
- if (isNaN(flowerNum) || flowerNum < 0) {
|
|
|
- this.$msg(`${name}花支数必须是大于等于0的数字`);
|
|
|
- return false;
|
|
|
- }
|
|
|
- const weight = parseFloat(spec.weight);
|
|
|
- if (spec.weight === '' || isNaN(weight) || weight < 0) {
|
|
|
- this.$msg(`${name}重量必须是大于等于0的数字`);
|
|
|
- return false;
|
|
|
- }
|
|
|
- const sold = parseFloat(spec.sold || 0);
|
|
|
- if (isNaN(sold) || sold < 0) {
|
|
|
- this.$msg(`${name}已售数量必须是大于等于0的数字`);
|
|
|
- return false;
|
|
|
+ const numErr = this.validateGoodsNumberFields(spec, name);
|
|
|
+ if (numErr) {
|
|
|
+ return numErr;
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
+ return '';
|
|
|
},
|
|
|
normalizeSpecSubmitData(formData) {
|
|
|
if (formData.specEnabled != 1) {
|
|
|
@@ -678,78 +713,29 @@ export default {
|
|
|
formData.sold = firstSpec.sold;
|
|
|
return formData;
|
|
|
},
|
|
|
- formSubmit(e) {
|
|
|
-
|
|
|
- let rules = [
|
|
|
- {
|
|
|
- name: "name",
|
|
|
- rule: ["required"],
|
|
|
- msg: ["请输入名称"]
|
|
|
- }
|
|
|
- ];
|
|
|
-
|
|
|
- if (!this.validateSpecList()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 只有在有价格类型时才验证价格
|
|
|
- if (this.form.specEnabled != 1 && this.form.priceType === '1') {
|
|
|
- rules.push({
|
|
|
- name: "price",
|
|
|
- rule: ["required"],
|
|
|
- msg: ["请输入价格"]
|
|
|
- });
|
|
|
-
|
|
|
- // 检查价格是否为有效数字且大于0
|
|
|
- if (this.form.price !== "" && (isNaN(parseFloat(this.form.price)) || parseFloat(this.form.price) <= 0)) {
|
|
|
- this.$msg('价格必须是大于0的数字!');
|
|
|
- return false;
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 提交前统一校验。用 this.form,避免原生 form 取值漏掉无 name 的规格字段。
|
|
|
+ * @returns {string} 第一条错误文案,空字符串表示通过
|
|
|
+ */
|
|
|
+ getFormValidateError() {
|
|
|
+ if (!this.form.name || !String(this.form.name).trim()) {
|
|
|
+ return '请输入名称';
|
|
|
}
|
|
|
-
|
|
|
- // 验证库存数量
|
|
|
- if (this.form.specEnabled != 1 && this.form.stockSet === '1' && this.form.stock !== "") {
|
|
|
- const stockNum = parseFloat(this.form.stock);
|
|
|
- if (isNaN(stockNum) || stockNum < 0) {
|
|
|
- this.$msg('库存数量必须是大于等于0的数字!');
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 验证已售数量
|
|
|
- if (this.form.specEnabled != 1 && this.form.sold !== "") {
|
|
|
- const soldNum = parseFloat(this.form.sold);
|
|
|
- if (isNaN(soldNum) || soldNum < 0) {
|
|
|
- this.$msg('已售数量必须是大于等于0的数字!');
|
|
|
- return false;
|
|
|
- }
|
|
|
+ if (this.form.specEnabled == 1) {
|
|
|
+ return this.validateSpecList();
|
|
|
}
|
|
|
-
|
|
|
- // 验证花支数
|
|
|
- if (this.form.specEnabled != 1 && this.form.flowerNum !== "" && this.form.flowerNum !== 0) {
|
|
|
- const flowerNum = parseFloat(this.form.flowerNum);
|
|
|
- if (isNaN(flowerNum) || flowerNum < 0) {
|
|
|
- this.$msg('花支数必须是大于0的数字!');
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 验证重量(千克)
|
|
|
- if (this.form.specEnabled != 1 && this.form.weight !== "") {
|
|
|
- const weightNum = parseFloat(this.form.weight);
|
|
|
- if (isNaN(weightNum) || weightNum < 0) {
|
|
|
- this.$msg('重量必须是大于等于0的数字!');
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let formData = e.detail.value;
|
|
|
- let checkRes = form.validation(formData, rules);
|
|
|
- if (!checkRes) {
|
|
|
- this.confirmFn();
|
|
|
- } else {
|
|
|
- this.$msg(checkRes);
|
|
|
+ return this.validateGoodsNumberFields(this.form, '');
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 表单提交入口。先校验再走确认保存,校验失败只提示第一条错误。
|
|
|
+ */
|
|
|
+ formSubmit() {
|
|
|
+ const err = this.getFormValidateError();
|
|
|
+ if (err) {
|
|
|
+ this.$msg(err);
|
|
|
+ return false;
|
|
|
}
|
|
|
+ this.confirmFn();
|
|
|
},
|
|
|
confirmFn() {
|
|
|
if (this.form.categoryIdList == 0) {
|