新增库存生成功能,支持明细模式和批次模式两种存储模式,在SKU管理中实现动态表单字段的库存操作,同时在资产编辑中为租户ID为1的用户新增存储模式选择功能
This commit is contained in:
@@ -163,3 +163,31 @@ export function getSpecsUnitOptions(assetType: string) {
|
||||
params: { assetType },
|
||||
});
|
||||
}
|
||||
|
||||
// 获取库存表单字段
|
||||
export function getStockFormFields(assetSkuId: string) {
|
||||
return newService({
|
||||
url: '/assets/stock/manage/getStockFormFields',
|
||||
method: 'get',
|
||||
params: { assetSkuId },
|
||||
});
|
||||
}
|
||||
|
||||
// 库存操作
|
||||
export interface StockOperationParams {
|
||||
assetSkuId: string;
|
||||
stock?: number;
|
||||
batchNo?: string;
|
||||
productionDate?: string;
|
||||
expiryDate?: string;
|
||||
expiryWarningDate?: string;
|
||||
[key: string]: any; // 支持动态字段
|
||||
}
|
||||
|
||||
export function stockOperation(data: StockOperationParams) {
|
||||
return newService({
|
||||
url: '/assets/stock/manage/stockOperation',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,6 +70,14 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" v-if="tenantId === '1'">
|
||||
<el-form-item label="存储模式">
|
||||
<el-radio-group v-model="ruleForm.stockMode" :disabled="isEdit">
|
||||
<el-radio :value="1">明细模式</el-radio>
|
||||
<el-radio :value="2">批次模式</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 分类属性值选择 -->
|
||||
@@ -454,6 +462,7 @@ import { Plus, Delete } from '@element-plus/icons-vue';
|
||||
import { getAsset, createAsset, updateAsset, uploadAssetImage } from '/@/api/assets/asset';
|
||||
import { getCategoryTree, getCategory } from '/@/api/assets/category';
|
||||
import { createFormDiff } from '/@/utils/diffUtils';
|
||||
import { Session } from '/@/utils/storage';
|
||||
import Editor from '/@/components/editor/index.vue';
|
||||
import type { UploadFile, UploadUserFile, UploadRequestOptions } from 'element-plus';
|
||||
|
||||
@@ -495,6 +504,7 @@ interface RuleForm {
|
||||
onlineTime: string;
|
||||
offlineTime: string;
|
||||
unlimitedStock: boolean;
|
||||
stockMode: number;
|
||||
physicalAssetConfig: {
|
||||
shipping: {
|
||||
deliveryMethod: string;
|
||||
@@ -568,6 +578,9 @@ const fileAddressPrefix = ref('');
|
||||
// 使用通用工具函数保存原始数据,用于最小化传参
|
||||
const assetFormDiff = createFormDiff<Record<string, any>>();
|
||||
|
||||
// 获取租户ID
|
||||
const tenantId = ref(Session.get('userInfo')?.tenantId || '');
|
||||
|
||||
const formatImageUrl = (url?: string) => {
|
||||
if (!url) return '';
|
||||
if (/^https?:\/\//i.test(url)) return url;
|
||||
@@ -598,6 +611,7 @@ const getInitialForm = (): RuleForm => ({
|
||||
onlineTime: '',
|
||||
offlineTime: '',
|
||||
unlimitedStock: false,
|
||||
stockMode: 1,
|
||||
physicalAssetConfig: {
|
||||
shipping: {
|
||||
deliveryMethod: 'express',
|
||||
@@ -903,6 +917,7 @@ const openDialog = (row?: any, edit?: boolean) => {
|
||||
ruleForm.onlineTime = data.onlineTime || '';
|
||||
ruleForm.offlineTime = data.offlineTime || '';
|
||||
ruleForm.unlimitedStock = data.unlimitedStock || false;
|
||||
ruleForm.stockMode = data.stockMode || 1;
|
||||
|
||||
// 主图预览 (支持 imageUrl 和 fileURL)
|
||||
const mainImg = data.imageUrl || data.fileURL;
|
||||
@@ -1110,6 +1125,11 @@ const buildRequestBody = async (): Promise<any> => {
|
||||
// 库存类型
|
||||
body.unlimitedStock = ruleForm.unlimitedStock;
|
||||
|
||||
// 库存存储模式(仅租户ID为1时提交)
|
||||
if (tenantId.value === '1') {
|
||||
body.stockMode = ruleForm.stockMode;
|
||||
}
|
||||
|
||||
// 主图 (已在上传时直接赋值给 ruleForm.mainImage)
|
||||
if (ruleForm.mainImage) {
|
||||
body.imageURL = ruleForm.mainImage;
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
<el-table-column label="操作" width="180" align="center">
|
||||
<template #default="scope">
|
||||
<el-button size="small" text type="primary" @click="onEditSku(scope.row)">编辑</el-button>
|
||||
<el-button v-if="scope.row.unlimitedStock" size="small" text type="success" @click="onGenerateStock(scope.row)">生成库存</el-button>
|
||||
<el-button v-if="!scope.row.unlimitedStock" size="small" text type="success" @click="onGenerateStock(scope.row)">生成库存</el-button>
|
||||
<el-button size="small" text type="danger" @click="onDeleteSku(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -163,6 +163,50 @@
|
||||
<el-button type="primary" :loading="submitLoading" @click="onSubmitSku">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 生成库存弹窗 -->
|
||||
<el-dialog v-model="stockFormVisible" title="生成库存" width="450px" :close-on-click-modal="false" append-to-body>
|
||||
<el-form ref="stockFormRef" :model="stockForm" :rules="getStockFormRules()" label-width="100px" v-loading="stockFormLoading">
|
||||
<el-form-item label="SKU名称">
|
||||
<el-input :model-value="currentSkuName" disabled />
|
||||
</el-form-item>
|
||||
<template v-for="field in stockFormFields" :key="field.name">
|
||||
<el-form-item :label="field.label" :prop="field.name">
|
||||
<!-- 数字类型 -->
|
||||
<el-input-number
|
||||
v-if="field.type === 'number'"
|
||||
v-model="stockForm[field.name]"
|
||||
:min="field.min"
|
||||
:max="field.max"
|
||||
controls-position="right"
|
||||
style="width: 200px"
|
||||
/>
|
||||
<!-- 日期类型 -->
|
||||
<el-date-picker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="stockForm[field.name]"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 200px"
|
||||
/>
|
||||
<!-- 文本类型 -->
|
||||
<el-input
|
||||
v-else
|
||||
v-model="stockForm[field.name]"
|
||||
:maxlength="field.maxLength"
|
||||
placeholder="请输入"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="stockFormVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="stockSubmitLoading" @click="onSubmitStock">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -170,7 +214,7 @@
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { listAssetSkus, createAssetSku, updateAssetSku, deleteAssetSku, getAssetSku, getAsset, uploadAssetImage, getSpecsUnitOptions } from '/@/api/assets/asset';
|
||||
import { listAssetSkus, createAssetSku, updateAssetSku, deleteAssetSku, getAssetSku, getAsset, uploadAssetImage, getSpecsUnitOptions, getStockFormFields, stockOperation } from '/@/api/assets/asset';
|
||||
import { createFormDiff } from '/@/utils/diffUtils';
|
||||
import type { UploadRequestOptions, UploadUserFile } from 'element-plus';
|
||||
|
||||
@@ -185,6 +229,18 @@ interface AssetSpecAttr {
|
||||
dictType?: string;
|
||||
}
|
||||
|
||||
// 库存表单字段接口
|
||||
interface StockFormField {
|
||||
name: string;
|
||||
label: string;
|
||||
type: string;
|
||||
required?: boolean;
|
||||
min?: number;
|
||||
max?: number;
|
||||
maxLength?: number;
|
||||
default?: string | number;
|
||||
}
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const submitLoading = ref(false);
|
||||
@@ -193,6 +249,16 @@ const skuFormVisible = ref(false);
|
||||
const isEditSku = ref(false);
|
||||
const editSkuId = ref('');
|
||||
|
||||
// 库存弹窗相关
|
||||
const stockFormVisible = ref(false);
|
||||
const stockFormLoading = ref(false);
|
||||
const stockSubmitLoading = ref(false);
|
||||
const stockFormFields = ref<StockFormField[]>([]);
|
||||
const stockFormRef = ref<FormInstance>();
|
||||
const stockForm = reactive<Record<string, any>>({});
|
||||
const currentSkuId = ref('');
|
||||
const currentSkuName = ref('');
|
||||
|
||||
const assetId = ref('');
|
||||
const assetName = ref('');
|
||||
const assetType = ref('');
|
||||
@@ -479,9 +545,82 @@ const onDeleteSku = (row: any) => {
|
||||
};
|
||||
|
||||
// 生成库存
|
||||
const onGenerateStock = (row: any) => {
|
||||
// TODO: 实现生成库存功能
|
||||
ElMessage.info(`生成库存功能待实现,SKU: ${row.skuName}`);
|
||||
const onGenerateStock = async (row: any) => {
|
||||
currentSkuId.value = row.id;
|
||||
currentSkuName.value = row.skuName;
|
||||
stockFormVisible.value = true;
|
||||
stockFormLoading.value = true;
|
||||
|
||||
// 重置表单
|
||||
Object.keys(stockForm).forEach((key) => delete stockForm[key]);
|
||||
|
||||
try {
|
||||
const res = await getStockFormFields(row.id);
|
||||
stockFormFields.value = res.data.fields || [];
|
||||
|
||||
// 设置默认值
|
||||
stockFormFields.value.forEach((field) => {
|
||||
if (field.default !== undefined) {
|
||||
stockForm[field.name] = field.default;
|
||||
} else if (field.type === 'number') {
|
||||
stockForm[field.name] = field.min || 0;
|
||||
} else {
|
||||
stockForm[field.name] = '';
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取库存表单字段失败:', error);
|
||||
ElMessage.error('获取库存表单字段失败');
|
||||
stockFormVisible.value = false;
|
||||
} finally {
|
||||
stockFormLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 提交库存操作
|
||||
const onSubmitStock = async () => {
|
||||
const form = stockFormRef.value;
|
||||
if (!form) return;
|
||||
|
||||
form.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
stockSubmitLoading.value = true;
|
||||
try {
|
||||
await stockOperation({
|
||||
assetSkuId: currentSkuId.value,
|
||||
...stockForm,
|
||||
});
|
||||
ElMessage.success('库存生成成功');
|
||||
stockFormVisible.value = false;
|
||||
getSkuList();
|
||||
} catch (error) {
|
||||
console.error('库存操作失败:', error);
|
||||
} finally {
|
||||
stockSubmitLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 生成库存表单验证规则
|
||||
const getStockFormRules = () => {
|
||||
const rules: Record<string, any[]> = {};
|
||||
stockFormFields.value.forEach((field) => {
|
||||
const fieldRules: any[] = [];
|
||||
if (field.required) {
|
||||
fieldRules.push({ required: true, message: `${field.label}不能为空`, trigger: 'blur' });
|
||||
}
|
||||
if (field.type === 'number' && field.min !== undefined) {
|
||||
fieldRules.push({ type: 'number', min: field.min, message: `${field.label}最小值为${field.min}`, trigger: 'blur' });
|
||||
}
|
||||
if (field.maxLength) {
|
||||
fieldRules.push({ max: field.maxLength, message: `${field.label}最大长度为${field.maxLength}`, trigger: 'blur' });
|
||||
}
|
||||
if (fieldRules.length > 0) {
|
||||
rules[field.name] = fieldRules;
|
||||
}
|
||||
});
|
||||
return rules;
|
||||
};
|
||||
|
||||
// 重置 SKU 表单
|
||||
|
||||
Reference in New Issue
Block a user