This commit is contained in:
郭永超 2025-07-02 11:44:07 +08:00
commit 466cef50a6
8 changed files with 333 additions and 162 deletions

49
src/api/customer/index.js Normal file
View File

@ -0,0 +1,49 @@
import request from "@/utils/request";
// 获取内容列表
export function getCustomerPage(query) {
return request({
url: "/goods/customer/customerPage",
method: "get",
params: query,
});
}
//新增
export function addCustomer(data) {
return request({
url: "/goods/customer/customerAdd",
method: "post",
data: data,
});
}
//编辑
export function updateCustomer(data) {
return request({
url: "/goods/customer/customerEdit",
method: "PUT",
data: data,
});
}
// 删除
export function deleteCustomer(id) {
return request({
url: '/goods/customer/customerDelete?id=' + id,
method: "delete",
});
}
//启用停用
export function updateCustomerEnable(data) {
return request({
url: "/goods/customer/customerEnable",
method: "put",
data: data,
});
}
// 获取内容信息id
export function getInfo(id) {
return request({
url: `/goods/customer/customerInfo/${id}`,
method: "get",
});
}

View File

@ -198,7 +198,7 @@ let nowClickRow = ref({});
//
const columns = ref([
{ prop: "id", label: "ID" },
{ prop: "brandUrl", label: "品牌LOGO", slotName:'brandUrl', width: "120", align: "left" },
{ prop: "brandUrl", label: "品牌LOGO", slotName:'brandUrl', width: "120",},
{ prop: "brandTitle", label: "品牌名称" },
{ prop: "brandCode", label: "品牌编码", },
// { prop: "code", label: "", width: "120" },

View File

@ -256,7 +256,7 @@ let nowClickRow = ref({});
//
const columns = ref([
{ prop: "id", label: "ID" },
{ prop: "imgPath", label: "品牌LOGO", slotName:'imgPath', width: "120", align: "left" },
{ prop: "imgPath", label: "品牌LOGO", slotName:'imgPath', width: "120",},
{ prop: "title", label: "品牌名称" },
{ prop: "code", label: "品牌编码", width: "120" },
{ prop: "createTime", label: "时间", width: "120" },

View File

@ -204,7 +204,7 @@ let nowClickRow = ref({});
//
const columns = ref([
{ prop: "id", label: "ID" },
{ prop: "brandUrl", label: "品牌LOGO", slotName:'brandUrl', width: "120", align: "left" },
{ prop: "brandUrl", label: "品牌LOGO", slotName:'brandUrl', width: "120",},
{ prop: "brandTitle", label: "品牌名称" },
{ prop: "brandCode", label: "品牌编码", },
// { prop: "code", label: "", width: "120" },

View File

@ -12,54 +12,33 @@
class="demo-form-inline"
:label-width="'auto'"
>
<el-form-item label="ID" prop="id">
<el-input
v-model="formInline.id"
placeholder="用户ID"
clearable
/>
</el-form-item>
<el-form-item label="分类名称" prop="userCategoryName">
<el-input
v-model="formInline.userCategoryName"
placeholder="用户分类名称"
v-model="formInline.categoryName"
placeholder="分类名称"
clearable
/>
</el-form-item>
<el-form-item label="用户状态" prop="userStatus">
<el-select v-model="formInline.userStatus" placeholder="请选择" clearable>
<el-option label="异常" value="0" />
<el-option label="正常" value="1" />
<el-form-item label="状态" prop="status">
<el-select v-model="formInline.status" placeholder="请选择" clearable>
<el-option label="启用" value="1" />
<el-option label="禁用" value="0" />
</el-select>
</el-form-item>
<el-form-item
label="申请日期"
prop="startDate"
label="添加时间"
prop="createTime"
style="margin-right: 0"
>
<el-date-picker
v-model="formInline.startDate"
v-model="formInline.createTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择起始日期"
placeholder="请选择添加时间"
clearable
:disabled-date="disableStartDate"
style="width: 160px"
/>
<span
style="width: 30px; text-align: center; display: inline-block"
>
-
</span>
<el-date-picker
v-model="formInline.endDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择截止日期"
clearable
:disabled-date="disableEndDate"
style="width: 160px"
/>
</el-form-item>
</el-form>
</div>
@ -78,35 +57,55 @@
</div>
<!-- 表格 -->
<div class="table-cont" :style="{ height: tableViewportHeight + 'px' }">
<tableComponent
:table-data="tableData"
:columns="columns"
:show-border="false"
:show-selection="false"
:header-cell-class-name="getHeaderClass"
@page-change="handlePaginationChange"
@selection-change="handleSelectionChange"
:total="tableTotal" :current-page="formInline.current" :page-size="formInline.size"
>
<!-- 自定义-状态 -->
<template #userStatus="slotProps">
<span v-if="slotProps.row.userStatus == 1" class="color-green"
>正常</span
>
<span v-else-if="slotProps.row.userStatus == 0" class="color-red"
>异常</span
>
<div class="table-toolbar">
<el-button icon="delete" @click="batchDelete" :disabled="btnStatus"
style="margin-right: 10px">批量删除</el-button>
<el-button type="primary" icon="plus" @click="handleAdd">新增客户</el-button>
</div>
<tableComponent :table-data="tableData" :columns="columns" :show-border="false" :show-selection="true"
:header-cell-class-name="getHeaderClass" @page-change="handlePaginationChange" :loading="tableLoading"
@selection-change="handleSelectionChange" :total="tableTotal" :current-page="formInline.current"
:page-size="formInline.size" :showSort="true" :rowkey="'goodId'">
<!-- 自定义 - 序号 -->
<template #sort="slotProps">
<span v-if="slotProps.row.goodPrice">{{ slotProps.row.goodPrice }}</span>
</template>
<!-- 自定义-操作 -->
<!-- 自定义-状态 -->
<template #status="slotProps">
<span v-if="slotProps.row.status == 0" class="color-red">禁用</span>
<span v-else-if="slotProps.row.status == 1" class="color-green">启用</span>
</template>
<!-- 自定义-操作 -->
<template #action="slotProps">
<el-button text class="el-button-custom" @click="seeDetails(slotProps.row)">查看</el-button>
<el-button text v-if="slotProps.row.status == 0" class="el-button-custom"
@click="startStop(slotProps.row)">启用</el-button>
<el-button text v-if="slotProps.row.status == 1" class="el-button-custom"
@click="startStop(slotProps.row)">禁用</el-button>
<el-button text class="el-button-custom" @click="handleEdit(slotProps.row)">编辑</el-button>
<el-button text class="el-button-delete" @click="handleDelete(slotProps.row)">删除</el-button>
</template>
</tableComponent>
</div>
</div>
<!-- 添加/编辑商品 -->
<el-dialog v-model="dialogFormVisible" :title="dialogTitle" width="500" :close-on-click-modal="false">
<el-form :model="dialogForm" :label-width="'80'" :rules="dialogFormRules" ref="dialogRef">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="dialogForm.categoryName" autocomplete="off" placeholder="请输入分类名称" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onSaveCategory">
保存
</el-button>
<el-button @click="cancelDialog">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
@ -114,26 +113,32 @@ import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
import tableComponent from "@/components/tableComponent.vue";
import Mock from "mockjs";
import { id } from "element-plus/es/locales.mjs";
import { ElMessage } from 'element-plus'
import {getCustomerPage,addCustomer,getInfo,updateCustomer,deleteCustomer,updateCustomerEnable} from "@/api/customer/index";
import { ElMessage,ElMessageBox } from 'element-plus'
import { start } from "nprogress";
const formInline = reactive({
id: "",
nickname: "",
userName: "",
userCategoryName: "",
accountNumber: "",
phoneNumber: "",
sex: "",
userStatus: "",
userCategory: "",
unitPrice: "",
ordersNums: "",
startDate: "",
endDate: "",
categoryName: "",
createTime: "",
status: null,
current: 1,
size: 10,
});
let isADD = ref(true);
const dialogFormVisible = ref(false);
const dialogRef = ref(null);
const dialogTitle = ref("添加客户");
let dialogForm = reactive({
categoryName: "",
});
const dialogFormRules = ref({
categoryName: [
{ required: true, message: "请输入分类名称", trigger: "blur" },
]
});
//
const disableStartDate = (time) => {
if (!formInline.endDate) return false;
@ -164,94 +169,73 @@ const onSubmit = () => {
loadData();
};
const resetForm = () => {
formInline.categoryName = "";
formInline.createTime = "";
formInline.status = null;
formInline.current = 1;
formInline.size = 10;
searchForm.value.resetFields();
formInline.endDate = "";
loadData();
};
//
const tableData = ref([]);
const tableLoading = ref(false);
const tableTotal = ref(0);
let nowClickRow = ref({});
const selectedIds = ref([]);
const btnStatus = computed(() => {
return selectedIds.value.length <= 0;
});
//
const columns = ref([
{ prop: "id", label: "ID" },
{ prop: "nickname", label: "昵称", width: "120" },
{ prop: "userName", label: "姓名" },
{ prop: "accountNumber", label: "账号", width: "120" },
{ prop: "phoneNumber", label: "手机号", width: "120" },
{ prop: "sex", label: "性别" },
{ prop: "userStatus", label: "用户状态", slotName: "userStatus" },
{ prop: "userCategory", label: "用户分类" },
{ prop: "unitPrice", label: "客单价" },
{ prop: "ordersNums", label: "订单数目" },
{ prop: "categoryName", label: "分类名称" },
{ prop: "createTime", label: "添加时间" },
{ prop: "status", label: "状态", slotName: "status" },
{ prop: "action", label: "操作", slotName: "action",width: "140",align: "center" },
]);
//
const generateFoodNickname = () => {
// /
const adjectives = [
"暴躁的",
"快乐的",
"忧郁的",
"疯狂的",
"安静的",
"慵懒的",
"甜甜的",
"咸咸的",
"酸酸的",
"辣辣的",
];
//
const foods = [
"辣椒",
"西瓜",
"土豆",
"番茄",
"黄瓜",
"苹果",
"蛋糕",
"面包",
"披萨",
"冰淇淋",
"奶茶",
"咖啡",
"啤酒",
"炸鸡",
];
// +
return Mock.mock(`@pick(${adjectives})`) + Mock.mock(`@pick(${foods})`);
};
//
const generateMockData = () => {
return Mock.mock({
"list|10": [
{
"id|+1": 10000,
nickname: () => generateFoodNickname(), //
userName: "@cname", //
accountNumber: "@integer(1000000000, 9999999999)", //
phoneNumber: "@integer(13000000000, 18999999999)", //
sex: '@pick(["男", "女"])', //
"userStatus|1": [0, 1], //0 1
"userCategory|1":
'@pick(["活跃/低消费", "活跃/中消费", "活跃/高消费"])', //
unitPrice: "@float(10, 200, 2, 2)", //
ordersNums: "@integer(10, 200)",
},
],
}).list;
try {
getCustomerPage(formInline).then(res=>{
// console.log(res);
if(res.code == 200){
tableData.value = res.data.records;
tableTotal.value = res.data.total;
}
})
} catch (error) {
console.log(error);
}
// return Mock.mock({
// "list|10": [
// {
// "id|+1": 10000,
// nickname: () => generateFoodNickname(), //
// userName: "@cname", //
// accountNumber: "@integer(1000000000, 9999999999)", //
// phoneNumber: "@integer(13000000000, 18999999999)", //
// sex: '@pick(["", ""])', //
// "userStatus|1": [0, 1], //0 1
// "userCategory|1":
// '@pick(["/", "/", "/"])', //
// unitPrice: "@float(10, 200, 2, 2)", //
// ordersNums: "@integer(10, 200)",
// },
// ],
// }).list;
};
//
const loadData = () => {
// API
setTimeout(() => {
tableData.value = generateMockData();
tableTotal.value = tableData.value.length;
}, 500);
generateMockData()
// // API
// setTimeout(() => {
// tableData.value = generateMockData();
// tableTotal.value = tableData.value.length;
// }, 500);
};
// ,columnsheaderClassName: 'custom-header'
const getHeaderClass = ({ column }) => {
@ -259,29 +243,125 @@ const getHeaderClass = ({ column }) => {
};
//
const handlePaginationChange = ({ page, pageSize }) => {
console.log("分页变化:", page, pageSize);
// console.log(":", page, pageSize);
formInline.current = page;
formInline.size = pageSize;
// API
loadData();
};
//
const handleSelectionChange = (selection) => {
console.log("选中项:", selection);
// console.log(":", selection);
selectedIds.value = [];
selection.forEach(element => {
selectedIds.value.push(element.id);
});
};
//
const seeDetails = (row) => {
nowClickRow.value = row;
console.log("要查看详情的行:", row);
//
const handleAdd = () => {
dialogTitle.value = "添加客户分类";
isADD.value = true;
dialogFormVisible.value = true;
// console.log(formInline);
};
//
const handleEdit = (row) => {
nowClickRow.value = row;
console.log("要编辑的行:", row);
const handleEdit = async(row) => {
isADD.value = false;
dialogFormVisible.value = true;
let response = await getInfo(row.id);
if (response.code === 200) {
Object.assign(dialogForm, response.data); //
dialogTitle.value = "编辑客户分类";
} else {
ElMessage.error(response.message);
}
};
//
const onSaveCategory = async () => {
dialogRef.value.validate(async (valid) => {
if (valid) {
if(isADD.value){
let response = await addCustomer(dialogForm);
if (response.code === 200) {
dialogFormVisible.value = false;
ElMessage.success("新增成功!");
dialogRef.value.resetFields();
loadData();
} else {
ElMessage.error(response.message);
}
}else{
let response = await updateCustomer(dialogForm);
if (response.code === 200) {
dialogFormVisible.value = false;
ElMessage.success("编辑成功!");
dialogRef.value.resetFields();
loadData();
} else {
ElMessage.error(response.message);
}
}
}
});
};
//
const handleDelete = (row) => {
nowClickRow.value = row;
console.log("要删除的行:", row);
//
ElMessageBox.confirm("确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
let response = await deleteCustomer(row.id);
if (response.code === 200) {
ElMessage.success("删除成功!");
loadData();
} else {
ElMessage.error(response.message);
}
})
.catch(() => {
ElMessage.info("已取消删除");
})
};
//
const batchDelete = async () => {
// deleteGoods(selectedIds.value.join(","));
ElMessageBox.confirm("确定要删除选中的数据吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
deleteCustomer(selectedIds.value);
loadData();
})
.catch(() => {
ElMessage.info("已取消删除");
})
};
//
const startStop = async (row) => {
let status = row.status == 1 ? 0 : 1;
let params = { id: row.id, status: status };
let response = await updateCustomerEnable(params);
if (response.code === 200) {
ElMessage.success("操作成功!");
loadData();
} else {
ElMessage.error(response.message);
}
};
//
const cancelDialog = () => {
dialogFormVisible.value = false;
dialogRef.value?.resetFields(); //
};
const titleRef = ref(null);
@ -322,4 +402,15 @@ onBeforeUnmount(() => {
window.removeEventListener("resize", calculateTableHeight);
});
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.table-toolbar {
width: 300px;
height: 50px;
position: absolute;
right: 0;
top: 0;
display: flex;
justify-content: end;
padding: 14px 16px 0 0;
}
</style>

View File

@ -67,6 +67,11 @@
<el-input-number v-model="formInline.stock" :min="1" :controls="false" />
</el-form-item>
<!-- 预警库存 -->
<el-form-item label="预警库存" prop="stockWarnCount" required>
<el-input-number v-model="formInline.stockWarnCount" :min="1" :controls="false" />
</el-form-item>
<!-- 净含量 -->
<el-form-item label="净含量" prop="netContent" required>
<el-input-number v-model="formInline.netContent" :min="1" :controls="false" />
@ -100,6 +105,7 @@
<div class="attr-clomn color-gray">商品规格</div>
<div class="attr-clomn200 color-gray">销售价格</div>
<div class="attr-clomn color-gray">库存数量</div>
<div class="attr-clomn color-gray">预警库存</div>
<div class="attr-clomn220 color-gray">净含量</div>
</div>
<div v-for="(item, index) in formInline.netWeight" :key="index" class="attr-row">
@ -111,6 +117,9 @@
<div class="attr-clomn">
<el-input-number v-model="item.goodStock" :min="1" :controls="false" />
</div>
<div class="attr-clomn">
<el-input-number v-model="item.stockWarnCount" :min="1" :controls="false" />
</div>
<div class="attr-clomn220 flex-left-top">
<el-input-number v-model="item.netContent" :min="1" :controls="false" />
<el-select v-model="item.unit" style="width: 80px; margin-left: 10px">
@ -241,11 +250,13 @@ const formInline = reactive({
goodSpecs: "",
salePrice: 1,//-
stock: 1,//-
stockWarnCount:1,//-
netContent: 1,//-
unit: "kg",//-
netWeight: [ //
{
goodSpecs: "",
stockWarnCount:1, //-
goodPrice: 1,
goodStock: 1,
netContent: 1,

View File

@ -67,6 +67,11 @@
<el-input-number v-model="formInline.stock" :min="1" :controls="false" />
</el-form-item>
<!-- 预警库存 -->
<el-form-item label="预警库存" prop="stockWarnCount" required>
<el-input-number v-model="formInline.stockWarnCount" :min="1" :controls="false" />
</el-form-item>
<!-- 净含量 -->
<el-form-item label="净含量" prop="netContent" required>
<el-input-number v-model="formInline.netContent" :min="1" :controls="false" />
@ -100,6 +105,7 @@
<div class="attr-clomn color-gray">商品规格</div>
<div class="attr-clomn200 color-gray">销售价格</div>
<div class="attr-clomn color-gray">库存数量</div>
<div class="attr-clomn color-gray">预警库存</div>
<div class="attr-clomn220 color-gray">净含量</div>
</div>
<div v-for="(item, index) in formInline.netWeight" :key="index" class="attr-row">
@ -111,6 +117,9 @@
<div class="attr-clomn">
<el-input-number v-model="item.goodStock" :min="1" :controls="false" />
</div>
<div class="attr-clomn">
<el-input-number v-model="item.stockWarnCount" :min="1" :controls="false" />
</div>
<div class="attr-clomn220 flex-left-top">
<el-input-number v-model="item.netContent" :min="1" :controls="false" />
<el-select v-model="item.unit" style="width: 80px; margin-left: 10px">
@ -241,11 +250,13 @@ const formInline = reactive({
goodSpecs: "",
salePrice: 1,//-
stock: 1,//-
stockWarnCount: 1,//-
netContent: 1,//-
unit: "kg",//-
netWeight: [ //
{
goodSpecs: "",
stockWarnCount:1, //-
goodPrice: 1,
goodStock: 1,
netContent: 1,

View File

@ -135,20 +135,27 @@ const resetForm = () => {
let activeCurrent = ref("1");
let bottomList = reactive([
{ title: "全部", id: "1", value: "" },
{ title: "待上架", id: "0", value: "" },
{ title: "已上架", id: "2", value: "" },
{ title: "已下架", id: "3", value: "" },
{ title: "库存告急", id: "4", value: "" },
]);
const tabChange = (Event) => {
if (Event.index == "0") {
//
formInline.type = "1";
} else if (Event.index == "1") {
//
formInline.type = "2";
} else if (Event.index == "2") {
//
formInline.type = "3";
}
console.log(Event.index);
formInline.type = bottomList[Event.index].id;
// if (Event.index == "0") {
// //
// formInline.type = "1";
// } else if (Event.index == "1") {
// //
// formInline.type = "0";
// } else if (Event.index == "2") {
// //
// formInline.type = "3";
// } else if (Event.index == "3") {
// //
// formInline.type = "4";
// }
loadData();
};
@ -364,8 +371,10 @@ const getGoodsManageCount = async () => {
let response = await getGoodManageCount();
if (response.code == 200) {
bottomList[0].value = `(${response.data?.allGoodCount ?? ""})`;
bottomList[1].value = `(${response.data?.alreadyListedCount ?? ""})`;
bottomList[2].value = `(${response.data?.removedCount ?? ""})`;
bottomList[1].value = `(${response.data?.readyListedCount ?? ""})`;
bottomList[2].value = `(${response.data?.alreadyListedCount ?? ""})`;
bottomList[3].value = `(${response.data?.removedCount ?? ""})`;
bottomList[4].value = `(${response.data?.stockWaringCount ?? ""})`;
}
} catch (error) { }
};