在线商城

This commit is contained in:
zjf committed 2025-06-19 16:46:54 +08:00
1 parent 3eb2b64600
commit 40e16b7d3b
5 files changed
+224 -182

No files matched your search

+7
View File
@@ -39,3 +39,10 @@ export function putObj(obj?: Object) {
})
}
export function tree(obj?: Object) {
return request({
url: '/supermarket/shopCategory/tree',
method: 'get',
data: obj
})
}
+38 -22
View File
@@ -4,8 +4,15 @@
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="父级分类ID,0为顶级" prop="parentId">
<el-input v-model="form.parentId" placeholder="请输入父级分类ID,0为顶级"/>
<el-form-item label="父级分类" prop="parentId">
<el-select v-model="form.parentId" clearable placeholder="请选择父级分类">
<el-option
v-for="item in categoryOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
@@ -15,12 +22,6 @@
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="层级(1/2/3)" prop="level">
<el-input v-model="form.level" placeholder="请输入层级(1/2/3)"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序" prop="sort">
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
@@ -42,12 +43,6 @@
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="部门ID" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门ID"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
@@ -62,8 +57,9 @@
<script setup lang="ts" name="ShopCategoryDialog">
import { useDict } from '/@/hooks/dict';
import { useMessage } from "/@/hooks/message";
import { getObj, addObj, putObj } from '/@/api/supermarket/shopCategory'
import { getObj, addObj, putObj, fetchList } from '/@/api/supermarket/shopCategory'
import { rule } from '/@/utils/validate';
import { ref, reactive, nextTick, onMounted } from 'vue';
const emit = defineEmits(['refresh']);
// 定义变量内容
@@ -78,11 +74,9 @@ const form = reactive({
id:'',
parentId: '',
name: '',
level: '',
sort: 0,
status: '',
sort: 0,
status: '0',
picUrl: '',
deptId: '',
});
// 定义校验规则
@@ -90,20 +84,40 @@ const dataRules = ref({
name: [{required: true, message: '分类名称不能为空', trigger: 'blur'}],
})
// 分类选项
const categoryOptions = ref<any[]>([]);
// 获取所有分类(排除自身)
const loadCategories = async () => {
const res = await fetchList({ size: 9999 });
if (res && res.data && res.data.records) {
// 排除自己,避免自己作为自己的父级
categoryOptions.value = res.data.records.filter((item: any) => item.id !== form.id);
}
};
onMounted(() => {
loadCategories();
});
// 打开弹窗
const openDialog = (id: string) => {
visible.value = true
form.id = ''
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
nextTick(() => {
dataFormRef.value?.resetFields();
form.status = '0';
});
// 获取shopCategory信息
if (id) {
form.id = id
getshopCategoryData(id)
} else {
// 新增时直接加载分类
loadCategories();
}
};
@@ -132,6 +146,8 @@ const getshopCategoryData = (id: string) => {
loading.value = true
getObj(id).then((res: any) => {
Object.assign(form, res.data)
// 编辑时加载分类并排除自己
loadCategories();
}).finally(() => {
loading.value = false
})
+65 -23
View File
@@ -29,23 +29,27 @@
@queryTable="getDataList"></right-toolbar>
</div>
</el-row>
<el-table :data="state.dataList" v-loading="state.loading" border
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
@selection-change="selectionChangHandle"
@sort-change="sortChangeHandle">
<el-table
:data="treeData"
row-key="id"
:tree-props="{ children: 'children' }"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
@selection-change="selectionChangHandle"
@sort-change="sortChangeHandle"
>
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="parentId" label="父级分类ID,0为顶级" show-overflow-tooltip/>
<el-table-column prop="name" label="分类名称" show-overflow-tooltip/>
<el-table-column prop="level" label="层级(1/2/3)" show-overflow-tooltip/>
<el-table-column prop="sort" label="排序" show-overflow-tooltip/>
<el-table-column prop="status" label="状态(0正常,1下架)" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip/>
<el-table-column prop="deptId" label="部门ID" show-overflow-tooltip/>
<el-table-column prop="name" label="分类名称" show-overflow-tooltip/>
<el-table-column prop="sort" label="排序" show-overflow-tooltip/>
<el-table-column prop="status" label="状态(0正常,1下架)" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip/>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_shopCategory_edit'"
@@ -54,20 +58,21 @@
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
<!-- <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" /> -->
</div>
<!-- 编辑、新增 -->
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
</div>
</template>
<script setup lang="ts" name="systemShopCategory">
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObjs } from "/@/api/supermarket/shopCategory";
import { fetchList, delObjs, tree as fetchTree } from "/@/api/supermarket/shopCategory";
import { useMessage, useMessageBox } from "/@/hooks/message";
import { useDict } from '/@/hooks/dict';
import { ref, reactive, onMounted, defineExpose } from 'vue';
// 引入组件
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
@@ -85,24 +90,57 @@ const multiple = ref(true)
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList
pageList: fetchList,
loading: false,
pagination: { total: 0 }
})
const treeData = ref<any[]>([])
function listToTree(list: any[]): any[] {
const map = new Map<string, any>();
list.forEach((item: any) => {
item.children = [];
map.set(item.id, item);
});
const tree: any[] = [];
list.forEach((item: any) => {
if (item.parentId && item.parentId !== '0' && map.has(item.parentId)) {
map.get(item.parentId).children.push(item);
} else {
tree.push(item);
}
});
return tree;
}
const getDataList = async () => {
state.loading = true;
try {
const res = await fetchTree();
treeData.value = res.data || [];
(state.pagination as any).total = Array.isArray(res.data) ? res.data.length : 0;
} finally {
state.loading = false;
}
}
onMounted(() => {
getDataList();
})
// table hook
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
sortChangeHandle,
downBlobFile,
tableStyle
tableStyle
} = useTable(state)
// 清空搜索条件
const resetQuery = () => {
// 清空搜索条件
queryRef.value?.resetFields()
// 清空多选
selectObjs.value = []
getDataList()
}
@@ -134,4 +172,8 @@ const handleDelete = async (ids: string[]) => {
useMessage().error(err.msg);
}
};
defineExpose({
treeData
});
</script>
+111 -126
View File
@@ -1,118 +1,102 @@
<template>
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="货号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入货号"/>
</el-form-item>
</el-col>
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="货号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入货号"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入商品名称"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入商品名称"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品详情" prop="description">
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入商品详情"></editor>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品分类编号" prop="categoryId">
<el-select v-model="form.categoryId" placeholder="请选择商品分类编号">
<el-option label="请选择">0</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品分类" prop="categoryId">
<el-select v-model="form.categoryId" placeholder="请选择商品分类">
<el-option label="请选择">0</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品封面图" prop="picUrl">
<upload-img v-model="form.picUrl"></upload-img>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="商品封面图" prop="picUrl">
<upload-img v-model="form.picUrl"></upload-img>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品轮播图地址
数组,以逗号分隔
最多上传15张" prop="sliderPicUrls">
<upload-img v-model="form.sliderPicUrls"></upload-img>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="商品轮播图" prop="sliderPicUrls">
<upload-img v-model="form.sliderPicUrls"></upload-img>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序字段" prop="sort">
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序字段"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序" prop="sort">
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序字段"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品状态: 1 上架(开启) 0 下架(禁用) -1 回收" prop="status">
<el-input v-model="form.status" placeholder="请输入商品状态: 1 上架(开启) 0 下架(禁用) -1 回收"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品状态" prop="status">
<el-input v-model="form.status" placeholder="请输入商品状态"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="库存" prop="stock">
<el-input-number :min="1" :max="1000" v-model="form.stock" placeholder="请输入库存"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="库存" prop="stock">
<el-input-number :min="0" :max="1000" v-model="form.stock" placeholder="请输入库存"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="赠送积分" prop="giveIntegral">
<el-input v-model="form.giveIntegral" placeholder="请输入赠送积分"/>
</el-form-item>
</el-col>
<!-- <el-col :span="12" class="mb20">-->
<!-- <el-form-item label="销量" prop="salesCount">-->
<!-- <el-input v-model="form.salesCount" placeholder="请输入销量"/>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="12" class="mb20">
<el-form-item label="商户关系表" prop="merchantRelationId">
<el-input v-model="form.merchantRelationId" placeholder="请输入商户关系表"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="单人限购数" prop="limitNum">
<el-input-number :min="1" :max="1000" v-model="form.limitNum"
placeholder="请输入单人限购数量"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="部门id" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门id"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="在销商户" prop="merchantRelationId">
<el-input v-model="form.merchantRelationId" placeholder="请输入商户关系表"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="skuid" prop="shopSkuId">
<el-input v-model="form.shopSkuId" placeholder="请输入skuid"/>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="商品详情" prop="description">
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入商品详情"></editor>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="销量" prop="salesCount">
<el-input v-model="form.salesCount" placeholder="请输入销量"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="单人限购数量" prop="limitNum">
<el-input-number :min="1" :max="1000" v-model="form.limitNum" placeholder="请输入单人限购数量"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
</span>
</template>
</el-dialog>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="ShopSpuDialog">
import { useDict } from '/src/hooks/dict';
import { useMessage } from "/src/hooks/message";
import { getObj, addObj, putObj } from '/src/api/supermarket/shopSpu'
import { rule } from '/src/utils/validate';
import {useDict} from '/src/hooks/dict';
import {useMessage} from "/src/hooks/message";
import {getObj, addObj, putObj} from '/src/api/supermarket/shopSpu'
import {rule} from '/src/utils/validate';
const emit = defineEmits(['refresh']);
// 定义变量内容
@@ -120,33 +104,33 @@ const dataFormRef = ref();
const visible = ref(false)
const loading = ref(false)
// 定义字典
const { spu_status } = useDict('spu_status')
const {spu_status} = useDict('spu_status')
// 提交表单数据
const form = reactive({
id:'',
productCode: '',
productName: '',
description: '',
categoryId: '',
picUrl: '',
sliderPicUrls: '',
sort: 0,
status: '',
stock: 0,
giveIntegral: '',
merchantRelationId: '',
deptId: '',
shopSkuId: '',
salesCount: '',
limitNum: 0,
id: '',
productCode: '',
productName: '',
description: '',
categoryId: '',
picUrl: '',
sliderPicUrls: '',
sort: 0,
status: '',
stock: 0,
giveIntegral: '',
merchantRelationId: '',
deptId: '',
shopSkuId: '',
salesCount: '',
limitNum: 0,
});
// 定义校验规则
const dataRules = ref({
sort: [{ validator: rule.number, trigger: 'blur' }],
stock: [{ validator: rule.number, trigger: 'blur' }],
limitNum: [{ validator: rule.number, trigger: 'blur' }],
sort: [{validator: rule.number, trigger: 'blur'}],
stock: [{validator: rule.number, trigger: 'blur'}],
limitNum: [{validator: rule.number, trigger: 'blur'}],
})
// 打开弹窗
@@ -155,9 +139,9 @@ const openDialog = (id: string) => {
form.id = ''
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取shopSpu信息
if (id) {
@@ -168,18 +152,19 @@ const openDialog = (id: string) => {
// 提交
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
const valid = await dataFormRef.value.validate().catch(() => {
});
if (!valid) return false;
try {
try {
loading.value = true;
form.id ? await putObj(form) : await addObj(form);
useMessage().success(form.id ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
form.id ? await putObj(form) : await addObj(form);
useMessage().success(form.id ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
+3 -11
View File
@@ -37,26 +37,18 @@
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="productCode" label="货号" show-overflow-tooltip/>
<el-table-column prop="productName" label="商品名称" show-overflow-tooltip/>
<el-table-column prop="introduction" label="商品简介" show-overflow-tooltip/>
<el-table-column prop="description" label="商品详情" show-overflow-tooltip/>
<el-table-column prop="categoryId" label="商品分类编号" show-overflow-tooltip/>
<el-table-column prop="categoryId" label="商品分类" show-overflow-tooltip/>
<el-table-column prop="picUrl" label="商品封面图" show-overflow-tooltip/>
<el-table-column prop="sliderPicUrls" label="商品轮播图地址
数组,以逗号分隔
最多上传15张" show-overflow-tooltip/>
<el-table-column prop="sort" label="排序字段" show-overflow-tooltip/>
<el-table-column prop="status" label="商品状态: 1 上架(开启) 0 下架(禁用) -1 回收" show-overflow-tooltip>
<el-table-column prop="status" label="商品状态" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="spu_status" :value="scope.row.status"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存" show-overflow-tooltip/>
<el-table-column prop="giveIntegral" label="赠送积分" show-overflow-tooltip/>
<el-table-column prop="merchantRelationId" label="商户关系表" show-overflow-tooltip/>
<el-table-column prop="deptId" label="部门id" show-overflow-tooltip/>
<el-table-column prop="shopSkuId" label="skuid" show-overflow-tooltip/>
<el-table-column prop="salesCount" label="销量" show-overflow-tooltip/>
<el-table-column prop="limitNum" label="单人限购数量" show-overflow-tooltip/>
<el-table-column prop="limitNum" label="单人限购数" show-overflow-tooltip/>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_shopSpu_edit'"