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