@@ -4,7 +4,7 @@ import type { MallBrandApi } from '#/api/mall/product/brand';
|
||||
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { ElLoading, ElMessage } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteBrand, getBrandPage } from '#/api/mall/product/brand';
|
||||
@@ -35,17 +35,15 @@ function handleEdit(row: MallBrandApi.Brand) {
|
||||
|
||||
/** 删除品牌 */
|
||||
async function handleDelete(row: MallBrandApi.Brand) {
|
||||
const loadingInstance = ElLoading.service({
|
||||
text: $t('ui.actionMessage.deleting', [row.name]),
|
||||
fullscreen: true,
|
||||
// 二次确认
|
||||
await ElMessageBox.confirm('确定删除该品牌吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
try {
|
||||
await deleteBrand(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
} finally {
|
||||
loadingInstance.close();
|
||||
}
|
||||
await deleteBrand(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useRouter } from 'vue-router';
|
||||
|
||||
import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { ElLoading, ElMessage } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteCategory, getCategoryList } from '#/api/mall/product/category';
|
||||
@@ -52,17 +52,14 @@ const handleViewSpu = (id: number) => {
|
||||
|
||||
/** 删除分类 */
|
||||
async function handleDelete(row: MallCategoryApi.Category) {
|
||||
const loadingInstance = ElLoading.service({
|
||||
text: $t('ui.actionMessage.deleting', [row.name]),
|
||||
fullscreen: true,
|
||||
await ElMessageBox.confirm('确定删除该分类吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
try {
|
||||
await deleteCategory(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
} finally {
|
||||
loadingInstance.close();
|
||||
}
|
||||
await deleteCategory(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
/** 切换树形展开/收缩状态 */
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { MallPropertyApi } from '#/api/mall/product/property';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { ElLoading, ElMessage } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteProperty, getPropertyPage } from '#/api/mall/product/property';
|
||||
@@ -40,17 +40,14 @@ function handleEdit(row: any) {
|
||||
|
||||
/** 删除属性 */
|
||||
async function handleDelete(row: MallPropertyApi.Property) {
|
||||
const loadingInstance = ElLoading.service({
|
||||
text: $t('ui.actionMessage.deleting', [row.name]),
|
||||
fullscreen: true,
|
||||
await ElMessageBox.confirm('确定删除该属性吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
try {
|
||||
await deleteProperty(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
} finally {
|
||||
loadingInstance.close();
|
||||
}
|
||||
await deleteProperty(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
/** 表格事件 */
|
||||
|
||||
@@ -6,7 +6,7 @@ import { watch } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { ElLoading, ElMessage } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
@@ -47,17 +47,14 @@ function handleEdit(row: MallPropertyApi.PropertyValue) {
|
||||
|
||||
/** 删除字典数据 */
|
||||
async function handleDelete(row: MallPropertyApi.PropertyValue) {
|
||||
const loadingInstance = ElLoading.service({
|
||||
text: $t('ui.actionMessage.deleting', [row.name]),
|
||||
fullscreen: true,
|
||||
await ElMessageBox.confirm('确定删除该属性值吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
try {
|
||||
await deletePropertyValue(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
} finally {
|
||||
loadingInstance.close();
|
||||
}
|
||||
await deletePropertyValue(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import * as ExpressTemplateApi from '#/api/mall/trade/delivery/expressTemplate';
|
||||
import { watch } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { DICT_TYPE, getIntDictOptions, DeliveryTypeEnum } from '#/utils';
|
||||
import { DeliveryTypeEnum, DICT_TYPE, getIntDictOptions } from '#/utils';
|
||||
|
||||
const props = defineProps<{
|
||||
propFormData: Object;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:activeName']);
|
||||
|
||||
/** 将传进来的值赋值给 formData */
|
||||
watch(
|
||||
() => props.propFormData,
|
||||
@@ -20,7 +24,6 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:activeName']);
|
||||
const validate = async () => {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
@@ -29,10 +32,10 @@ const validate = async () => {
|
||||
try {
|
||||
// 校验通过更新数据
|
||||
Object.assign(props.propFormData, formApi.getValues());
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
ElMessage.error('【物流设置】不完善,请填写相关信息');
|
||||
emit('update:activeName', 'delivery');
|
||||
throw e; // 目的截断之后的校验
|
||||
throw error; // 目的截断之后的校验
|
||||
}
|
||||
};
|
||||
defineExpose({ validate });
|
||||
@@ -62,11 +65,8 @@ const [Form, formApi] = useVbenForm({
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: ExpressTemplateApi.getSimpleTemplateList,
|
||||
props: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
},
|
||||
labelField: 'name',
|
||||
valueField: 'id',
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { handleTree } from '@vben/utils';
|
||||
import * as ProductCategoryApi from '#/api/mall/product/category';
|
||||
import * as ProductBrandApi from '#/api/mall/product/brand';
|
||||
import { watch } from 'vue';
|
||||
|
||||
import { handleTree } from '@vben/utils';
|
||||
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import * as ProductBrandApi from '#/api/mall/product/brand';
|
||||
import * as ProductCategoryApi from '#/api/mall/product/category';
|
||||
|
||||
const props = defineProps<{
|
||||
propFormData: Object;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:activeName']);
|
||||
|
||||
const getCategoryList = async () => {
|
||||
const data = await ProductCategoryApi.getCategorySimpleList();
|
||||
return handleTree(data, 'id');
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
propFormData: Object;
|
||||
}>();
|
||||
|
||||
/** 将传进来的值赋值给 formData */
|
||||
watch(
|
||||
() => props.propFormData,
|
||||
@@ -26,7 +31,6 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:activeName']);
|
||||
const validate = async () => {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
@@ -35,10 +39,10 @@ const validate = async () => {
|
||||
try {
|
||||
// 校验通过更新数据
|
||||
Object.assign(props.propFormData, formApi.getValues());
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
ElMessage.error('【基础设置】不完善,请填写相关信息');
|
||||
emit('update:activeName', 'info');
|
||||
throw e; // 目的截断之后的校验
|
||||
throw error; // 目的截断之后的校验
|
||||
}
|
||||
};
|
||||
defineExpose({ validate });
|
||||
@@ -68,11 +72,9 @@ const [Form, formApi] = useVbenForm({
|
||||
component: 'ApiCascader',
|
||||
componentProps: {
|
||||
api: getCategoryList,
|
||||
props: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
},
|
||||
labelField: 'name',
|
||||
valueField: 'id',
|
||||
childrenField: 'children',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
|
||||
@@ -24,7 +24,9 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||
const res = await getCategoryList({});
|
||||
return handleTree(res, 'id', 'parentId', 'children');
|
||||
},
|
||||
fieldNames: { label: 'name', value: 'id', children: 'children' },
|
||||
labelField: 'name',
|
||||
valueField: 'id',
|
||||
childrenField: 'children',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
treeToString,
|
||||
} from '@vben/utils';
|
||||
|
||||
import { ElDescriptions, ElLoading, ElMessage, ElTabs } from 'element-plus';
|
||||
import { ElDescriptions, ElMessage, ElMessageBox, ElTabs } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getCategoryList } from '#/api/mall/product/category';
|
||||
@@ -97,35 +97,31 @@ function handleEdit(row: MallSpuApi.Spu) {
|
||||
|
||||
/** 删除商品 */
|
||||
async function handleDelete(row: MallSpuApi.Spu) {
|
||||
const hideLoading = ElLoading.service({
|
||||
text: $t('ui.actionMessage.deleting', [row.name]),
|
||||
fullscreen: true,
|
||||
await ElMessageBox.confirm('确定删除该商品吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
try {
|
||||
await deleteSpu(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
} finally {
|
||||
hideLoading.close();
|
||||
}
|
||||
await deleteSpu(row.id as number);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
/** 添加到仓库 / 回收站的状态 */
|
||||
async function handleStatus02Change(row: MallSpuApi.Spu, newStatus: number) {
|
||||
// 二次确认
|
||||
const text =
|
||||
newStatus === ProductSpuStatusEnum.RECYCLE.status
|
||||
? '加入到回收站'
|
||||
: '恢复到仓库';
|
||||
confirm(`确认要"${row.name}"${text}吗?`)
|
||||
.then(async () => {
|
||||
await updateStatus({ id: row.id as number, status: newStatus });
|
||||
ElMessage.success(`${text}成功`);
|
||||
onRefresh();
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error(`${text}失败`);
|
||||
});
|
||||
// 二次确认
|
||||
await ElMessageBox.confirm(`确认要jian"${row.name}"${text}吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
await updateStatus({ id: row.id as number, status: newStatus });
|
||||
ElMessage.success(`${text}成功`);
|
||||
onRefresh();
|
||||
}
|
||||
|
||||
/** 更新状态 */
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
<script lang="ts" setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { floatToFixed2 } from '@vben/utils';
|
||||
import * as ProductSpuApi from '#/api/mall/product/spu';
|
||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||
import * as ProductCategoryApi from '#/api/mall/product/category';
|
||||
import * as ProductBrandApi from '#/api/mall/product/brand';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { getIntDictOptions, DICT_TYPE } from '#/utils/dict';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { floatToFixed2 } from '@vben/utils';
|
||||
|
||||
import {
|
||||
ElButton,
|
||||
ElCard,
|
||||
ElDescriptions,
|
||||
ElDescriptionsItem,
|
||||
ElCarousel,
|
||||
ElCarouselItem,
|
||||
ElImage,
|
||||
ElDivider,
|
||||
ElButton,
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElTag,
|
||||
ElBadge,
|
||||
ElDescriptions,
|
||||
ElDescriptionsItem,
|
||||
ElEmpty,
|
||||
ElImage,
|
||||
ElTabPane,
|
||||
ElTabs,
|
||||
ElTag,
|
||||
} from 'element-plus';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import * as ProductBrandApi from '#/api/mall/product/brand';
|
||||
import * as ProductCategoryApi from '#/api/mall/product/category';
|
||||
import * as ProductSpuApi from '#/api/mall/product/spu';
|
||||
import { DICT_TYPE, getIntDictOptions } from '#/utils/dict';
|
||||
|
||||
interface Category {
|
||||
id: number;
|
||||
@@ -214,18 +216,18 @@ onMounted(async () => {
|
||||
<ElTag v-if="formData.specType" type="success">多规格</ElTag>
|
||||
<ElTag v-else type="info">单规格</ElTag>
|
||||
<ElTag v-if="formData.subCommissionType" type="warning">分销</ElTag>
|
||||
<ElTag type="danger"
|
||||
>库存:
|
||||
<ElTag type="danger">
|
||||
库存:
|
||||
{{
|
||||
formData.skus?.reduce(
|
||||
(sum, sku) => sum + (sku.stock || 0),
|
||||
0,
|
||||
) || 0
|
||||
}}</ElTag
|
||||
>
|
||||
<ElTag type="info"
|
||||
>分类: {{ getCategoryNameById(formData.categoryId) }}</ElTag
|
||||
>
|
||||
}}
|
||||
</ElTag>
|
||||
<ElTag type="info">
|
||||
分类: {{ getCategoryNameById(formData.categoryId) }}
|
||||
</ElTag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,32 +238,31 @@ onMounted(async () => {
|
||||
<!-- 基本信息 -->
|
||||
<ElCard shadow="never" header="商品信息" class="h-full">
|
||||
<ElDescriptions :column="1" border>
|
||||
<ElDescriptionsItem label="商品名称">{{
|
||||
formData.name
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="商品名称">
|
||||
{{ formData.name }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="商品分类">
|
||||
<ElTag type="success">{{
|
||||
getCategoryNameById(formData.categoryId)
|
||||
}}</ElTag>
|
||||
<ElTag type="success">
|
||||
{{ getCategoryNameById(formData.categoryId) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="商品品牌">
|
||||
<ElTag type="primary">{{
|
||||
getBrandNameById(formData.brandId)
|
||||
}}</ElTag>
|
||||
<ElTag type="primary">
|
||||
{{ getBrandNameById(formData.brandId) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="关键字">
|
||||
<ElTag type="danger"></ElTag
|
||||
>{{ formData.keyword || '无' }}</ElDescriptionsItem
|
||||
>
|
||||
<ElDescriptionsItem label="赠送积分">{{
|
||||
formData.giveIntegral
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="虚拟销量">{{
|
||||
formData.virtualSalesCount
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="排序">{{
|
||||
formData.sort
|
||||
}}</ElDescriptionsItem>
|
||||
<ElTag type="danger" />{{ formData.keyword || '无' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="赠送积分">
|
||||
{{ formData.giveIntegral }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="虚拟销量">
|
||||
{{ formData.virtualSalesCount }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="排序">
|
||||
{{ formData.sort }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="规格类型">
|
||||
<ElTag :type="formData.specType ? 'success' : 'info'">
|
||||
{{ formData.specType ? '多规格' : '单规格' }}
|
||||
@@ -309,9 +310,9 @@ onMounted(async () => {
|
||||
</span>
|
||||
</div>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="运费模板">{{
|
||||
formData.deliveryTemplateId || '未设置'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="运费模板">
|
||||
{{ formData.deliveryTemplateId || '未设置' }}
|
||||
</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElCard>
|
||||
</div>
|
||||
@@ -370,7 +371,7 @@ onMounted(async () => {
|
||||
>
|
||||
<ElCard
|
||||
shadow="hover"
|
||||
:header="`规格 ${index + 1}${sku.properties && sku.properties.length > 0 ? ' - ' + sku.properties.map((p) => p.valueName).join('/') : ''}`"
|
||||
:header="`规格 ${index + 1}${sku.properties && sku.properties.length > 0 ? ` - ${sku.properties.map((p) => p.valueName).join('/')}` : ''}`"
|
||||
>
|
||||
<div class="flex flex-col gap-4 md:flex-row">
|
||||
<ElImage
|
||||
@@ -484,14 +485,17 @@ onMounted(async () => {
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.product-description :deep(img) {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.product-description :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.product-description :deep(table td) {
|
||||
padding: 8px;
|
||||
border: 1px solid #eee;
|
||||
|
||||
Reference in New Issue
Block a user