commit
9cac5a2937
|
|
@ -91,6 +91,7 @@ async function handleBatchDelete() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deletePurchaseOrderList(checkedIds.value);
|
await deletePurchaseOrderList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success({
|
message.success({
|
||||||
content: $t('ui.actionMessage.deleteSuccess'),
|
content: $t('ui.actionMessage.deleteSuccess'),
|
||||||
key: 'action_process_msg',
|
key: 'action_process_msg',
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteCodegenTableList(checkedIds.value);
|
await deleteCodegenTableList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteConfigList(checkedIds.value);
|
await deleteConfigList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo01ContactList(checkedIds.value);
|
await deleteDemo01ContactList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03CourseList(checkedIds.value);
|
await deleteDemo03CourseList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03GradeList(checkedIds.value);
|
await deleteDemo03GradeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo01ContactList(checkedIds.value);
|
await deleteDemo01ContactList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03CourseList(checkedIds.value);
|
await deleteDemo03CourseList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03GradeList(checkedIds.value);
|
await deleteDemo03GradeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteFileList(checkedIds.value);
|
await deleteFileList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteFileConfigList(checkedIds.value);
|
await deleteFileConfigList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteJobList(checkedIds.value);
|
await deleteJobList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDeptList(checkedIds.value);
|
await deleteDeptList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDictDataList(checkedIds.value);
|
await deleteDictDataList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDictTypeList(checkedIds.value);
|
await deleteDictTypeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteMailAccountList(checkedIds.value);
|
await deleteMailAccountList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteMailTemplateList(checkedIds.value);
|
await deleteMailTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteNoticeList(checkedIds.value);
|
await deleteNoticeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteNotifyTemplateList(checkedIds.value);
|
await deleteNotifyTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deletePostList(checkedIds.value);
|
await deletePostList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteRoleList(checkedIds.value);
|
await deleteRoleList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteSmsChannelList(checkedIds.value);
|
await deleteSmsChannelList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success({
|
message.success({
|
||||||
content: $t('ui.actionMessage.deleteSuccess', ['短信渠道']),
|
content: $t('ui.actionMessage.deleteSuccess', ['短信渠道']),
|
||||||
key: 'action_key_msg',
|
key: 'action_key_msg',
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteSmsTemplateList(checkedIds.value);
|
await deleteSmsTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteTenantList(checkedIds.value);
|
await deleteTenantList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteTenantPackageList(checkedIds.value);
|
await deleteTenantPackageList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteUserList(checkedIds.value);
|
await deleteUserList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ async function onDelete(row: InfraCodegenApi.CodegenTable) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该代码生成配置吗?');
|
await confirm('确定要批量删除该代码生成配置吗?');
|
||||||
await deleteCodegenTableList(checkedIds.value);
|
await deleteCodegenTableList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function onDelete(row: InfraConfigApi.Config) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该参数吗?');
|
await confirm('确定要批量删除该参数吗?');
|
||||||
await deleteConfigList(checkedIds.value);
|
await deleteConfigList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ async function onDelete(row: InfraDataSourceConfigApi.DataSourceConfig) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该数据源吗?');
|
await confirm('确定要批量删除该数据源吗?');
|
||||||
await deleteDataSourceConfigList(checkedIds.value);
|
await deleteDataSourceConfigList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo01ContactList(checkedIds.value);
|
await deleteDemo01ContactList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03CourseList(checkedIds.value);
|
await deleteDemo03CourseList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03GradeList(checkedIds.value);
|
await deleteDemo03GradeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo01ContactList(checkedIds.value);
|
await deleteDemo01ContactList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03CourseList(checkedIds.value);
|
await deleteDemo03CourseList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03GradeList(checkedIds.value);
|
await deleteDemo03GradeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ async function handleDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDemo03StudentList(checkedIds.value);
|
await deleteDemo03StudentList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
await getList();
|
await getList();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ async function onDelete(row: InfraFileApi.File) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该文件吗?');
|
await confirm('确定要批量删除该文件吗?');
|
||||||
await deleteFileList(checkedIds.value);
|
await deleteFileList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ async function onDelete(row: InfraFileConfigApi.FileConfig) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该文件配置吗?');
|
await confirm('确定要批量删除该文件配置吗?');
|
||||||
await deleteFileConfigList(checkedIds.value);
|
await deleteFileConfigList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ async function onDelete(row: InfraJobApi.Job) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该任务吗?');
|
await confirm('确定要批量删除该任务吗?');
|
||||||
await deleteJobList(checkedIds.value);
|
await deleteJobList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
|
||||||
import type { PropertyAndValues } from './model';
|
import type { PropertyAndValues } from './model';
|
||||||
|
|
||||||
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得商品的规格列表 - 商品相关的公共函数
|
* 获得商品的规格列表 - 商品相关的公共函数
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useVbenForm } from '#/adapter/form';
|
|
||||||
import * as ExpressTemplateApi from '#/api/mall/trade/delivery/expressTemplate';
|
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { DICT_TYPE, getIntDictOptions, DeliveryTypeEnum } from '#/utils';
|
|
||||||
|
import { useVbenForm } from '#/adapter/form';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
propFormData: Object;
|
propFormData: Object;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:activeName']);
|
||||||
|
|
||||||
/** 将传进来的值赋值给 formData */
|
/** 将传进来的值赋值给 formData */
|
||||||
watch(
|
watch(
|
||||||
() => props.propFormData,
|
() => props.propFormData,
|
||||||
|
|
@ -20,7 +22,6 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(['update:activeName']);
|
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
@ -29,10 +30,10 @@ const validate = async () => {
|
||||||
try {
|
try {
|
||||||
// 校验通过更新数据
|
// 校验通过更新数据
|
||||||
Object.assign(props.propFormData, formApi.getValues());
|
Object.assign(props.propFormData, formApi.getValues());
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
ElMessage.error('【商品详情】不完善,请填写相关信息');
|
ElMessage.error('【商品详情】不完善,请填写相关信息');
|
||||||
emit('update:activeName', 'description');
|
emit('update:activeName', 'description');
|
||||||
throw e; // 目的截断之后的校验
|
throw error; // 目的截断之后的校验
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
defineExpose({ validate });
|
defineExpose({ validate });
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import SkuList from './SkuList.vue';
|
|
||||||
|
|
||||||
interface PropertyAndValues {
|
interface PropertyAndValues {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -22,4 +20,6 @@ interface RuleConfig {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { SkuList, PropertyAndValues, RuleConfig, getPropertyList };
|
export { getPropertyList, PropertyAndValues, RuleConfig };
|
||||||
|
|
||||||
|
export { default as SkuList } from './SkuList.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useVbenForm } from '#/adapter/form';
|
|
||||||
import * as ExpressTemplateApi from '#/api/mall/trade/delivery/expressTemplate';
|
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { DICT_TYPE, getIntDictOptions, DeliveryTypeEnum } from '#/utils';
|
|
||||||
|
import { useVbenForm } from '#/adapter/form';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
propFormData: Object;
|
propFormData: Object;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:activeName']);
|
||||||
|
|
||||||
/** 将传进来的值赋值给 formData */
|
/** 将传进来的值赋值给 formData */
|
||||||
watch(
|
watch(
|
||||||
() => props.propFormData,
|
() => props.propFormData,
|
||||||
|
|
@ -20,7 +22,6 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(['update:activeName']);
|
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
@ -29,10 +30,10 @@ const validate = async () => {
|
||||||
try {
|
try {
|
||||||
// 校验通过更新数据
|
// 校验通过更新数据
|
||||||
Object.assign(props.propFormData, formApi.getValues());
|
Object.assign(props.propFormData, formApi.getValues());
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
ElMessage.error('【其它设置】不完善,请填写相关信息');
|
ElMessage.error('【其它设置】不完善,请填写相关信息');
|
||||||
emit('update:activeName', 'other');
|
emit('update:activeName', 'other');
|
||||||
throw e; // 目的截断之后的校验
|
throw error; // 目的截断之后的校验
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
defineExpose({ validate });
|
defineExpose({ validate });
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,149 @@
|
||||||
<!-- 商品发布 - 库存价格 - 属性列表 -->
|
<!-- 商品发布 - 库存价格 - 属性列表 -->
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
|
import type { PropertyAndValues } from './model';
|
||||||
|
|
||||||
|
import type { MallPropertyApi } from '#/api/mall/product/property';
|
||||||
|
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElCol,
|
||||||
|
ElDivider,
|
||||||
|
ElMessage,
|
||||||
|
ElSpace,
|
||||||
|
ElTag,
|
||||||
|
ElText,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
|
import * as PropertyApi from '#/api/mall/product/property';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ProductAttributes' });
|
||||||
|
|
||||||
|
// 商品属性名称下拉框
|
||||||
|
const props = defineProps({
|
||||||
|
propertyList: {
|
||||||
|
type: Array as PropType<PropertyAndValues[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
}); /** 输入框失去焦点或点击回车时触发 */
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
const inputValue = ref(''); // 输入框值
|
||||||
|
const attributeIndex = ref<null | number>(null); // 获取焦点时记录当前属性项的index
|
||||||
|
// 输入框显隐控制
|
||||||
|
const inputVisible = computed(() => (index: number) => {
|
||||||
|
if (attributeIndex.value === null) return false;
|
||||||
|
if (attributeIndex.value === index) return true;
|
||||||
|
});
|
||||||
|
const inputRef = ref<any[]>([]); // 标签输入框Ref
|
||||||
|
/** 解决 ref 在 v-for 中的获取问题*/
|
||||||
|
const setInputRef = (el: any) => {
|
||||||
|
if (el === null || el === undefined) return;
|
||||||
|
// 如果不存在 id 相同的元素才添加
|
||||||
|
if (
|
||||||
|
!inputRef.value.some(
|
||||||
|
(item) => item.inputRef?.attributes.id === el.inputRef?.attributes.id,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
inputRef.value.push(el);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const attributeList = ref<PropertyAndValues[]>([]); // 商品属性列表
|
||||||
|
const attributeOptions = ref([] as MallPropertyApi.PropertyValue[]);
|
||||||
|
watch(
|
||||||
|
() => props.propertyList,
|
||||||
|
(data) => {
|
||||||
|
if (!data) return;
|
||||||
|
attributeList.value = data as any;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 删除属性值*/
|
||||||
|
const handleCloseValue = (index: number, valueIndex: number) => {
|
||||||
|
if (index < attributeList.value.length) {
|
||||||
|
const values = attributeList.value[index]!.values as any[];
|
||||||
|
values.splice(valueIndex, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除属性*/
|
||||||
|
const handleCloseProperty = (index: number) => {
|
||||||
|
if (index < attributeList.value.length) {
|
||||||
|
attributeList.value.splice(index, 1);
|
||||||
|
emit('success', attributeList.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 显示输入框并获取焦点 */
|
||||||
|
const showInput = async (index: number) => {
|
||||||
|
if (index < attributeList.value.length) {
|
||||||
|
attributeIndex.value = index;
|
||||||
|
inputRef.value[index].focus();
|
||||||
|
// 获取属性下拉选项
|
||||||
|
await getAttributeOptions(attributeList.value[index]!.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 定义 success 事件,用于操作成功后的回调
|
||||||
|
const handleInputConfirm = async (index: number, propertyId: number) => {
|
||||||
|
if (inputValue.value && index < attributeList.value.length) {
|
||||||
|
// 1. 重复添加校验
|
||||||
|
const values = attributeList.value[index]!.values as any[];
|
||||||
|
if (values.find((item) => item.name === inputValue.value)) {
|
||||||
|
ElMessage.warning('已存在相同属性值,请重试');
|
||||||
|
attributeIndex.value = null;
|
||||||
|
inputValue.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.1 情况一:属性值已存在,则直接使用并结束
|
||||||
|
const existValue = attributeOptions.value.find(
|
||||||
|
(item) => item.name === inputValue.value,
|
||||||
|
);
|
||||||
|
if (existValue) {
|
||||||
|
attributeIndex.value = null;
|
||||||
|
inputValue.value = '';
|
||||||
|
const values = attributeList.value[index]!.values as any[];
|
||||||
|
values.push({
|
||||||
|
id: existValue.id!,
|
||||||
|
name: existValue.name,
|
||||||
|
});
|
||||||
|
emit('success', attributeList.value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.2 情况二:新属性值,则进行保存
|
||||||
|
try {
|
||||||
|
const id = await PropertyApi.createPropertyValue({
|
||||||
|
propertyId,
|
||||||
|
name: inputValue.value,
|
||||||
|
});
|
||||||
|
const values = attributeList.value[index]!.values as any[];
|
||||||
|
values.push({ id, name: inputValue.value });
|
||||||
|
ElMessage.success($t('common.createSuccess'));
|
||||||
|
emit('success', attributeList.value);
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('添加失败,请重试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attributeIndex.value = null;
|
||||||
|
inputValue.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取商品属性下拉选项 */
|
||||||
|
const getAttributeOptions = async (propertyId: number) => {
|
||||||
|
attributeOptions.value =
|
||||||
|
await PropertyApi.getPropertyValueSimpleList(propertyId);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElCol v-for="(item, index) in attributeList" :key="index">
|
<ElCol v-for="(item, index) in attributeList" :key="index">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -53,144 +198,3 @@
|
||||||
<ElDivider class="my-10px" />
|
<ElDivider class="my-10px" />
|
||||||
</ElCol>
|
</ElCol>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, watch, computed } from 'vue';
|
|
||||||
import type { PropType } from 'vue';
|
|
||||||
|
|
||||||
import * as PropertyApi from '#/api/mall/product/property';
|
|
||||||
import type { MallPropertyApi } from '#/api/mall/product/property';
|
|
||||||
import {
|
|
||||||
ElMessage,
|
|
||||||
ElCol,
|
|
||||||
ElTag,
|
|
||||||
ElText,
|
|
||||||
ElButton,
|
|
||||||
ElDivider,
|
|
||||||
ElSpace,
|
|
||||||
} from 'element-plus';
|
|
||||||
import { $t } from '#/locales';
|
|
||||||
import type { PropertyAndValues } from './model';
|
|
||||||
|
|
||||||
defineOptions({ name: 'ProductAttributes' });
|
|
||||||
|
|
||||||
const inputValue = ref(''); // 输入框值
|
|
||||||
const attributeIndex = ref<number | null>(null); // 获取焦点时记录当前属性项的index
|
|
||||||
// 输入框显隐控制
|
|
||||||
const inputVisible = computed(() => (index: number) => {
|
|
||||||
if (attributeIndex.value === null) return false;
|
|
||||||
if (attributeIndex.value === index) return true;
|
|
||||||
});
|
|
||||||
const inputRef = ref<any[]>([]); //标签输入框Ref
|
|
||||||
/** 解决 ref 在 v-for 中的获取问题*/
|
|
||||||
const setInputRef = (el: any) => {
|
|
||||||
if (el === null || typeof el === 'undefined') return;
|
|
||||||
// 如果不存在 id 相同的元素才添加
|
|
||||||
if (
|
|
||||||
!inputRef.value.some(
|
|
||||||
(item) => item.inputRef?.attributes.id === el.inputRef?.attributes.id,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
inputRef.value.push(el);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const attributeList = ref<PropertyAndValues[]>([]); // 商品属性列表
|
|
||||||
const attributeOptions = ref([] as MallPropertyApi.PropertyValue[]); // 商品属性名称下拉框
|
|
||||||
const props = defineProps({
|
|
||||||
propertyList: {
|
|
||||||
type: Array as PropType<PropertyAndValues[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.propertyList,
|
|
||||||
(data) => {
|
|
||||||
if (!data) return;
|
|
||||||
attributeList.value = data as any;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true,
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/** 删除属性值*/
|
|
||||||
const handleCloseValue = (index: number, valueIndex: number) => {
|
|
||||||
if (index < attributeList.value.length) {
|
|
||||||
const values = attributeList.value[index]!.values as any[];
|
|
||||||
values.splice(valueIndex, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 删除属性*/
|
|
||||||
const handleCloseProperty = (index: number) => {
|
|
||||||
if (index < attributeList.value.length) {
|
|
||||||
attributeList.value.splice(index, 1);
|
|
||||||
emit('success', attributeList.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 显示输入框并获取焦点 */
|
|
||||||
const showInput = async (index: number) => {
|
|
||||||
if (index < attributeList.value.length) {
|
|
||||||
attributeIndex.value = index;
|
|
||||||
inputRef.value[index].focus();
|
|
||||||
// 获取属性下拉选项
|
|
||||||
await getAttributeOptions(attributeList.value[index]!.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 输入框失去焦点或点击回车时触发 */
|
|
||||||
const emit = defineEmits(['success']); // 定义 success 事件,用于操作成功后的回调
|
|
||||||
const handleInputConfirm = async (index: number, propertyId: number) => {
|
|
||||||
if (inputValue.value && index < attributeList.value.length) {
|
|
||||||
// 1. 重复添加校验
|
|
||||||
const values = attributeList.value[index]!.values as any[];
|
|
||||||
if (values.find((item) => item.name === inputValue.value)) {
|
|
||||||
ElMessage.warning('已存在相同属性值,请重试');
|
|
||||||
attributeIndex.value = null;
|
|
||||||
inputValue.value = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.1 情况一:属性值已存在,则直接使用并结束
|
|
||||||
const existValue = attributeOptions.value.find(
|
|
||||||
(item) => item.name === inputValue.value,
|
|
||||||
);
|
|
||||||
if (existValue) {
|
|
||||||
attributeIndex.value = null;
|
|
||||||
inputValue.value = '';
|
|
||||||
const values = attributeList.value[index]!.values as any[];
|
|
||||||
values.push({
|
|
||||||
id: existValue.id!,
|
|
||||||
name: existValue.name,
|
|
||||||
});
|
|
||||||
emit('success', attributeList.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.2 情况二:新属性值,则进行保存
|
|
||||||
try {
|
|
||||||
const id = await PropertyApi.createPropertyValue({
|
|
||||||
propertyId,
|
|
||||||
name: inputValue.value,
|
|
||||||
});
|
|
||||||
const values = attributeList.value[index]!.values as any[];
|
|
||||||
values.push({ id, name: inputValue.value });
|
|
||||||
ElMessage.success($t('common.createSuccess'));
|
|
||||||
emit('success', attributeList.value);
|
|
||||||
} catch {
|
|
||||||
ElMessage.error('添加失败,请重试');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attributeIndex.value = null;
|
|
||||||
inputValue.value = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 获取商品属性下拉选项 */
|
|
||||||
const getAttributeOptions = async (propertyId: number) => {
|
|
||||||
attributeOptions.value =
|
|
||||||
await PropertyApi.getPropertyValueSimpleList(propertyId);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,25 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
|
import type { MallPropertyApi } from '#/api/mall/product/property';
|
||||||
|
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import { $t } from '#/locales';
|
|
||||||
import { getPropertySimpleList } from '#/api/mall/product/property';
|
import { getPropertySimpleList } from '#/api/mall/product/property';
|
||||||
import * as PropertyApi from '#/api/mall/product/property';
|
import * as PropertyApi from '#/api/mall/product/property';
|
||||||
import type { MallPropertyApi } from '#/api/mall/product/property';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
// 扩展Property接口,添加values属性
|
// 扩展Property接口,添加values属性
|
||||||
interface ExtendedProperty extends MallPropertyApi.Property {
|
interface ExtendedProperty extends MallPropertyApi.Property {
|
||||||
values?: any[];
|
values?: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['success']);
|
// 商品属性名称下拉框
|
||||||
|
|
||||||
const attributeList = ref<ExtendedProperty[]>([]); // 商品属性列表
|
|
||||||
const attributeOptions = ref([] as MallPropertyApi.Property[]); // 商品属性名称下拉框
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
propertyList: {
|
propertyList: {
|
||||||
|
|
@ -29,6 +28,10 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
|
||||||
|
const attributeList = ref<ExtendedProperty[]>([]); // 商品属性列表
|
||||||
|
const attributeOptions = ref([] as MallPropertyApi.Property[]);
|
||||||
const [Form, formApi] = useVbenForm({
|
const [Form, formApi] = useVbenForm({
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { ref, watch } from 'vue';
|
||||||
import { watch, ref } from 'vue';
|
|
||||||
import { ElMessage, ElSpace } from 'element-plus';
|
|
||||||
import SkuList from './sku-list.vue';
|
|
||||||
import { Page, useVbenModal } from '@vben/common-ui';
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
import ProductPropertyAddForm from './product-property-add-form.vue';
|
|
||||||
|
import { ElMessage, ElSpace } from 'element-plus';
|
||||||
|
|
||||||
|
import { useVbenForm } from '#/adapter/form';
|
||||||
|
|
||||||
import { getPropertyList } from './data';
|
import { getPropertyList } from './data';
|
||||||
import ProductAttributes from './product-attributes.vue';
|
import ProductAttributes from './product-attributes.vue';
|
||||||
|
import ProductPropertyAddForm from './product-property-add-form.vue';
|
||||||
|
import SkuList from './sku-list.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
propFormData: Object;
|
propFormData: Object;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:activeName']);
|
||||||
|
|
||||||
interface PropertyAndValues {
|
interface PropertyAndValues {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -71,7 +77,6 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(['update:activeName']);
|
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
@ -80,10 +85,10 @@ const validate = async () => {
|
||||||
try {
|
try {
|
||||||
// 校验通过更新数据
|
// 校验通过更新数据
|
||||||
Object.assign(props.propFormData, formApi.getValues());
|
Object.assign(props.propFormData, formApi.getValues());
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
ElMessage.error('【库存价格】不完善,请填写相关信息');
|
ElMessage.error('【库存价格】不完善,请填写相关信息');
|
||||||
emit('update:activeName', 'sku');
|
emit('update:activeName', 'sku');
|
||||||
throw e; // 目的截断之后的校验
|
throw error; // 目的截断之后的校验
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
defineExpose({ validate });
|
defineExpose({ validate });
|
||||||
|
|
@ -214,9 +219,9 @@ watch(
|
||||||
</template>
|
</template>
|
||||||
<template #specTypeItem>
|
<template #specTypeItem>
|
||||||
<ElSpace direction="vertical" alignment="flex-start">
|
<ElSpace direction="vertical" alignment="flex-start">
|
||||||
<ElButton type="primary" @click="productPropertyAddFormApi.open()"
|
<ElButton type="primary" @click="productPropertyAddFormApi.open()">
|
||||||
>添加属性</ElButton
|
添加属性
|
||||||
>
|
</ElButton>
|
||||||
<ProductAttributes
|
<ProductAttributes
|
||||||
:property-list="propertyList"
|
:property-list="propertyList"
|
||||||
@success="generateSkus"
|
@success="generateSkus"
|
||||||
|
|
@ -238,6 +243,6 @@ watch(
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Form>
|
</Form>
|
||||||
<ProductPropertyAddFormModal :propertyList="propertyList" />
|
<ProductPropertyAddFormModal :property-list="propertyList" />
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,636 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
|
import type { PropertyAndValues, RuleConfig } from './model';
|
||||||
|
|
||||||
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
|
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { formatToFraction, isEmpty } from '@vben/utils';
|
||||||
|
|
||||||
|
import { ElInput, ElMessage, ElTable } from 'element-plus';
|
||||||
|
|
||||||
|
import UploadImg from '#/components/upload/image-upload.vue';
|
||||||
|
import { copyValueToTarget } from '#/utils';
|
||||||
|
|
||||||
|
defineOptions({ name: 'SkuList' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
propFormData: {
|
||||||
|
type: Object as PropType<MallSpuApi.Spu>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
propertyList: {
|
||||||
|
type: Array as PropType<PropertyAndValues[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
ruleConfig: {
|
||||||
|
type: Array as PropType<RuleConfig[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
isBatch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, // 是否作为批量操作组件
|
||||||
|
isComponent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, // 是否作为组件
|
||||||
|
isActivityComponent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, // 是否作为活动组件
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'selectionChange', value: MallSpuApi.Sku[]): void;
|
||||||
|
}>(); const formData = ref<MallSpuApi.Spu>(); // 表单数据
|
||||||
|
const skuList = ref<MallSpuApi.Sku[]>([
|
||||||
|
{
|
||||||
|
price: 0, // 商品价格
|
||||||
|
marketPrice: 0, // 市场价
|
||||||
|
costPrice: 0, // 成本价
|
||||||
|
barCode: '', // 商品条码
|
||||||
|
picUrl: '', // 图片地址
|
||||||
|
stock: 0, // 库存
|
||||||
|
weight: 0, // 商品重量
|
||||||
|
volume: 0, // 商品体积
|
||||||
|
firstBrokeragePrice: 0, // 一级分销的佣金
|
||||||
|
secondBrokeragePrice: 0, // 二级分销的佣金
|
||||||
|
},
|
||||||
|
]); // 批量添加时的临时数据
|
||||||
|
|
||||||
|
/** 批量添加 */
|
||||||
|
const batchAdd = () => {
|
||||||
|
validateProperty();
|
||||||
|
formData.value!.skus!.forEach((item: MallSpuApi.Sku) => {
|
||||||
|
copyValueToTarget(item, skuList.value[0]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 校验商品属性属性值 */
|
||||||
|
const validateProperty = () => {
|
||||||
|
// 校验商品属性属性值是否为空,有一个为空都不给过
|
||||||
|
const warningInfo = '存在属性属性值为空,请先检查完善属性值后重试!!!';
|
||||||
|
for (const item of props.propertyList) {
|
||||||
|
if (!item.values || isEmpty(item.values)) {
|
||||||
|
ElMessage.warning(warningInfo);
|
||||||
|
throw new Error(warningInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 删除 sku */
|
||||||
|
const deleteSku = (row: MallSpuApi.Sku) => {
|
||||||
|
const index = formData.value!.skus!.findIndex(
|
||||||
|
// 直接把列表转成字符串比较
|
||||||
|
(sku: MallSpuApi.Sku) =>
|
||||||
|
JSON.stringify(sku.properties) === JSON.stringify(row.properties),
|
||||||
|
);
|
||||||
|
formData.value!.skus!.splice(index, 1);
|
||||||
|
};
|
||||||
|
const tableHeaders = ref<{ label: string; prop: string; }[]>([]); // 多属性表头
|
||||||
|
/**
|
||||||
|
* 保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。
|
||||||
|
*/
|
||||||
|
const validateSku = () => {
|
||||||
|
validateProperty();
|
||||||
|
let warningInfo = '请检查商品各行相关属性配置,';
|
||||||
|
let validate = true; // 默认通过
|
||||||
|
for (const sku of formData.value!.skus!) {
|
||||||
|
// 作为活动组件的校验
|
||||||
|
for (const rule of props?.ruleConfig) {
|
||||||
|
const arg = getValue(sku, rule.name);
|
||||||
|
if (!rule.rule(arg)) {
|
||||||
|
validate = false; // 只要有一个不通过则直接不通过
|
||||||
|
warningInfo += rule.message;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只要有一个不通过则结束后续的校验
|
||||||
|
if (!validate) {
|
||||||
|
ElMessage.warning(warningInfo);
|
||||||
|
throw new Error(warningInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getValue = (obj: any, arg: string) => {
|
||||||
|
const keys = arg.split('.');
|
||||||
|
let value = obj;
|
||||||
|
for (const key of keys) {
|
||||||
|
if (value && typeof value === 'object' && key in value) {
|
||||||
|
value = value[key];
|
||||||
|
} else {
|
||||||
|
value = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择时触发
|
||||||
|
* @param Sku 传递过来的选中的 sku 是一个数组
|
||||||
|
*/
|
||||||
|
const handleSelectionChange = (val: MallSpuApi.Sku[]) => {
|
||||||
|
emit('selectionChange', val);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将传进来的值赋值给 skuList
|
||||||
|
*/
|
||||||
|
watch(
|
||||||
|
() => props.propFormData,
|
||||||
|
(data) => {
|
||||||
|
if (!data) return;
|
||||||
|
formData.value = data;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 生成表数据 */
|
||||||
|
const generateTableData = (propertyList: any[]) => {
|
||||||
|
// 构建数据结构
|
||||||
|
const propertyValues = propertyList.map((item) =>
|
||||||
|
item.values.map((v: any) => ({
|
||||||
|
propertyId: item.id,
|
||||||
|
propertyName: item.name,
|
||||||
|
valueId: v.id,
|
||||||
|
valueName: v.name,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const buildSkuList = build(propertyValues);
|
||||||
|
// 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表
|
||||||
|
if (!validateData(propertyList)) {
|
||||||
|
// 如果不一致则重置表数据,默认添加新的属性重新生成 sku 列表
|
||||||
|
formData.value!.skus = [];
|
||||||
|
}
|
||||||
|
if (buildSkuList && buildSkuList.length > 0) {
|
||||||
|
for (const item of buildSkuList) {
|
||||||
|
const row = {
|
||||||
|
properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个 property 对象
|
||||||
|
price: 0,
|
||||||
|
marketPrice: 0,
|
||||||
|
costPrice: 0,
|
||||||
|
barCode: '',
|
||||||
|
picUrl: '',
|
||||||
|
stock: 0,
|
||||||
|
weight: 0,
|
||||||
|
volume: 0,
|
||||||
|
firstBrokeragePrice: 0,
|
||||||
|
secondBrokeragePrice: 0,
|
||||||
|
};
|
||||||
|
// 如果存在属性相同的 sku 则不做处理
|
||||||
|
const index = formData.value!.skus!.findIndex(
|
||||||
|
(sku: MallSpuApi.Sku) =>
|
||||||
|
JSON.stringify(sku.properties) === JSON.stringify(row.properties),
|
||||||
|
);
|
||||||
|
if (index !== -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
formData.value!.skus!.push(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 skus 前置校验
|
||||||
|
*/
|
||||||
|
const validateData = (propertyList: any[]) => {
|
||||||
|
const skuPropertyIds: number[] = [];
|
||||||
|
formData.value!.skus!.forEach((sku: MallSpuApi.Sku) =>
|
||||||
|
sku.properties
|
||||||
|
?.map((property: any) => property.propertyId)
|
||||||
|
?.forEach((propertyId: number) => {
|
||||||
|
if (!skuPropertyIds.indexOf(propertyId!) === -1) {
|
||||||
|
skuPropertyIds.push(propertyId!);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const propertyIds = propertyList.map((item) => item.id);
|
||||||
|
return skuPropertyIds.length === propertyIds.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 构建所有排列组合 */
|
||||||
|
const build = (
|
||||||
|
propertyValuesList: MallSpuApi.Property[][],
|
||||||
|
): MallSpuApi.Property[] | MallSpuApi.Property[][] => {
|
||||||
|
if (!propertyValuesList || propertyValuesList.length === 0) {
|
||||||
|
return [];
|
||||||
|
} else if (propertyValuesList.length === 1) {
|
||||||
|
return propertyValuesList[0] || [];
|
||||||
|
} else {
|
||||||
|
const result: MallSpuApi.Property[][] = [];
|
||||||
|
const rest = build(propertyValuesList.slice(1));
|
||||||
|
if (propertyValuesList[0] && Array.isArray(rest)) {
|
||||||
|
for (let i = 0; i < propertyValuesList[0].length; i++) {
|
||||||
|
for (const restItem of rest) {
|
||||||
|
const currentItem = propertyValuesList[0][i];
|
||||||
|
// 第一次不是数组结构,后面的都是数组结构
|
||||||
|
if (Array.isArray(restItem)) {
|
||||||
|
result.push([currentItem!, ...restItem]);
|
||||||
|
} else if (restItem) {
|
||||||
|
// 确保restItem不是undefined,并进行类型断言
|
||||||
|
result.push([currentItem!, restItem as MallSpuApi.Property]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 监听属性列表,生成相关参数和表头 */
|
||||||
|
watch(
|
||||||
|
() => props.propertyList,
|
||||||
|
(propertyList: PropertyAndValues[]) => {
|
||||||
|
// 如果不是多规格则结束
|
||||||
|
if (!formData.value!.specType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果当前组件作为批量添加数据使用,则重置表数据
|
||||||
|
if (props.isBatch) {
|
||||||
|
skuList.value = [
|
||||||
|
{
|
||||||
|
price: 0,
|
||||||
|
marketPrice: 0,
|
||||||
|
costPrice: 0,
|
||||||
|
barCode: '',
|
||||||
|
picUrl: '',
|
||||||
|
stock: 0,
|
||||||
|
weight: 0,
|
||||||
|
volume: 0,
|
||||||
|
firstBrokeragePrice: 0,
|
||||||
|
secondBrokeragePrice: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断代理对象是否为空
|
||||||
|
if (JSON.stringify(propertyList) === '[]') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 重置表头
|
||||||
|
tableHeaders.value = [];
|
||||||
|
// 生成表头
|
||||||
|
propertyList.forEach((item, index) => {
|
||||||
|
// name加属性项index区分属性值
|
||||||
|
tableHeaders.value.push({ prop: `name${index}`, label: item.name });
|
||||||
|
});
|
||||||
|
// 如果回显的 sku 属性和添加的属性一致则不处理
|
||||||
|
if (validateData(propertyList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 添加新属性没有属性值也不做处理
|
||||||
|
if (propertyList.some((item) => !item.values || isEmpty(item.values))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 生成 table 数据,即 sku 列表
|
||||||
|
generateTableData(propertyList);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const activitySkuListRef = ref<InstanceType<typeof ElTable>>();
|
||||||
|
|
||||||
|
const getSkuTableRef = () => {
|
||||||
|
return activitySkuListRef.value;
|
||||||
|
};
|
||||||
|
// 暴露出生成 sku 方法,给添加属性成功时调用
|
||||||
|
defineExpose({ generateTableData, validateSku, getSkuTableRef });
|
||||||
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<!-- 情况一:添加/修改 -->
|
<!-- 情况一:添加/修改 -->
|
||||||
<el-table
|
<ElTable
|
||||||
|
v-if="!isActivityComponent"
|
||||||
|
:data="isBatch ? skuList : formData!.skus!"
|
||||||
|
border
|
||||||
|
class="tabNumWidth"
|
||||||
|
max-height="500"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-table-column align="center" label="图片" min-width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<UploadImg
|
||||||
|
v-model="row.picUrl"
|
||||||
|
height="50px"
|
||||||
|
width="50px"
|
||||||
|
:show-description="false"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<template v-if="formData!.specType && !isBatch">
|
||||||
|
<!-- 根据商品属性动态添加 -->
|
||||||
|
<el-table-column
|
||||||
|
v-for="(item, index) in tableHeaders"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
align="center"
|
||||||
|
min-width="120"
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span style="font-weight: bold; color: #40aaff">
|
||||||
|
{{ row.properties?.[index]?.valueName }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<el-table-column align="center" label="商品条码" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<ElInput v-model="row.barCode" class="w-100%" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="销售价" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.price"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="市场价" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.marketPrice"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="成本价" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.costPrice"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="库存" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.stock"
|
||||||
|
:min="0"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="重量(kg)" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.weight"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="体积(m^3)" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.volume"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<template v-if="formData!.subCommissionType">
|
||||||
|
<el-table-column align="center" label="一级返佣(元)" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.firstBrokeragePrice"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="二级返佣(元)" min-width="168">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number
|
||||||
|
v-model="row.secondBrokeragePrice"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
class="w-100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<el-table-column
|
||||||
|
v-if="formData?.specType"
|
||||||
|
align="center"
|
||||||
|
fixed="right"
|
||||||
|
label="操作"
|
||||||
|
width="80"
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button
|
||||||
|
v-if="isBatch"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="batchAdd"
|
||||||
|
>
|
||||||
|
批量添加
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="deleteSku(row)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</ElTable>
|
||||||
|
|
||||||
|
<!-- 情况二:作为活动组件 -->
|
||||||
|
<ElTable
|
||||||
|
v-if="isActivityComponent"
|
||||||
|
:data="formData!.skus!"
|
||||||
|
border
|
||||||
|
max-height="500"
|
||||||
|
size="small"
|
||||||
|
style="width: 99%"
|
||||||
|
>
|
||||||
|
<el-table-column v-if="isComponent" type="selection" width="45" />
|
||||||
|
<el-table-column align="center" label="图片" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-image :src="row.picUrl" class="h-60px w-60px" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<template v-if="formData!.specType">
|
||||||
|
<!-- 根据商品属性动态添加 -->
|
||||||
|
<el-table-column
|
||||||
|
v-for="(item, index) in tableHeaders"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
align="center"
|
||||||
|
min-width="80"
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span style="font-weight: bold; color: #40aaff">
|
||||||
|
{{ row.properties?.[index]?.valueName }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<el-table-column align="center" label="商品条码" min-width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.barCode }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="销售价(元)" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatToFraction(row.price) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="市场价(元)" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatToFraction(row.marketPrice) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="成本价(元)" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatToFraction(row.costPrice) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="库存" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.stock }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 方便扩展每个活动配置的属性不一样 -->
|
||||||
|
<slot name="extension"></slot>
|
||||||
|
</ElTable>
|
||||||
|
</template>.includes(propertyId!)) {
|
||||||
|
skuPropertyIds.push(propertyId!);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const propertyIds = propertyList.map((item) => item.id);
|
||||||
|
return skuPropertyIds.length === propertyIds.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 构建所有排列组合 */
|
||||||
|
const build = (
|
||||||
|
propertyValuesList: MallSpuApi.Property[][],
|
||||||
|
): MallSpuApi.Property[] | MallSpuApi.Property[][] => {
|
||||||
|
if (!propertyValuesList || propertyValuesList.length === 0) {
|
||||||
|
return [];
|
||||||
|
} else if (propertyValuesList.length === 1) {
|
||||||
|
return propertyValuesList[0] || [];
|
||||||
|
} else {
|
||||||
|
const result: MallSpuApi.Property[][] = [];
|
||||||
|
const rest = build(propertyValuesList.slice(1));
|
||||||
|
if (propertyValuesList[0] && Array.isArray(rest)) {
|
||||||
|
for (let i = 0; i < propertyValuesList[0].length; i++) {
|
||||||
|
for (const restItem of rest) {
|
||||||
|
const currentItem = propertyValuesList[0][i];
|
||||||
|
// 第一次不是数组结构,后面的都是数组结构
|
||||||
|
if (Array.isArray(restItem)) {
|
||||||
|
result.push([currentItem!, ...restItem]);
|
||||||
|
} else if (restItem) {
|
||||||
|
// 确保restItem不是undefined,并进行类型断言
|
||||||
|
result.push([currentItem!, restItem as MallSpuApi.Property]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 监听属性列表,生成相关参数和表头 */
|
||||||
|
watch(
|
||||||
|
() => props.propertyList,
|
||||||
|
(propertyList: PropertyAndValues[]) => {
|
||||||
|
// 如果不是多规格则结束
|
||||||
|
if (!formData.value!.specType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果当前组件作为批量添加数据使用,则重置表数据
|
||||||
|
if (props.isBatch) {
|
||||||
|
skuList.value = [
|
||||||
|
{
|
||||||
|
price: 0,
|
||||||
|
marketPrice: 0,
|
||||||
|
costPrice: 0,
|
||||||
|
barCode: '',
|
||||||
|
picUrl: '',
|
||||||
|
stock: 0,
|
||||||
|
weight: 0,
|
||||||
|
volume: 0,
|
||||||
|
firstBrokeragePrice: 0,
|
||||||
|
secondBrokeragePrice: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断代理对象是否为空
|
||||||
|
if (JSON.stringify(propertyList) === '[]') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 重置表头
|
||||||
|
tableHeaders.value = [];
|
||||||
|
// 生成表头
|
||||||
|
propertyList.forEach((item, index) => {
|
||||||
|
// name加属性项index区分属性值
|
||||||
|
tableHeaders.value.push({ prop: `name${index}`, label: item.name });
|
||||||
|
});
|
||||||
|
// 如果回显的 sku 属性和添加的属性一致则不处理
|
||||||
|
if (validateData(propertyList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 添加新属性没有属性值也不做处理
|
||||||
|
if (propertyList.some((item) => !item.values || isEmpty(item.values))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 生成 table 数据,即 sku 列表
|
||||||
|
generateTableData(propertyList);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const activitySkuListRef = ref<InstanceType<typeof ElTable>>();
|
||||||
|
|
||||||
|
const getSkuTableRef = () => {
|
||||||
|
return activitySkuListRef.value;
|
||||||
|
};
|
||||||
|
// 暴露出生成 sku 方法,给添加属性成功时调用
|
||||||
|
defineExpose({ generateTableData, validateSku, getSkuTableRef });
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<!-- 情况一:添加/修改 -->
|
||||||
|
<ElTable
|
||||||
v-if="!isActivityComponent"
|
v-if="!isActivityComponent"
|
||||||
:data="isBatch ? skuList : formData!.skus!"
|
:data="isBatch ? skuList : formData!.skus!"
|
||||||
border
|
border
|
||||||
|
|
@ -162,10 +792,10 @@
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</ElTable>
|
||||||
|
|
||||||
<!-- 情况二:作为活动组件 -->
|
<!-- 情况二:作为活动组件 -->
|
||||||
<el-table
|
<ElTable
|
||||||
v-if="isActivityComponent"
|
v-if="isActivityComponent"
|
||||||
:data="formData!.skus!"
|
:data="formData!.skus!"
|
||||||
border
|
border
|
||||||
|
|
@ -222,306 +852,5 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 方便扩展每个活动配置的属性不一样 -->
|
<!-- 方便扩展每个活动配置的属性不一样 -->
|
||||||
<slot name="extension"></slot>
|
<slot name="extension"></slot>
|
||||||
</el-table>
|
</ElTable>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
|
||||||
import { copyValueToTarget } from '#/utils';
|
|
||||||
import { formatToFraction, isEmpty } from '@vben/utils';
|
|
||||||
import type { PropertyAndValues, RuleConfig } from './model';
|
|
||||||
import UploadImg from '#/components/upload/image-upload.vue';
|
|
||||||
import { ElTable, ElInput, ElMessage } from 'element-plus';
|
|
||||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
import type { PropType } from 'vue';
|
|
||||||
|
|
||||||
defineOptions({ name: 'SkuList' });
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
propFormData: {
|
|
||||||
type: Object as PropType<MallSpuApi.Spu>,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
propertyList: {
|
|
||||||
type: Array as PropType<PropertyAndValues[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
ruleConfig: {
|
|
||||||
type: Array as PropType<RuleConfig[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
isBatch: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
}, // 是否作为批量操作组件
|
|
||||||
isComponent: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
}, // 是否作为组件
|
|
||||||
isActivityComponent: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
}, // 是否作为活动组件
|
|
||||||
});
|
|
||||||
|
|
||||||
const formData = ref<MallSpuApi.Spu>(); // 表单数据
|
|
||||||
const skuList = ref<MallSpuApi.Sku[]>([
|
|
||||||
{
|
|
||||||
price: 0, // 商品价格
|
|
||||||
marketPrice: 0, // 市场价
|
|
||||||
costPrice: 0, // 成本价
|
|
||||||
barCode: '', // 商品条码
|
|
||||||
picUrl: '', // 图片地址
|
|
||||||
stock: 0, // 库存
|
|
||||||
weight: 0, // 商品重量
|
|
||||||
volume: 0, // 商品体积
|
|
||||||
firstBrokeragePrice: 0, // 一级分销的佣金
|
|
||||||
secondBrokeragePrice: 0, // 二级分销的佣金
|
|
||||||
},
|
|
||||||
]); // 批量添加时的临时数据
|
|
||||||
|
|
||||||
/** 批量添加 */
|
|
||||||
const batchAdd = () => {
|
|
||||||
validateProperty();
|
|
||||||
formData.value!.skus!.forEach((item: MallSpuApi.Sku) => {
|
|
||||||
copyValueToTarget(item, skuList.value[0]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/** 校验商品属性属性值 */
|
|
||||||
const validateProperty = () => {
|
|
||||||
// 校验商品属性属性值是否为空,有一个为空都不给过
|
|
||||||
const warningInfo = '存在属性属性值为空,请先检查完善属性值后重试!!!';
|
|
||||||
for (const item of props.propertyList) {
|
|
||||||
if (!item.values || isEmpty(item.values)) {
|
|
||||||
ElMessage.warning(warningInfo);
|
|
||||||
throw new Error(warningInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/** 删除 sku */
|
|
||||||
const deleteSku = (row: MallSpuApi.Sku) => {
|
|
||||||
const index = formData.value!.skus!.findIndex(
|
|
||||||
// 直接把列表转成字符串比较
|
|
||||||
(sku: MallSpuApi.Sku) =>
|
|
||||||
JSON.stringify(sku.properties) === JSON.stringify(row.properties),
|
|
||||||
);
|
|
||||||
formData.value!.skus!.splice(index, 1);
|
|
||||||
};
|
|
||||||
const tableHeaders = ref<{ prop: string; label: string }[]>([]); // 多属性表头
|
|
||||||
/**
|
|
||||||
* 保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。
|
|
||||||
*/
|
|
||||||
const validateSku = () => {
|
|
||||||
validateProperty();
|
|
||||||
let warningInfo = '请检查商品各行相关属性配置,';
|
|
||||||
let validate = true; // 默认通过
|
|
||||||
for (const sku of formData.value!.skus!) {
|
|
||||||
// 作为活动组件的校验
|
|
||||||
for (const rule of props?.ruleConfig) {
|
|
||||||
const arg = getValue(sku, rule.name);
|
|
||||||
if (!rule.rule(arg)) {
|
|
||||||
validate = false; // 只要有一个不通过则直接不通过
|
|
||||||
warningInfo += rule.message;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 只要有一个不通过则结束后续的校验
|
|
||||||
if (!validate) {
|
|
||||||
ElMessage.warning(warningInfo);
|
|
||||||
throw new Error(warningInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const getValue = (obj: any, arg: string) => {
|
|
||||||
const keys = arg.split('.');
|
|
||||||
let value = obj;
|
|
||||||
for (const key of keys) {
|
|
||||||
if (value && typeof value === 'object' && key in value) {
|
|
||||||
value = value[key];
|
|
||||||
} else {
|
|
||||||
value = undefined;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'selectionChange', value: MallSpuApi.Sku[]): void;
|
|
||||||
}>();
|
|
||||||
/**
|
|
||||||
* 选择时触发
|
|
||||||
* @param Sku 传递过来的选中的 sku 是一个数组
|
|
||||||
*/
|
|
||||||
const handleSelectionChange = (val: MallSpuApi.Sku[]) => {
|
|
||||||
emit('selectionChange', val);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将传进来的值赋值给 skuList
|
|
||||||
*/
|
|
||||||
watch(
|
|
||||||
() => props.propFormData,
|
|
||||||
(data) => {
|
|
||||||
if (!data) return;
|
|
||||||
formData.value = data;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true,
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/** 生成表数据 */
|
|
||||||
const generateTableData = (propertyList: any[]) => {
|
|
||||||
// 构建数据结构
|
|
||||||
const propertyValues = propertyList.map((item) =>
|
|
||||||
item.values.map((v: any) => ({
|
|
||||||
propertyId: item.id,
|
|
||||||
propertyName: item.name,
|
|
||||||
valueId: v.id,
|
|
||||||
valueName: v.name,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
const buildSkuList = build(propertyValues);
|
|
||||||
// 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表
|
|
||||||
if (!validateData(propertyList)) {
|
|
||||||
// 如果不一致则重置表数据,默认添加新的属性重新生成 sku 列表
|
|
||||||
formData.value!.skus = [];
|
|
||||||
}
|
|
||||||
if (buildSkuList && buildSkuList.length > 0) {
|
|
||||||
for (const item of buildSkuList) {
|
|
||||||
const row = {
|
|
||||||
properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个 property 对象
|
|
||||||
price: 0,
|
|
||||||
marketPrice: 0,
|
|
||||||
costPrice: 0,
|
|
||||||
barCode: '',
|
|
||||||
picUrl: '',
|
|
||||||
stock: 0,
|
|
||||||
weight: 0,
|
|
||||||
volume: 0,
|
|
||||||
firstBrokeragePrice: 0,
|
|
||||||
secondBrokeragePrice: 0,
|
|
||||||
};
|
|
||||||
// 如果存在属性相同的 sku 则不做处理
|
|
||||||
const index = formData.value!.skus!.findIndex(
|
|
||||||
(sku: MallSpuApi.Sku) =>
|
|
||||||
JSON.stringify(sku.properties) === JSON.stringify(row.properties),
|
|
||||||
);
|
|
||||||
if (index !== -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
formData.value!.skus!.push(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 skus 前置校验
|
|
||||||
*/
|
|
||||||
const validateData = (propertyList: any[]) => {
|
|
||||||
const skuPropertyIds: number[] = [];
|
|
||||||
formData.value!.skus!.forEach((sku: MallSpuApi.Sku) =>
|
|
||||||
sku.properties
|
|
||||||
?.map((property: any) => property.propertyId)
|
|
||||||
?.forEach((propertyId: number) => {
|
|
||||||
if (skuPropertyIds.indexOf(propertyId!) === -1) {
|
|
||||||
skuPropertyIds.push(propertyId!);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
const propertyIds = propertyList.map((item) => item.id);
|
|
||||||
return skuPropertyIds.length === propertyIds.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 构建所有排列组合 */
|
|
||||||
const build = (
|
|
||||||
propertyValuesList: MallSpuApi.Property[][],
|
|
||||||
): MallSpuApi.Property[] | MallSpuApi.Property[][] => {
|
|
||||||
if (!propertyValuesList || propertyValuesList.length === 0) {
|
|
||||||
return [];
|
|
||||||
} else if (propertyValuesList.length === 1) {
|
|
||||||
return propertyValuesList[0] || [];
|
|
||||||
} else {
|
|
||||||
const result: MallSpuApi.Property[][] = [];
|
|
||||||
const rest = build(propertyValuesList.slice(1));
|
|
||||||
if (propertyValuesList[0] && Array.isArray(rest)) {
|
|
||||||
for (let i = 0; i < propertyValuesList[0].length; i++) {
|
|
||||||
for (let j = 0; j < rest.length; j++) {
|
|
||||||
const currentItem = propertyValuesList[0][i];
|
|
||||||
const restItem = rest[j];
|
|
||||||
// 第一次不是数组结构,后面的都是数组结构
|
|
||||||
if (Array.isArray(restItem)) {
|
|
||||||
result.push([currentItem!, ...restItem]);
|
|
||||||
} else if (restItem) {
|
|
||||||
// 确保restItem不是undefined,并进行类型断言
|
|
||||||
result.push([currentItem!, restItem as MallSpuApi.Property]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 监听属性列表,生成相关参数和表头 */
|
|
||||||
watch(
|
|
||||||
() => props.propertyList,
|
|
||||||
(propertyList: PropertyAndValues[]) => {
|
|
||||||
// 如果不是多规格则结束
|
|
||||||
if (!formData.value!.specType) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果当前组件作为批量添加数据使用,则重置表数据
|
|
||||||
if (props.isBatch) {
|
|
||||||
skuList.value = [
|
|
||||||
{
|
|
||||||
price: 0,
|
|
||||||
marketPrice: 0,
|
|
||||||
costPrice: 0,
|
|
||||||
barCode: '',
|
|
||||||
picUrl: '',
|
|
||||||
stock: 0,
|
|
||||||
weight: 0,
|
|
||||||
volume: 0,
|
|
||||||
firstBrokeragePrice: 0,
|
|
||||||
secondBrokeragePrice: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断代理对象是否为空
|
|
||||||
if (JSON.stringify(propertyList) === '[]') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 重置表头
|
|
||||||
tableHeaders.value = [];
|
|
||||||
// 生成表头
|
|
||||||
propertyList.forEach((item, index) => {
|
|
||||||
// name加属性项index区分属性值
|
|
||||||
tableHeaders.value.push({ prop: `name${index}`, label: item.name });
|
|
||||||
});
|
|
||||||
// 如果回显的 sku 属性和添加的属性一致则不处理
|
|
||||||
if (validateData(propertyList)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 添加新属性没有属性值也不做处理
|
|
||||||
if (propertyList.some((item) => !item.values || isEmpty(item.values))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 生成 table 数据,即 sku 列表
|
|
||||||
generateTableData(propertyList);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true,
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const activitySkuListRef = ref<InstanceType<typeof ElTable>>();
|
|
||||||
|
|
||||||
const getSkuTableRef = () => {
|
|
||||||
return activitySkuListRef.value;
|
|
||||||
};
|
|
||||||
// 暴露出生成 sku 方法,给添加属性成功时调用
|
|
||||||
defineExpose({ generateTableData, validateSku, getSkuTableRef });
|
|
||||||
</script>
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Page } from '@vben/common-ui';
|
|
||||||
import { onMounted, ref, unref } from 'vue';
|
|
||||||
import { cloneDeep } from '@vben/utils';
|
|
||||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
|
||||||
import { formatToFraction, convertToInteger } from '@vben/utils';
|
import { onMounted, ref, unref } from 'vue';
|
||||||
import * as ProductSpuApi from '#/api/mall/product/spu';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
import { cloneDeep, convertToInteger, formatToFraction } from '@vben/utils';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
import InfoForm from '../components/info-form.vue';
|
import * as ProductSpuApi from '#/api/mall/product/spu';
|
||||||
|
|
||||||
import DeliveryForm from '../components/delivery-form.vue';
|
import DeliveryForm from '../components/delivery-form.vue';
|
||||||
import DescriptionForm from '../components/description-form.vue';
|
import DescriptionForm from '../components/description-form.vue';
|
||||||
|
import InfoForm from '../components/info-form.vue';
|
||||||
import OtherForm from '../components/other-form.vue';
|
import OtherForm from '../components/other-form.vue';
|
||||||
import SkuForm from '../components/sku-form.vue';
|
import SkuForm from '../components/sku-form.vue';
|
||||||
|
|
||||||
|
|
@ -115,12 +118,12 @@ const submitForm = async () => {
|
||||||
// 校验都通过后提交表单
|
// 校验都通过后提交表单
|
||||||
const data = deepCopyFormData as MallSpuApi.Spu;
|
const data = deepCopyFormData as MallSpuApi.Spu;
|
||||||
const id = params.id as unknown as number;
|
const id = params.id as unknown as number;
|
||||||
if (!id) {
|
if (id) {
|
||||||
await ProductSpuApi.createSpu(data);
|
|
||||||
ElMessage.success('创建成功');
|
|
||||||
} else {
|
|
||||||
await ProductSpuApi.updateSpu(data);
|
await ProductSpuApi.updateSpu(data);
|
||||||
ElMessage.success('更新成功');
|
ElMessage.success('更新成功');
|
||||||
|
} else {
|
||||||
|
await ProductSpuApi.createSpu(data);
|
||||||
|
ElMessage.success('创建成功');
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -144,43 +147,43 @@ onMounted(async () => {
|
||||||
<ElTabs v-model="activeTab">
|
<ElTabs v-model="activeTab">
|
||||||
<ElTabPane label="基础设置" name="info">
|
<ElTabPane label="基础设置" name="info">
|
||||||
<InfoForm
|
<InfoForm
|
||||||
:propFormData="formData"
|
:prop-form-data="formData"
|
||||||
v-model:activeName="activeName"
|
v-model:active-name="activeName"
|
||||||
ref="infoRef"
|
ref="infoRef"
|
||||||
/>
|
/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
<ElTabPane label="价格库存" name="sku">
|
<ElTabPane label="价格库存" name="sku">
|
||||||
<SkuForm
|
<SkuForm
|
||||||
:propFormData="formData"
|
:prop-form-data="formData"
|
||||||
v-model:activeName="activeName"
|
v-model:active-name="activeName"
|
||||||
ref="skuRef"
|
ref="skuRef"
|
||||||
/>
|
/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
<ElTabPane label="物流设置" name="delivery">
|
<ElTabPane label="物流设置" name="delivery">
|
||||||
<DeliveryForm
|
<DeliveryForm
|
||||||
:propFormData="formData"
|
:prop-form-data="formData"
|
||||||
v-model:activeName="activeName"
|
v-model:active-name="activeName"
|
||||||
ref="deliveryRef"
|
ref="deliveryRef"
|
||||||
/>
|
/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
<ElTabPane label="商品详情" name="description">
|
<ElTabPane label="商品详情" name="description">
|
||||||
<DescriptionForm
|
<DescriptionForm
|
||||||
:propFormData="formData"
|
:prop-form-data="formData"
|
||||||
v-model:activeName="activeName"
|
v-model:active-name="activeName"
|
||||||
ref="descriptionRef"
|
ref="descriptionRef"
|
||||||
/>
|
/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
<ElTabPane label="其它设置" name="other">
|
<ElTabPane label="其它设置" name="other">
|
||||||
<OtherForm
|
<OtherForm
|
||||||
:propFormData="formData"
|
:prop-form-data="formData"
|
||||||
v-model:activeName="activeName"
|
v-model:active-name="activeName"
|
||||||
ref="otherRef"
|
ref="otherRef"
|
||||||
/>
|
/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
</ElTabs>
|
</ElTabs>
|
||||||
<ElButton type="primary" :loading="formLoading" @click="submitForm"
|
<ElButton type="primary" :loading="formLoading" @click="submitForm">
|
||||||
>保存</ElButton
|
保存
|
||||||
>
|
</ElButton>
|
||||||
<ElButton @click="close">返回</ElButton>
|
<ElButton @click="close">返回</ElButton>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ async function onDelete(row: any) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该字典数据吗?');
|
await confirm('确定要批量删除该字典数据吗?');
|
||||||
await deleteDictDataList(checkedIds.value);
|
await deleteDictDataList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ async function onDelete(row: SystemDictTypeApi.DictType) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该字典类型吗?');
|
await confirm('确定要批量删除该字典类型吗?');
|
||||||
await deleteDictTypeList(checkedIds.value);
|
await deleteDictTypeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ async function onDelete(row: SystemMailAccountApi.MailAccount) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该邮箱账号吗?');
|
await confirm('确定要批量删除该邮箱账号吗?');
|
||||||
await deleteMailAccountList(checkedIds.value);
|
await deleteMailAccountList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ async function onDelete(row: SystemMailTemplateApi.MailTemplate) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该邮件模板吗?');
|
await confirm('确定要批量删除该邮件模板吗?');
|
||||||
await deleteMailTemplateList(checkedIds.value);
|
await deleteMailTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ async function onDelete(row: SystemNoticeApi.Notice) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该公告吗?');
|
await confirm('确定要批量删除该公告吗?');
|
||||||
await deleteNoticeList(checkedIds.value);
|
await deleteNoticeList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ async function onDeleteBatch() {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteNotifyTemplateList(checkedIds.value);
|
await deleteNotifyTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
loadingInstance.close();
|
loadingInstance.close();
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ async function onDelete(row: SystemOAuth2ClientApi.OAuth2Client) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该 OAuth2 客户端吗?');
|
await confirm('确定要批量删除该 OAuth2 客户端吗?');
|
||||||
await deleteOAuth2ClientList(checkedIds.value);
|
await deleteOAuth2ClientList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function onDelete(row: SystemPostApi.Post) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该岗位吗?');
|
await confirm('确定要批量删除该岗位吗?');
|
||||||
await deletePostList(checkedIds.value);
|
await deletePostList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ async function onDelete(row: SystemRoleApi.Role) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该角色吗?');
|
await confirm('确定要批量删除该角色吗?');
|
||||||
await deleteRoleList(checkedIds.value);
|
await deleteRoleList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async function onDelete(row: SystemSmsChannelApi.SmsChannel) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该短信渠道吗?');
|
await confirm('确定要批量删除该短信渠道吗?');
|
||||||
await deleteSmsChannelList(checkedIds.value);
|
await deleteSmsChannelList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ async function onDelete(row: SystemSmsTemplateApi.SmsTemplate) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该短信模板吗?');
|
await confirm('确定要批量删除该短信模板吗?');
|
||||||
await deleteSmsTemplateList(checkedIds.value);
|
await deleteSmsTemplateList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ async function onDelete(row: SystemSocialClientApi.SocialClient) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该社交客户端吗?');
|
await confirm('确定要批量删除该社交客户端吗?');
|
||||||
await deleteSocialClientList(checkedIds.value);
|
await deleteSocialClientList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ async function onDelete(row: SystemTenantApi.Tenant) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该租户吗?');
|
await confirm('确定要批量删除该租户吗?');
|
||||||
await deleteTenantList(checkedIds.value);
|
await deleteTenantList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ async function onDelete(row: SystemTenantPackageApi.TenantPackage) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该租户套餐吗?');
|
await confirm('确定要批量删除该租户套餐吗?');
|
||||||
await deleteTenantPackageList(checkedIds.value);
|
await deleteTenantPackageList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ async function onDelete(row: SystemUserApi.User) {
|
||||||
async function onDeleteBatch() {
|
async function onDeleteBatch() {
|
||||||
await confirm('确定要批量删除该用户吗?');
|
await confirm('确定要批量删除该用户吗?');
|
||||||
await deleteUserList(checkedIds.value);
|
await deleteUserList(checkedIds.value);
|
||||||
|
checkedIds.value = [];
|
||||||
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue