mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-10 19:08:58 +08:00
refactor: 四端完成 Options API → script setup + vuex → pinia 迁移
- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup> - 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录) - util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入 - 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md) - 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API - 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -216,7 +216,7 @@
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="modalVisible" title="下架操作" width="500px" :close-on-click-modal="false">
|
||||
<el-form ref="underForm" :model="underForm" label-width="100px">
|
||||
<el-form ref="underFormRef" :model="underForm" label-width="100px">
|
||||
<el-form-item label="下架原因" prop="reason">
|
||||
<el-input v-model="underForm.reason" clearable />
|
||||
</el-form-item>
|
||||
@@ -255,7 +255,7 @@
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form ref="batchAuditForm" :model="batchAuditForm" label-width="100px">
|
||||
<el-form ref="batchAuditFormRef" :model="batchAuditForm" label-width="100px">
|
||||
<el-form-item label="审核结果" prop="auth_flag">
|
||||
<el-radio-group v-model="batchAuditForm.auth_flag">
|
||||
<el-radio :value="1">审核通过</el-radio>
|
||||
@@ -278,7 +278,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="goodsGroupFlag" title="批量设置商品分组" width="420px">
|
||||
<el-form ref="goodsGroupForm" :model="goodsGroupForm" :rules="goodsGroupRule" label-width="90px">
|
||||
<el-form ref="goodsGroupFormRef" :model="goodsGroupForm" :rules="goodsGroupRule" label-width="90px">
|
||||
<el-form-item label="商品分组" prop="groupId">
|
||||
<el-select v-model="goodsGroupForm.groupId" clearable filterable style="width: 240px">
|
||||
<el-option
|
||||
@@ -298,7 +298,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, reactive, ref } from "vue";
|
||||
import {
|
||||
getGoodsListData,
|
||||
getGoodsNumerData,
|
||||
@@ -310,421 +311,423 @@ import {
|
||||
} from "@/api/goods";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { unitPrice, customRouterPush } from "@/utils/filters";
|
||||
export default {
|
||||
name: "goods",
|
||||
data() {
|
||||
return {
|
||||
id: "", //要操作的id
|
||||
loading: true, // 表单加载状态
|
||||
modalVisible: false, // 添加或编辑显示
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "create_time", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
groupId: "",
|
||||
},
|
||||
underForm: {
|
||||
// 下架原因
|
||||
reason: "",
|
||||
},
|
||||
goodsAuditForm: {
|
||||
// 商品审核表单
|
||||
auth_flag: 1,
|
||||
},
|
||||
auditModalVisible: false, // 审核弹框显示状态
|
||||
auditSubmitLoading: false,
|
||||
currentAuditGoods: null, // 当前审核的商品
|
||||
submitLoading: false, // 添加或编辑提交状态
|
||||
data: [], // 表单数据
|
||||
total: 0, // 表单数据总数
|
||||
currentStatus: "ALL",
|
||||
goodsNumerData: {},
|
||||
selectedRows: [], // 选中的行数据
|
||||
selectAll: false, // 全选状态
|
||||
batchAuditModalVisible: false, // 批量审核弹框显示状态
|
||||
batchAuditSubmitLoading: false,
|
||||
batchAuditForm: {
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
},
|
||||
goodsGroupFlag: false,
|
||||
goodsGroupLoading: false,
|
||||
goodsGroupList: [],
|
||||
goodsGroupForm: {
|
||||
groupId: ""
|
||||
},
|
||||
goodsGroupRule: {
|
||||
groupId: [{ required: true, message: "请选择商品分组", trigger: "change" }]
|
||||
}
|
||||
|
||||
defineOptions({ name: "goods" });
|
||||
|
||||
// 模板 ref(searchFormRef/underFormRef/batchAuditFormRef/goodsGroupFormRef 因与 data 同名改为 xxxRef)
|
||||
const searchFormRef = ref(null);
|
||||
const table = ref(null);
|
||||
const underFormRef = ref(null);
|
||||
const auditForm = ref(null);
|
||||
const batchAuditFormRef = ref(null);
|
||||
const goodsGroupFormRef = ref(null);
|
||||
|
||||
const id = ref(""); //要操作的id
|
||||
const loading = ref(true); // 表单加载状态
|
||||
const modalVisible = ref(false); // 添加或编辑显示
|
||||
const searchForm = reactive({
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "create_time", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
groupId: "",
|
||||
});
|
||||
const underForm = reactive({
|
||||
// 下架原因
|
||||
reason: "",
|
||||
});
|
||||
const goodsAuditForm = reactive({
|
||||
// 商品审核表单
|
||||
auth_flag: 1,
|
||||
});
|
||||
const auditModalVisible = ref(false); // 审核弹框显示状态
|
||||
const auditSubmitLoading = ref(false);
|
||||
const currentAuditGoods = ref(null); // 当前审核的商品
|
||||
const submitLoading = ref(false); // 添加或编辑提交状态
|
||||
const data = ref([]); // 表单数据
|
||||
const total = ref(0); // 表单数据总数
|
||||
const currentStatus = ref("ALL");
|
||||
const goodsNumerData = ref({});
|
||||
const selectedRows = ref([]); // 选中的行数据
|
||||
const selectAll = ref(false); // 全选状态
|
||||
const batchAuditModalVisible = ref(false); // 批量审核弹框显示状态
|
||||
const batchAuditSubmitLoading = ref(false);
|
||||
const batchAuditForm = ref({
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
});
|
||||
const goodsGroupFlag = ref(false);
|
||||
const goodsGroupLoading = ref(false);
|
||||
const goodsGroupList = ref([]);
|
||||
const goodsGroupForm = ref({
|
||||
groupId: ""
|
||||
});
|
||||
const goodsGroupRule = reactive({
|
||||
groupId: [{ required: true, message: "请选择商品分组", trigger: "change" }]
|
||||
});
|
||||
|
||||
const goodsStatusWithCount = computed(() => {
|
||||
return [
|
||||
{title: '全部', value: 'ALL'},
|
||||
{title: `出售中${goodsNumerData.value.upperGoodsNum ? '(' + goodsNumerData.value.upperGoodsNum + ')' : ''}`, value: 'UPPER'},
|
||||
{title: `仓库中${goodsNumerData.value.downGoodsNum ? '(' + goodsNumerData.value.downGoodsNum + ')' : ''}`, value: 'DOWN'},
|
||||
{title: `待审核${goodsNumerData.value.auditGoodsNum ? '(' + goodsNumerData.value.auditGoodsNum + ')' : ''}`, value: 'TOBEAUDITED'},
|
||||
{title: `审核未通过${goodsNumerData.value.refuseGoodsNum ? '(' + goodsNumerData.value.refuseGoodsNum + ')' : ''}`, value: 'REFUSE'}
|
||||
];
|
||||
});
|
||||
|
||||
function clearTableSelection() {
|
||||
table.value?.clearSelection?.();
|
||||
}
|
||||
function onStatusTabClick(tab) {
|
||||
const status = tab.paneName ?? tab.props?.name;
|
||||
goodsStatusClick(status);
|
||||
}
|
||||
function salesModelText(v) {
|
||||
if (v === "RETAIL") return "零售";
|
||||
if (v === "WHOLESALE") return "批发";
|
||||
return "其他类型";
|
||||
}
|
||||
function goodsTypeText(v) {
|
||||
if (v === "PHYSICAL_GOODS") return "实物商品";
|
||||
if (v === "VIRTUAL_GOODS") return "虚拟商品";
|
||||
if (v === "E_COUPON") return "电子卡券"; // 卡密商品
|
||||
if (v === "APPOINTMENT_GOODS") return "预约商品";
|
||||
return v || "—";
|
||||
}
|
||||
function marketEnableText(v) {
|
||||
if (v === "DOWN") return "下架";
|
||||
if (v === "UPPER") return "上架";
|
||||
return "";
|
||||
}
|
||||
function authFlagText(v) {
|
||||
if (v === "TOBEAUDITED") return "待审核";
|
||||
if (v === "PASS") return "通过";
|
||||
if (v === "REFUSE") return "拒绝";
|
||||
return "";
|
||||
}
|
||||
// 初始化数据
|
||||
function init() {
|
||||
getDataList();
|
||||
getNumberData();
|
||||
loadGoodsGroupList();
|
||||
}
|
||||
// 分页 改变页码
|
||||
function changePage(v) {
|
||||
searchForm.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
// 分页 改变页数
|
||||
function changePageSize(v) {
|
||||
searchForm.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
// 搜索
|
||||
function handleSearch() {
|
||||
searchForm.pageNumber = 1;
|
||||
searchForm.pageSize = 20;
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
// 获取数据
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
getGoodsListData(searchForm).then((res) => {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
data.value = res.result.records;
|
||||
total.value = res.result.total;
|
||||
}
|
||||
});
|
||||
}
|
||||
function getNumberData() {
|
||||
// 创建一个不包含goodsStatus字段的搜索参数
|
||||
const { goodsStatus, ...searchParams } = searchForm;
|
||||
getGoodsNumerData(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
goodsNumerData.value = res.result;
|
||||
}
|
||||
})
|
||||
}
|
||||
// 编辑
|
||||
function edit(v) {
|
||||
id.value = v.id;
|
||||
if (v.underMessage) {
|
||||
underForm.reason = v.underMessage;
|
||||
} else {
|
||||
underForm.reason = "";
|
||||
}
|
||||
modalVisible.value = true;
|
||||
}
|
||||
// 下架
|
||||
function lower() {
|
||||
const reason = underForm.reason ? underForm.reason.trim() : "";
|
||||
if (!reason) {
|
||||
ElMessage.error("下架原因不能为空");
|
||||
return;
|
||||
}
|
||||
let params = {
|
||||
goodsId: id.value,
|
||||
reason
|
||||
};
|
||||
lowGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
modalVisible.value = false;
|
||||
getDataList();
|
||||
getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
}
|
||||
// 上架
|
||||
function upper(v) {
|
||||
ElMessageBox.confirm("您确认要上架 " + v.goodsName + " ?", "确认上架", { type: "warning" }).then(() => {
|
||||
let params = {
|
||||
goodsId: v.id
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
goodsStatusWithCount() {
|
||||
return [
|
||||
{title: '全部', value: 'ALL'},
|
||||
{title: `出售中${this.goodsNumerData.upperGoodsNum ? '(' + this.goodsNumerData.upperGoodsNum + ')' : ''}`, value: 'UPPER'},
|
||||
{title: `仓库中${this.goodsNumerData.downGoodsNum ? '(' + this.goodsNumerData.downGoodsNum + ')' : ''}`, value: 'DOWN'},
|
||||
{title: `待审核${this.goodsNumerData.auditGoodsNum ? '(' + this.goodsNumerData.auditGoodsNum + ')' : ''}`, value: 'TOBEAUDITED'},
|
||||
{title: `审核未通过${this.goodsNumerData.refuseGoodsNum ? '(' + this.goodsNumerData.refuseGoodsNum + ')' : ''}`, value: 'REFUSE'}
|
||||
];
|
||||
return upGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("上架成功");
|
||||
getDataList();
|
||||
getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
//查看商品详情
|
||||
function showDetail(v) {
|
||||
customRouterPush({
|
||||
name: "goods-detail",
|
||||
query: { id: v.id },
|
||||
});
|
||||
}
|
||||
|
||||
// 商品状态筛选
|
||||
function goodsStatusClick(name) {
|
||||
if (name === "ALL" || name === "" || name === undefined || name === null) {
|
||||
delete searchForm.goodsStatus;
|
||||
currentStatus.value = "ALL";
|
||||
} else {
|
||||
searchForm.goodsStatus = name;
|
||||
currentStatus.value = name;
|
||||
}
|
||||
selectedRows.value = [];
|
||||
clearTableSelection();
|
||||
getDataList();
|
||||
}
|
||||
function examine(v, authFlag) {
|
||||
// 审核商品
|
||||
let examine = "通过";
|
||||
goodsAuditForm.authFlag = "PASS";
|
||||
if (authFlag != 1) {
|
||||
examine = "拒绝";
|
||||
goodsAuditForm.authFlag = "REFUSE";
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("您确认要审核" + examine + " " + v.goodsName + " ?", "确认审核", { type: "warning" }).then(() => {
|
||||
goodsAuditForm.goodsIds=v.id;
|
||||
let formData = new FormData();
|
||||
formData.append('goodsIds', v.id);
|
||||
formData.append('authFlag', goodsAuditForm.authFlag);
|
||||
|
||||
return authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
// 打开审核弹框
|
||||
function openAuditModal(goods) {
|
||||
currentAuditGoods.value = goods;
|
||||
goodsAuditForm.auth_flag = 1;
|
||||
goodsAuditForm.reason = '';
|
||||
auditSubmitLoading.value = false;
|
||||
auditModalVisible.value = true;
|
||||
}
|
||||
|
||||
// 提交审核
|
||||
function submitAudit() {
|
||||
if (!currentAuditGoods.value) {
|
||||
return;
|
||||
}
|
||||
auditSubmitLoading.value = true;
|
||||
const formData = new FormData();
|
||||
formData.append('goodsIds', currentAuditGoods.value.id);
|
||||
formData.append('authFlag', goodsAuditForm.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('审核成功');
|
||||
auditModalVisible.value = false;
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
unitPrice,
|
||||
clearTableSelection() {
|
||||
this.$refs.table?.clearSelection?.();
|
||||
},
|
||||
onStatusTabClick(tab) {
|
||||
const status = tab.paneName ?? tab.props?.name;
|
||||
this.goodsStatusClick(status);
|
||||
},
|
||||
salesModelText(v) {
|
||||
if (v === "RETAIL") return "零售";
|
||||
if (v === "WHOLESALE") return "批发";
|
||||
return "其他类型";
|
||||
},
|
||||
goodsTypeText(v) {
|
||||
if (v === "PHYSICAL_GOODS") return "实物商品";
|
||||
if (v === "VIRTUAL_GOODS") return "虚拟商品";
|
||||
if (v === "E_COUPON") return "电子卡券"; // 卡密商品
|
||||
if (v === "APPOINTMENT_GOODS") return "预约商品";
|
||||
return v || "—";
|
||||
},
|
||||
marketEnableText(v) {
|
||||
if (v === "DOWN") return "下架";
|
||||
if (v === "UPPER") return "上架";
|
||||
return "";
|
||||
},
|
||||
authFlagText(v) {
|
||||
if (v === "TOBEAUDITED") return "待审核";
|
||||
if (v === "PASS") return "通过";
|
||||
if (v === "REFUSE") return "拒绝";
|
||||
return "";
|
||||
},
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
this.loadGoodsGroupList();
|
||||
},
|
||||
// 分页 改变页码
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
// 分页 改变页数
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
},
|
||||
// 获取数据
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getGoodsListData(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
getNumberData() {
|
||||
// 创建一个不包含goodsStatus字段的搜索参数
|
||||
const { goodsStatus, ...searchParams } = this.searchForm;
|
||||
getGoodsNumerData(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
this.goodsNumerData = res.result;
|
||||
}
|
||||
})
|
||||
},
|
||||
// 编辑
|
||||
edit(v) {
|
||||
this.id = v.id;
|
||||
if (v.underMessage) {
|
||||
this.underForm.reason = v.underMessage;
|
||||
} else {
|
||||
this.underForm.reason = "";
|
||||
}).finally(() => {
|
||||
auditSubmitLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function onSelectionChange(selection) {
|
||||
selectedRows.value = selection;
|
||||
}
|
||||
|
||||
// 批量上架
|
||||
function batchUpper() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要上架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = selectedRows.value.map(item => item.goodsName).join('、');
|
||||
ElMessageBox.confirm(`您确认要上架以下商品吗?\n${goodsNames}`, "确认批量上架", { type: "warning" }).then(() => {
|
||||
const goodsIds = selectedRows.value.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds
|
||||
};
|
||||
|
||||
return upGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('批量上架成功');
|
||||
selectedRows.value = [];
|
||||
selectAll.value = false;
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
this.modalVisible = true;
|
||||
},
|
||||
// 下架
|
||||
lower() {
|
||||
const reason = this.underForm.reason ? this.underForm.reason.trim() : "";
|
||||
if (!reason) {
|
||||
ElMessage.error("下架原因不能为空");
|
||||
return;
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
// 批量下架
|
||||
function batchLower() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要下架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = selectedRows.value.map(item => item.goodsName).join('、');
|
||||
ElMessageBox.confirm(`您确认要下架以下商品吗?\n${goodsNames}`, "确认批量下架", { type: "warning" }).then(() => {
|
||||
const goodsIds = selectedRows.value.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds,
|
||||
reason: '批量下架操作'
|
||||
};
|
||||
|
||||
return lowGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('批量下架成功');
|
||||
selectedRows.value = [];
|
||||
selectAll.value = false;
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
let params = {
|
||||
goodsId: this.id,
|
||||
reason
|
||||
};
|
||||
lowGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.modalVisible = false;
|
||||
this.getDataList();
|
||||
this.getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
},
|
||||
// 上架
|
||||
upper(v) {
|
||||
ElMessageBox.confirm("您确认要上架 " + v.goodsName + " ?", "确认上架", { type: "warning" }).then(() => {
|
||||
let params = {
|
||||
goodsId: v.id
|
||||
};
|
||||
return upGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("上架成功");
|
||||
this.getDataList();
|
||||
this.getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
//查看商品详情
|
||||
showDetail(v) {
|
||||
customRouterPush({
|
||||
name: "goods-detail",
|
||||
query: { id: v.id },
|
||||
});
|
||||
},
|
||||
// 批量审核
|
||||
function batchAudit() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
// 商品状态筛选
|
||||
goodsStatusClick(name) {
|
||||
if (name === "ALL" || name === "" || name === undefined || name === null) {
|
||||
delete this.searchForm.goodsStatus;
|
||||
this.currentStatus = "ALL";
|
||||
} else {
|
||||
this.searchForm.goodsStatus = name;
|
||||
this.currentStatus = name;
|
||||
}
|
||||
this.selectedRows = [];
|
||||
this.clearTableSelection();
|
||||
this.getDataList();
|
||||
},
|
||||
examine(v, authFlag) {
|
||||
// 审核商品
|
||||
let examine = "通过";
|
||||
this.goodsAuditForm.authFlag = "PASS";
|
||||
if (authFlag != 1) {
|
||||
examine = "拒绝";
|
||||
this.goodsAuditForm.authFlag = "REFUSE";
|
||||
}
|
||||
// 重置批量审核表单
|
||||
batchAuditForm.value = {
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
};
|
||||
batchAuditModalVisible.value = true;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("您确认要审核" + examine + " " + v.goodsName + " ?", "确认审核", { type: "warning" }).then(() => {
|
||||
this.goodsAuditForm.goodsIds=v.id;
|
||||
let formData = new FormData();
|
||||
formData.append('goodsIds', v.id);
|
||||
formData.append('authFlag', this.goodsAuditForm.authFlag);
|
||||
// 提交批量审核
|
||||
function submitBatchAudit() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
return authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
// 如果是拒绝审核,必须填写原因
|
||||
if (batchAuditForm.value.auth_flag === 2 && !batchAuditForm.value.reason.trim()) {
|
||||
ElMessage.warning('审核拒绝时必须填写拒绝原因');
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开审核弹框
|
||||
openAuditModal(goods) {
|
||||
this.currentAuditGoods = goods;
|
||||
this.goodsAuditForm.auth_flag = 1;
|
||||
this.goodsAuditForm.reason = '';
|
||||
this.auditSubmitLoading = false;
|
||||
this.auditModalVisible = true;
|
||||
},
|
||||
const actionText = batchAuditForm.value.auth_flag === 1 ? '通过' : '拒绝';
|
||||
const goodsIds = selectedRows.value.map(item => item.id);
|
||||
const formData = new FormData();
|
||||
formData.append('goodsIds', goodsIds.join(','));
|
||||
formData.append('authFlag', batchAuditForm.value.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
if (batchAuditForm.value.reason) {
|
||||
formData.append('reason', batchAuditForm.value.reason);
|
||||
}
|
||||
|
||||
// 提交审核
|
||||
submitAudit() {
|
||||
if (!this.currentAuditGoods) {
|
||||
return;
|
||||
}
|
||||
this.auditSubmitLoading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('goodsIds', this.currentAuditGoods.id);
|
||||
formData.append('authFlag', this.goodsAuditForm.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('审核成功');
|
||||
this.auditModalVisible = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.auditSubmitLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
onSelectionChange(selection) {
|
||||
this.selectedRows = selection;
|
||||
},
|
||||
|
||||
// 批量上架
|
||||
batchUpper() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
ElMessage.warning('请先选择要上架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = this.selectedRows.map(item => item.goodsName).join('、');
|
||||
ElMessageBox.confirm(`您确认要上架以下商品吗?\n${goodsNames}`, "确认批量上架", { type: "warning" }).then(() => {
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds
|
||||
};
|
||||
|
||||
return upGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('批量上架成功');
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
// 批量下架
|
||||
batchLower() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
ElMessage.warning('请先选择要下架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = this.selectedRows.map(item => item.goodsName).join('、');
|
||||
ElMessageBox.confirm(`您确认要下架以下商品吗?\n${goodsNames}`, "确认批量下架", { type: "warning" }).then(() => {
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds,
|
||||
reason: '批量下架操作'
|
||||
};
|
||||
|
||||
return lowGoods(params).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success('批量下架成功');
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
// 批量审核
|
||||
batchAudit() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
// 重置批量审核表单
|
||||
this.batchAuditForm = {
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
};
|
||||
this.batchAuditModalVisible = true;
|
||||
},
|
||||
|
||||
// 提交批量审核
|
||||
submitBatchAudit() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是拒绝审核,必须填写原因
|
||||
if (this.batchAuditForm.auth_flag === 2 && !this.batchAuditForm.reason.trim()) {
|
||||
ElMessage.warning('审核拒绝时必须填写拒绝原因');
|
||||
return;
|
||||
}
|
||||
|
||||
const actionText = this.batchAuditForm.auth_flag === 1 ? '通过' : '拒绝';
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
const formData = new FormData();
|
||||
formData.append('goodsIds', goodsIds.join(','));
|
||||
formData.append('authFlag', this.batchAuditForm.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
if (this.batchAuditForm.reason) {
|
||||
formData.append('reason', this.batchAuditForm.reason);
|
||||
}
|
||||
|
||||
this.batchAuditSubmitLoading = true;
|
||||
authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success(`批量审核${actionText}成功`);
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.batchAuditModalVisible = false;
|
||||
this.clearTableSelection();
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.batchAuditSubmitLoading = false;
|
||||
});
|
||||
},
|
||||
loadGoodsGroupList() {
|
||||
getGoodsGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.goodsGroupList = res.result.records || [];
|
||||
}
|
||||
});
|
||||
},
|
||||
openSetGoodsGroup() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
ElMessage.warning("请先选择商品");
|
||||
return;
|
||||
}
|
||||
this.goodsGroupFlag = true;
|
||||
this.goodsGroupLoading = false;
|
||||
this.goodsGroupForm = { groupId: "" };
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsGroupForm) this.$refs.goodsGroupForm.resetFields();
|
||||
});
|
||||
this.loadGoodsGroupList();
|
||||
},
|
||||
submitSetGoodsGroup() {
|
||||
this.$refs.goodsGroupForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
const goodsIds = this.selectedRows.map((item) => item.id);
|
||||
this.goodsGroupLoading = true;
|
||||
addGoodsGroupItems(this.goodsGroupForm.groupId, goodsIds).then((res) => {
|
||||
this.goodsGroupLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("设置成功");
|
||||
this.goodsGroupFlag = false;
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.clearTableSelection();
|
||||
this.getDataList();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.goodsGroupLoading = false;
|
||||
ElMessage.error("设置失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
batchAuditSubmitLoading.value = true;
|
||||
authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success(`批量审核${actionText}成功`);
|
||||
selectedRows.value = [];
|
||||
selectAll.value = false;
|
||||
batchAuditModalVisible.value = false;
|
||||
clearTableSelection();
|
||||
getDataList();
|
||||
getNumberData();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
}).finally(() => {
|
||||
batchAuditSubmitLoading.value = false;
|
||||
});
|
||||
}
|
||||
function loadGoodsGroupList() {
|
||||
getGoodsGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
goodsGroupList.value = res.result.records || [];
|
||||
}
|
||||
});
|
||||
}
|
||||
function openSetGoodsGroup() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning("请先选择商品");
|
||||
return;
|
||||
}
|
||||
goodsGroupFlag.value = true;
|
||||
goodsGroupLoading.value = false;
|
||||
goodsGroupForm.value = { groupId: "" };
|
||||
nextTick(() => {
|
||||
if (goodsGroupFormRef.value) goodsGroupFormRef.value.resetFields();
|
||||
});
|
||||
loadGoodsGroupList();
|
||||
}
|
||||
function submitSetGoodsGroup() {
|
||||
goodsGroupFormRef.value.validate((valid) => {
|
||||
if (!valid) return;
|
||||
const goodsIds = selectedRows.value.map((item) => item.id);
|
||||
goodsGroupLoading.value = true;
|
||||
addGoodsGroupItems(goodsGroupForm.value.groupId, goodsIds).then((res) => {
|
||||
goodsGroupLoading.value = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("设置成功");
|
||||
goodsGroupFlag.value = false;
|
||||
selectedRows.value = [];
|
||||
selectAll.value = false;
|
||||
clearTableSelection();
|
||||
getDataList();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
}).catch(() => {
|
||||
goodsGroupLoading.value = false;
|
||||
ElMessage.error("设置失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
// Tab组件样式
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -87,104 +87,103 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { authGoods, getAuthGoodsListData } from "@/api/goods";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { unitPrice, customRouterPush } from "@/utils/filters";
|
||||
|
||||
export default {
|
||||
name: "goodsApply",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
},
|
||||
goodsAuditForm: {
|
||||
auth_flag: 1,
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
unitPrice,
|
||||
authFlagText(v) {
|
||||
const map = {
|
||||
TOBEAUDITED: "待审核",
|
||||
PASS: "审核通过",
|
||||
REFUSE: "审核拒绝",
|
||||
};
|
||||
return map[v] || v || "-";
|
||||
},
|
||||
authFlagTagType(v) {
|
||||
const map = {
|
||||
TOBEAUDITED: "warning",
|
||||
PASS: "success",
|
||||
REFUSE: "danger",
|
||||
};
|
||||
return map[v] || "info";
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
this.searchForm.authFlag = 0;
|
||||
getAuthGoodsListData(this.searchForm)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
examine(v, authFlag) {
|
||||
const examine = authFlag === 1 ? "通过" : "拒绝";
|
||||
this.goodsAuditForm.authFlag = authFlag === 1 ? "PASS" : "REFUSE";
|
||||
ElMessageBox.confirm(`您确认要审核${examine} ${v.goodsName} ?`, "确认审核", { type: "warning" }).then(() => {
|
||||
const formData = new FormData();
|
||||
formData.append("goodsIds", v.id);
|
||||
formData.append("authFlag", this.goodsAuditForm.authFlag);
|
||||
return authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
showDetail(v) {
|
||||
customRouterPush({
|
||||
name: "goods-detail",
|
||||
query: { id: v.id },
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
defineOptions({ name: "goodsApply" });
|
||||
|
||||
// 模板中 el-form 的 ref 与数据 searchForm 同名,避免相互覆盖改名
|
||||
const searchFormRef = ref(null);
|
||||
const table = ref(null);
|
||||
|
||||
const loading = ref(true);
|
||||
const searchForm = ref({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
});
|
||||
const goodsAuditForm = ref({
|
||||
auth_flag: 1,
|
||||
});
|
||||
const data = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
function authFlagText(v) {
|
||||
const map = {
|
||||
TOBEAUDITED: "待审核",
|
||||
PASS: "审核通过",
|
||||
REFUSE: "审核拒绝",
|
||||
};
|
||||
return map[v] || v || "-";
|
||||
}
|
||||
function authFlagTagType(v) {
|
||||
const map = {
|
||||
TOBEAUDITED: "warning",
|
||||
PASS: "success",
|
||||
REFUSE: "danger",
|
||||
};
|
||||
return map[v] || "info";
|
||||
}
|
||||
function init() {
|
||||
getDataList();
|
||||
}
|
||||
function changePage(v) {
|
||||
searchForm.value.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
function changePageSize(v) {
|
||||
searchForm.value.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
function handleSearch() {
|
||||
searchForm.value.pageNumber = 1;
|
||||
searchForm.value.pageSize = 20;
|
||||
getDataList();
|
||||
}
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
searchForm.value.authFlag = 0;
|
||||
getAuthGoodsListData(searchForm.value)
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
data.value = res.result.records;
|
||||
total.value = res.result.total;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
function examine(v, authFlag) {
|
||||
const examine = authFlag === 1 ? "通过" : "拒绝";
|
||||
goodsAuditForm.value.authFlag = authFlag === 1 ? "PASS" : "REFUSE";
|
||||
ElMessageBox.confirm(`您确认要审核${examine} ${v.goodsName} ?`, "确认审核", { type: "warning" }).then(() => {
|
||||
const formData = new FormData();
|
||||
formData.append("goodsIds", v.id);
|
||||
formData.append("authFlag", goodsAuditForm.value.authFlag);
|
||||
return authGoods(formData).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
getDataList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
function showDetail(v) {
|
||||
customRouterPush({
|
||||
name: "goods-detail",
|
||||
query: { id: v.id },
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -376,307 +376,304 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, reactive, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { View } from "@element-plus/icons-vue";
|
||||
import { authGoods, getBrandListData, getGoodsDetail } from "@/api/goods";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
export default {
|
||||
name: "goodsDetail",
|
||||
components: { View },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
goods: {},
|
||||
brandList: [],
|
||||
previewGoodsPicture: "",
|
||||
goodsPictureVisible: false,
|
||||
wholesaleData: [],
|
||||
skuData: [],
|
||||
activeTab: "basic",
|
||||
slotCapacityVisible: false,
|
||||
currentSlotCapacities: [],
|
||||
goodsAuditForm: {
|
||||
auth_flag: 1,
|
||||
},
|
||||
auditModalVisible: false,
|
||||
auditSubmitLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isAppointmentGoods() {
|
||||
return this.goods.goodsType === "APPOINTMENT_GOODS";
|
||||
},
|
||||
needsLogistics() {
|
||||
return this.goods.goodsType === "PHYSICAL_GOODS";
|
||||
},
|
||||
salesModelDisplayText() {
|
||||
const type = this.goods.goodsType;
|
||||
const model = this.goods.salesModel;
|
||||
if (type === "APPOINTMENT_GOODS") return "预约型";
|
||||
if (type === "E_COUPON") return "电子卡券";
|
||||
if (type === "VIRTUAL_GOODS") return "虚拟型";
|
||||
if (model === "WHOLESALE") return "批发型";
|
||||
if (model === "RETAIL") return "零售型";
|
||||
return model || "—";
|
||||
},
|
||||
sectionTabs() {
|
||||
const tabs = [
|
||||
{ name: "basic", label: "基础信息" },
|
||||
{ name: "media", label: "图文信息" },
|
||||
];
|
||||
if (this.isAppointmentGoods) {
|
||||
tabs.push({ name: "appointment", label: "预约规则" });
|
||||
}
|
||||
tabs.push(
|
||||
{ name: "price", label: "价格库存" },
|
||||
{ name: "other", label: "其他信息" },
|
||||
);
|
||||
return tabs;
|
||||
},
|
||||
categoryText() {
|
||||
const names = this.goods.categoryName;
|
||||
if (!names || !names.length) return "—";
|
||||
return names.join(" > ");
|
||||
},
|
||||
/** 兼容扁平列表与历史嵌套分组两种 params 结构 */
|
||||
displayGoodsParams() {
|
||||
let list = this.goods.goodsParamsDTOList;
|
||||
if ((!Array.isArray(list) || !list.length) && this.goods.params) {
|
||||
list = this.parseParamsJson(this.goods.params);
|
||||
}
|
||||
if (!Array.isArray(list) || !list.length) return [];
|
||||
const flat = [];
|
||||
list.forEach((item) => {
|
||||
if (Array.isArray(item?.goodsParamsItemDTOList) && item.goodsParamsItemDTOList.length) {
|
||||
item.goodsParamsItemDTOList.forEach((child) => {
|
||||
if (child?.paramName) flat.push(child);
|
||||
});
|
||||
} else if (item?.paramName) {
|
||||
flat.push(item);
|
||||
}
|
||||
defineOptions({ name: "goodsDetail" });
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const loading = ref(false);
|
||||
const goods = ref({});
|
||||
const brandList = ref([]);
|
||||
const previewGoodsPicture = ref("");
|
||||
const goodsPictureVisible = ref(false);
|
||||
const wholesaleData = ref([]);
|
||||
const skuData = ref([]);
|
||||
const activeTab = ref("basic");
|
||||
const slotCapacityVisible = ref(false);
|
||||
const currentSlotCapacities = ref([]);
|
||||
const goodsAuditForm = reactive({
|
||||
auth_flag: 1,
|
||||
});
|
||||
const auditModalVisible = ref(false);
|
||||
const auditSubmitLoading = ref(false);
|
||||
|
||||
const isAppointmentGoods = computed(() => {
|
||||
return goods.value.goodsType === "APPOINTMENT_GOODS";
|
||||
});
|
||||
const needsLogistics = computed(() => {
|
||||
return goods.value.goodsType === "PHYSICAL_GOODS";
|
||||
});
|
||||
const salesModelDisplayText = computed(() => {
|
||||
const type = goods.value.goodsType;
|
||||
const model = goods.value.salesModel;
|
||||
if (type === "APPOINTMENT_GOODS") return "预约型";
|
||||
if (type === "E_COUPON") return "电子卡券";
|
||||
if (type === "VIRTUAL_GOODS") return "虚拟型";
|
||||
if (model === "WHOLESALE") return "批发型";
|
||||
if (model === "RETAIL") return "零售型";
|
||||
return model || "—";
|
||||
});
|
||||
const sectionTabs = computed(() => {
|
||||
const tabs = [
|
||||
{ name: "basic", label: "基础信息" },
|
||||
{ name: "media", label: "图文信息" },
|
||||
];
|
||||
if (isAppointmentGoods.value) {
|
||||
tabs.push({ name: "appointment", label: "预约规则" });
|
||||
}
|
||||
tabs.push(
|
||||
{ name: "price", label: "价格库存" },
|
||||
{ name: "other", label: "其他信息" },
|
||||
);
|
||||
return tabs;
|
||||
});
|
||||
const categoryText = computed(() => {
|
||||
const names = goods.value.categoryName;
|
||||
if (!names || !names.length) return "—";
|
||||
return names.join(" > ");
|
||||
});
|
||||
/** 兼容扁平列表与历史嵌套分组两种 params 结构 */
|
||||
const displayGoodsParams = computed(() => {
|
||||
let list = goods.value.goodsParamsDTOList;
|
||||
if ((!Array.isArray(list) || !list.length) && goods.value.params) {
|
||||
list = parseParamsJson(goods.value.params);
|
||||
}
|
||||
if (!Array.isArray(list) || !list.length) return [];
|
||||
const flat = [];
|
||||
list.forEach((item) => {
|
||||
if (Array.isArray(item?.goodsParamsItemDTOList) && item.goodsParamsItemDTOList.length) {
|
||||
item.goodsParamsItemDTOList.forEach((child) => {
|
||||
if (child?.paramName) flat.push(child);
|
||||
});
|
||||
return flat;
|
||||
},
|
||||
appointmentSettings() {
|
||||
return this.goods.appointmentSettings || null;
|
||||
},
|
||||
appointmentSlotTemplate() {
|
||||
return this.goods.appointmentSlotTemplate || null;
|
||||
},
|
||||
appointmentSlots() {
|
||||
return this.appointmentSlotTemplate?.slots || [];
|
||||
},
|
||||
bookableDateText() {
|
||||
const s = this.appointmentSettings;
|
||||
if (!s) return "—";
|
||||
if (s.bookableDateMode === "CUSTOM") {
|
||||
const parts = [];
|
||||
if (s.bookableCustomStartDate && s.bookableCustomEndDate) {
|
||||
parts.push(`${s.bookableCustomStartDate} ~ ${s.bookableCustomEndDate}`);
|
||||
}
|
||||
const weekdays = this.formatWeekdays(s.bookableWeekdays);
|
||||
if (weekdays) parts.push(weekdays);
|
||||
return parts.length ? parts.join(";") : "自定义";
|
||||
} else if (item?.paramName) {
|
||||
flat.push(item);
|
||||
}
|
||||
});
|
||||
return flat;
|
||||
});
|
||||
const appointmentSettings = computed(() => {
|
||||
return goods.value.appointmentSettings || null;
|
||||
});
|
||||
const appointmentSlotTemplate = computed(() => {
|
||||
return goods.value.appointmentSlotTemplate || null;
|
||||
});
|
||||
const appointmentSlots = computed(() => {
|
||||
return appointmentSlotTemplate.value?.slots || [];
|
||||
});
|
||||
const bookableDateText = computed(() => {
|
||||
const s = appointmentSettings.value;
|
||||
if (!s) return "—";
|
||||
if (s.bookableDateMode === "CUSTOM") {
|
||||
const parts = [];
|
||||
if (s.bookableCustomStartDate && s.bookableCustomEndDate) {
|
||||
parts.push(`${s.bookableCustomStartDate} ~ ${s.bookableCustomEndDate}`);
|
||||
}
|
||||
const weekdays = formatWeekdays(s.bookableWeekdays);
|
||||
if (weekdays) parts.push(weekdays);
|
||||
return parts.length ? parts.join(";") : "自定义";
|
||||
}
|
||||
if (s.bookableDateMode === "EVERY_DAY") return "每天";
|
||||
return "—";
|
||||
});
|
||||
const bookableDaysText = computed(() => {
|
||||
const s = appointmentSettings.value;
|
||||
if (!s || s.bookableDays == null) return "—";
|
||||
return `对用户展示 ${s.bookableDays} 天内的可预约日期`;
|
||||
});
|
||||
const advanceBookingText = computed(() => {
|
||||
const s = appointmentSettings.value;
|
||||
if (!s) return "—";
|
||||
if (s.advanceMode === "NONE") return "无需提前预约";
|
||||
if (s.advanceMode === "REQUIRE_HOURS" && s.advanceHours != null) {
|
||||
return `需提前 ${s.advanceHours} 小时进行预约`;
|
||||
}
|
||||
return "—";
|
||||
});
|
||||
const cancelRuleText = computed(() => {
|
||||
const s = appointmentSettings.value;
|
||||
if (!s) return "—";
|
||||
if (s.cancelMode === "NOT_ALLOWED") return "不允许取消";
|
||||
if (s.cancelMode === "ALLOW_BEFORE_HOURS" && s.cancelAheadHours != null) {
|
||||
return `服务开始 ${s.cancelAheadHours} 小时之前,允许取消并自动退款`;
|
||||
}
|
||||
return "—";
|
||||
});
|
||||
const formSubmitText = computed(() => {
|
||||
const s = appointmentSettings.value;
|
||||
if (!s) return "—";
|
||||
if (s.formSubmitMode === "PER_APPOINTMENT") return "每个预约提交一次";
|
||||
if (s.formSubmitMode === "PER_ORDER") return "每单提交一次";
|
||||
return "—";
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
loadBrandList();
|
||||
initGoods(route.query.id);
|
||||
});
|
||||
|
||||
function sectionNo(name) {
|
||||
const index = sectionTabs.value.findIndex((tab) => tab.name === name);
|
||||
return index >= 0 ? index + 1 : "";
|
||||
}
|
||||
function parseParamsJson(paramsJson) {
|
||||
if (!paramsJson) return [];
|
||||
try {
|
||||
const array = JSON.parse(paramsJson);
|
||||
if (!Array.isArray(array)) return [];
|
||||
const items = [];
|
||||
array.forEach((element) => {
|
||||
if (Array.isArray(element?.goodsParamsItemDTOList)) {
|
||||
items.push(...element.goodsParamsItemDTOList);
|
||||
} else if (element?.paramName) {
|
||||
items.push(element);
|
||||
}
|
||||
if (s.bookableDateMode === "EVERY_DAY") return "每天";
|
||||
return "—";
|
||||
},
|
||||
bookableDaysText() {
|
||||
const s = this.appointmentSettings;
|
||||
if (!s || s.bookableDays == null) return "—";
|
||||
return `对用户展示 ${s.bookableDays} 天内的可预约日期`;
|
||||
},
|
||||
advanceBookingText() {
|
||||
const s = this.appointmentSettings;
|
||||
if (!s) return "—";
|
||||
if (s.advanceMode === "NONE") return "无需提前预约";
|
||||
if (s.advanceMode === "REQUIRE_HOURS" && s.advanceHours != null) {
|
||||
return `需提前 ${s.advanceHours} 小时进行预约`;
|
||||
}
|
||||
return "—";
|
||||
},
|
||||
cancelRuleText() {
|
||||
const s = this.appointmentSettings;
|
||||
if (!s) return "—";
|
||||
if (s.cancelMode === "NOT_ALLOWED") return "不允许取消";
|
||||
if (s.cancelMode === "ALLOW_BEFORE_HOURS" && s.cancelAheadHours != null) {
|
||||
return `服务开始 ${s.cancelAheadHours} 小时之前,允许取消并自动退款`;
|
||||
}
|
||||
return "—";
|
||||
},
|
||||
formSubmitText() {
|
||||
const s = this.appointmentSettings;
|
||||
if (!s) return "—";
|
||||
if (s.formSubmitMode === "PER_APPOINTMENT") return "每个预约提交一次";
|
||||
if (s.formSubmitMode === "PER_ORDER") return "每单提交一次";
|
||||
return "—";
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadBrandList();
|
||||
this.initGoods(this.$route.query.id);
|
||||
},
|
||||
methods: {
|
||||
sectionNo(name) {
|
||||
const index = this.sectionTabs.findIndex((tab) => tab.name === name);
|
||||
return index >= 0 ? index + 1 : "";
|
||||
},
|
||||
parseParamsJson(paramsJson) {
|
||||
if (!paramsJson) return [];
|
||||
try {
|
||||
const array = JSON.parse(paramsJson);
|
||||
if (!Array.isArray(array)) return [];
|
||||
const items = [];
|
||||
array.forEach((element) => {
|
||||
if (Array.isArray(element?.goodsParamsItemDTOList)) {
|
||||
items.push(...element.goodsParamsItemDTOList);
|
||||
} else if (element?.paramName) {
|
||||
items.push(element);
|
||||
}
|
||||
});
|
||||
return items;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
jumpToTab(name) {
|
||||
this.activeTab = name;
|
||||
this.$nextTick(() => {
|
||||
const el = document.getElementById(`goods-section-${name}`);
|
||||
el?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
});
|
||||
},
|
||||
loadBrandList() {
|
||||
getBrandListData().then((res) => {
|
||||
this.brandList = Array.isArray(res) ? res : res?.result || [];
|
||||
});
|
||||
},
|
||||
initGoods(id) {
|
||||
if (!id) return;
|
||||
this.loading = true;
|
||||
getGoodsDetail(id)
|
||||
.then((res) => {
|
||||
if (!res?.success) return;
|
||||
this.goods = res.result || {};
|
||||
this.skuData = (res.result?.skuList || []).map((sku) => ({
|
||||
id: sku.id,
|
||||
specs: sku.simpleSpecs || sku.goodsName,
|
||||
sn: sku.sn,
|
||||
weight: sku.weight,
|
||||
price: sku.price,
|
||||
image: sku.goodsGalleryList,
|
||||
quantity: sku.quantity,
|
||||
slotCapacities: sku.slotCapacities,
|
||||
}));
|
||||
this.wholesaleData = res.result?.wholesaleList || [];
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
brandText(brandId) {
|
||||
if (!brandId || brandId === "0") return "—";
|
||||
const brand = this.brandList.find((item) => String(item.id) === String(brandId));
|
||||
return brand?.name || brandId;
|
||||
},
|
||||
goodsTypeText(v) {
|
||||
if (v === "PHYSICAL_GOODS") return "实物商品";
|
||||
if (v === "VIRTUAL_GOODS") return "虚拟商品";
|
||||
if (v === "E_COUPON") return "电子卡券";
|
||||
if (v === "APPOINTMENT_GOODS") return "预约商品";
|
||||
return v || "—";
|
||||
},
|
||||
normalizeSlotCapacities(caps) {
|
||||
if (!Array.isArray(caps) || !caps.length) return [];
|
||||
return caps.map((item) => ({
|
||||
startTime: item.startTime || "",
|
||||
endTime: item.endTime || "",
|
||||
capacity: item.slotCapacity ?? item.capacity ?? 0,
|
||||
});
|
||||
return items;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
function jumpToTab(name) {
|
||||
activeTab.value = name;
|
||||
nextTick(() => {
|
||||
const el = document.getElementById(`goods-section-${name}`);
|
||||
el?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
});
|
||||
}
|
||||
function loadBrandList() {
|
||||
getBrandListData().then((res) => {
|
||||
brandList.value = Array.isArray(res) ? res : res?.result || [];
|
||||
});
|
||||
}
|
||||
function initGoods(id) {
|
||||
if (!id) return;
|
||||
loading.value = true;
|
||||
getGoodsDetail(id)
|
||||
.then((res) => {
|
||||
if (!res?.success) return;
|
||||
goods.value = res.result || {};
|
||||
skuData.value = (res.result?.skuList || []).map((sku) => ({
|
||||
id: sku.id,
|
||||
specs: sku.simpleSpecs || sku.goodsName,
|
||||
sn: sku.sn,
|
||||
weight: sku.weight,
|
||||
price: sku.price,
|
||||
image: sku.goodsGalleryList,
|
||||
quantity: sku.quantity,
|
||||
slotCapacities: sku.slotCapacities,
|
||||
}));
|
||||
},
|
||||
hasSlotCapacities(row) {
|
||||
return this.slotCapacityCount(row) > 0;
|
||||
},
|
||||
slotCapacityCount(row) {
|
||||
return this.normalizeSlotCapacities(row?.slotCapacities).length;
|
||||
},
|
||||
openSlotCapacityDialog(row) {
|
||||
this.currentSlotCapacities = this.normalizeSlotCapacities(row?.slotCapacities);
|
||||
this.slotCapacityVisible = true;
|
||||
},
|
||||
formatSlotCapacity(capacity) {
|
||||
const value = Number(capacity);
|
||||
if (!value) return "不限制";
|
||||
return String(value);
|
||||
},
|
||||
marketEnableText(v) {
|
||||
if (v === "UPPER") return "上架";
|
||||
if (v === "DOWN") return "下架";
|
||||
return "—";
|
||||
},
|
||||
authFlagText(v) {
|
||||
if (v === "TOBEAUDITED") return "待审核";
|
||||
if (v === "PASS") return "通过";
|
||||
if (v === "REFUSE") return "拒绝";
|
||||
return v || "—";
|
||||
},
|
||||
authFlagTagType(v) {
|
||||
if (v === "PASS") return "success";
|
||||
if (v === "TOBEAUDITED") return "warning";
|
||||
if (v === "REFUSE") return "danger";
|
||||
return "info";
|
||||
},
|
||||
formatServiceModes(modes) {
|
||||
if (!modes || !modes.length) return "—";
|
||||
const map = {
|
||||
IN_STORE: "到店服务",
|
||||
ON_SITE: "上门服务",
|
||||
};
|
||||
return modes.map((m) => map[m] || m).join("、");
|
||||
},
|
||||
formatWeekdays(weekdays) {
|
||||
if (!Array.isArray(weekdays) || !weekdays.length) return "";
|
||||
const map = {
|
||||
1: "周一",
|
||||
2: "周二",
|
||||
3: "周三",
|
||||
4: "周四",
|
||||
5: "周五",
|
||||
6: "周六",
|
||||
7: "周日",
|
||||
};
|
||||
return weekdays.map((d) => map[d] || d).join("、");
|
||||
},
|
||||
handleViewGoodsPicture(url) {
|
||||
this.previewGoodsPicture = url;
|
||||
this.goodsPictureVisible = true;
|
||||
},
|
||||
openAuditModal() {
|
||||
this.goodsAuditForm.auth_flag = 1;
|
||||
this.auditSubmitLoading = false;
|
||||
this.auditModalVisible = true;
|
||||
},
|
||||
submitAudit() {
|
||||
if (!this.goods.id) return;
|
||||
this.auditSubmitLoading = true;
|
||||
const formData = new FormData();
|
||||
formData.append("goodsIds", this.goods.id);
|
||||
formData.append("authFlag", this.goodsAuditForm.auth_flag === 1 ? "PASS" : "REFUSE");
|
||||
authGoods(formData)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
this.auditModalVisible = false;
|
||||
this.initGoods(this.goods.id);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.auditSubmitLoading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
wholesaleData.value = res.result?.wholesaleList || [];
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
function brandText(brandId) {
|
||||
if (!brandId || brandId === "0") return "—";
|
||||
const brand = brandList.value.find((item) => String(item.id) === String(brandId));
|
||||
return brand?.name || brandId;
|
||||
}
|
||||
function goodsTypeText(v) {
|
||||
if (v === "PHYSICAL_GOODS") return "实物商品";
|
||||
if (v === "VIRTUAL_GOODS") return "虚拟商品";
|
||||
if (v === "E_COUPON") return "电子卡券";
|
||||
if (v === "APPOINTMENT_GOODS") return "预约商品";
|
||||
return v || "—";
|
||||
}
|
||||
function normalizeSlotCapacities(caps) {
|
||||
if (!Array.isArray(caps) || !caps.length) return [];
|
||||
return caps.map((item) => ({
|
||||
startTime: item.startTime || "",
|
||||
endTime: item.endTime || "",
|
||||
capacity: item.slotCapacity ?? item.capacity ?? 0,
|
||||
}));
|
||||
}
|
||||
function hasSlotCapacities(row) {
|
||||
return slotCapacityCount(row) > 0;
|
||||
}
|
||||
function slotCapacityCount(row) {
|
||||
return normalizeSlotCapacities(row?.slotCapacities).length;
|
||||
}
|
||||
function openSlotCapacityDialog(row) {
|
||||
currentSlotCapacities.value = normalizeSlotCapacities(row?.slotCapacities);
|
||||
slotCapacityVisible.value = true;
|
||||
}
|
||||
function formatSlotCapacity(capacity) {
|
||||
const value = Number(capacity);
|
||||
if (!value) return "不限制";
|
||||
return String(value);
|
||||
}
|
||||
function marketEnableText(v) {
|
||||
if (v === "UPPER") return "上架";
|
||||
if (v === "DOWN") return "下架";
|
||||
return "—";
|
||||
}
|
||||
function authFlagText(v) {
|
||||
if (v === "TOBEAUDITED") return "待审核";
|
||||
if (v === "PASS") return "通过";
|
||||
if (v === "REFUSE") return "拒绝";
|
||||
return v || "—";
|
||||
}
|
||||
function authFlagTagType(v) {
|
||||
if (v === "PASS") return "success";
|
||||
if (v === "TOBEAUDITED") return "warning";
|
||||
if (v === "REFUSE") return "danger";
|
||||
return "info";
|
||||
}
|
||||
function formatServiceModes(modes) {
|
||||
if (!modes || !modes.length) return "—";
|
||||
const map = {
|
||||
IN_STORE: "到店服务",
|
||||
ON_SITE: "上门服务",
|
||||
};
|
||||
return modes.map((m) => map[m] || m).join("、");
|
||||
}
|
||||
function formatWeekdays(weekdays) {
|
||||
if (!Array.isArray(weekdays) || !weekdays.length) return "";
|
||||
const map = {
|
||||
1: "周一",
|
||||
2: "周二",
|
||||
3: "周三",
|
||||
4: "周四",
|
||||
5: "周五",
|
||||
6: "周六",
|
||||
7: "周日",
|
||||
};
|
||||
return weekdays.map((d) => map[d] || d).join("、");
|
||||
}
|
||||
function handleViewGoodsPicture(url) {
|
||||
previewGoodsPicture.value = url;
|
||||
goodsPictureVisible.value = true;
|
||||
}
|
||||
function openAuditModal() {
|
||||
goodsAuditForm.auth_flag = 1;
|
||||
auditSubmitLoading.value = false;
|
||||
auditModalVisible.value = true;
|
||||
}
|
||||
function submitAudit() {
|
||||
if (!goods.value.id) return;
|
||||
auditSubmitLoading.value = true;
|
||||
const formData = new FormData();
|
||||
formData.append("goodsIds", goods.value.id);
|
||||
formData.append("authFlag", goodsAuditForm.auth_flag === 1 ? "PASS" : "REFUSE");
|
||||
authGoods(formData)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("审核成功");
|
||||
auditModalVisible.value = false;
|
||||
initGoods(goods.value.id);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
auditSubmitLoading.value = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -87,7 +87,7 @@
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form ref="form" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form ref="formRef" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form-item label="品牌名称" prop="name">
|
||||
<el-input v-model="form.name" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
<el-dialog v-model="picModelFlag" width="1200px" :show-close="true">
|
||||
<ossManage
|
||||
ref="ossManage"
|
||||
ref="ossManageRef"
|
||||
:is-component="true"
|
||||
:initialize="picModelFlag"
|
||||
@callback="callbackSelected"
|
||||
@@ -146,13 +146,14 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, nextTick, onMounted, getCurrentInstance } from "vue";
|
||||
import {
|
||||
getManagerBrandPage,
|
||||
addBrand,
|
||||
updateBrand,
|
||||
disableBrand,
|
||||
delBrand,
|
||||
delBrand as delBrandApi,
|
||||
getCategoryTree,
|
||||
getBrandCategoryListData,
|
||||
saveBrandCategory,
|
||||
@@ -162,222 +163,234 @@ import { regular } from "@/utils";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import defaultPic from "@/assets/default.png";
|
||||
|
||||
export default {
|
||||
name: "brand",
|
||||
components: {
|
||||
ossManage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultPic,
|
||||
loading: true,
|
||||
modalType: 0,
|
||||
modalVisible: false,
|
||||
modalTitle: "",
|
||||
picModelFlag: false,
|
||||
categoryModalVisible: false,
|
||||
categoryModalTitle: "关联分类",
|
||||
categoryTreeLoading: false,
|
||||
categoryTreeData: [],
|
||||
categoryTreeKey: 0,
|
||||
categorySubmitLoading: false,
|
||||
currentBrandId: "",
|
||||
selectedCategoryIds: [],
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
},
|
||||
form: {
|
||||
name: "",
|
||||
logo: "",
|
||||
deleteFlag: "",
|
||||
},
|
||||
formValidate: {
|
||||
name: [regular.REQUIRED, regular.VARCHAR20],
|
||||
logo: [regular.REQUIRED, regular.URL200],
|
||||
},
|
||||
submitLoading: false,
|
||||
data: [],
|
||||
total: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openLogoPicker() {
|
||||
this.picModelFlag = true;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.ossManage) {
|
||||
this.$refs.ossManage.selectImage = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
callbackSelected(val) {
|
||||
this.picModelFlag = false;
|
||||
this.form.logo = val.url;
|
||||
},
|
||||
buildCategoryTreeNodes(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
children: this.buildCategoryTreeNodes(item.children || []),
|
||||
}));
|
||||
},
|
||||
async openCategoryModal(row) {
|
||||
this.currentBrandId = row.id;
|
||||
this.categoryModalTitle = "关联分类 - " + (row.name || "");
|
||||
this.categoryModalVisible = true;
|
||||
this.categoryTreeLoading = true;
|
||||
this.categoryTreeKey += 1;
|
||||
this.categoryTreeData = [];
|
||||
this.selectedCategoryIds = [];
|
||||
try {
|
||||
const [treeRes, bindRes] = await Promise.all([
|
||||
getCategoryTree(),
|
||||
getBrandCategoryListData(row.id),
|
||||
]);
|
||||
const selectedIds = Array.isArray(bindRes?.result)
|
||||
? bindRes.result
|
||||
.map((x) => (typeof x === "string" ? x : x && x.id))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
this.selectedCategoryIds = selectedIds;
|
||||
this.categoryTreeData =
|
||||
treeRes && treeRes.success
|
||||
? this.buildCategoryTreeNodes(treeRes.result || [])
|
||||
: [];
|
||||
} finally {
|
||||
this.categoryTreeLoading = false;
|
||||
defineOptions({ name: "brand" });
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const loading = ref(true);
|
||||
const modalType = ref(0);
|
||||
const modalVisible = ref(false);
|
||||
const modalTitle = ref("");
|
||||
const picModelFlag = ref(false);
|
||||
const categoryModalVisible = ref(false);
|
||||
const categoryModalTitle = ref("关联分类");
|
||||
const categoryTreeLoading = ref(false);
|
||||
const categoryTreeData = ref([]);
|
||||
const categoryTreeKey = ref(0);
|
||||
const categorySubmitLoading = ref(false);
|
||||
const currentBrandId = ref("");
|
||||
const selectedCategoryIds = ref([]);
|
||||
const searchForm = reactive({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
});
|
||||
const form = ref({
|
||||
name: "",
|
||||
logo: "",
|
||||
deleteFlag: "",
|
||||
});
|
||||
const formValidate = reactive({
|
||||
name: [regular.REQUIRED, regular.VARCHAR20],
|
||||
logo: [regular.REQUIRED, regular.URL200],
|
||||
});
|
||||
const submitLoading = ref(false);
|
||||
const data = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
const searchFormRef = ref(null);
|
||||
const formRef = ref(null);
|
||||
const ossManageRef = ref(null);
|
||||
|
||||
function openLogoPicker() {
|
||||
picModelFlag.value = true;
|
||||
nextTick(() => {
|
||||
if (ossManageRef.value) {
|
||||
ossManageRef.value.selectImage = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function callbackSelected(val) {
|
||||
picModelFlag.value = false;
|
||||
form.value.logo = val.url;
|
||||
}
|
||||
|
||||
function buildCategoryTreeNodes(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
children: buildCategoryTreeNodes(item.children || []),
|
||||
}));
|
||||
}
|
||||
|
||||
async function openCategoryModal(row) {
|
||||
currentBrandId.value = row.id;
|
||||
categoryModalTitle.value = "关联分类 - " + (row.name || "");
|
||||
categoryModalVisible.value = true;
|
||||
categoryTreeLoading.value = true;
|
||||
categoryTreeKey.value += 1;
|
||||
categoryTreeData.value = [];
|
||||
selectedCategoryIds.value = [];
|
||||
try {
|
||||
const [treeRes, bindRes] = await Promise.all([
|
||||
getCategoryTree(),
|
||||
getBrandCategoryListData(row.id),
|
||||
]);
|
||||
const selectedIds = Array.isArray(bindRes?.result)
|
||||
? bindRes.result
|
||||
.map((x) => (typeof x === "string" ? x : x && x.id))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
selectedCategoryIds.value = selectedIds;
|
||||
categoryTreeData.value =
|
||||
treeRes && treeRes.success
|
||||
? buildCategoryTreeNodes(treeRes.result || [])
|
||||
: [];
|
||||
} finally {
|
||||
categoryTreeLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onCategoryTreeCheckChange(_data, checkedInfo) {
|
||||
selectedCategoryIds.value = checkedInfo?.checkedKeys || [];
|
||||
}
|
||||
|
||||
function submitBrandCategory() {
|
||||
if (!currentBrandId.value) return;
|
||||
categorySubmitLoading.value = true;
|
||||
saveBrandCategory(
|
||||
currentBrandId.value,
|
||||
(selectedCategoryIds.value || []).map((id) => String(id))
|
||||
)
|
||||
.then((res) => {
|
||||
categorySubmitLoading.value = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
categoryModalVisible.value = false;
|
||||
}
|
||||
},
|
||||
onCategoryTreeCheckChange(_data, checkedInfo) {
|
||||
this.selectedCategoryIds = checkedInfo?.checkedKeys || [];
|
||||
},
|
||||
submitBrandCategory() {
|
||||
if (!this.currentBrandId) return;
|
||||
this.categorySubmitLoading = true;
|
||||
saveBrandCategory(
|
||||
this.currentBrandId,
|
||||
(this.selectedCategoryIds || []).map((id) => String(id))
|
||||
)
|
||||
.then((res) => {
|
||||
this.categorySubmitLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.categoryModalVisible = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.categorySubmitLoading = false;
|
||||
});
|
||||
},
|
||||
handleStatusSwitchChange(row, checked) {
|
||||
const disable = !checked;
|
||||
ElMessageBox.confirm(
|
||||
"您确认要" + (disable ? "禁用" : "启用") + "品牌 " + row.name + " ?",
|
||||
disable ? "确认禁用" : "确认启用",
|
||||
{ type: "warning" }
|
||||
).then(() => {
|
||||
return disableBrand(row.id, { disable }).then((res) => {
|
||||
})
|
||||
.catch(() => {
|
||||
categorySubmitLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleStatusSwitchChange(row, checked) {
|
||||
const disable = !checked;
|
||||
ElMessageBox.confirm(
|
||||
"您确认要" + (disable ? "禁用" : "启用") + "品牌 " + row.name + " ?",
|
||||
disable ? "确认禁用" : "确认启用",
|
||||
{ type: "warning" }
|
||||
).then(() => {
|
||||
return disableBrand(row.id, { disable }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
}
|
||||
getDataList();
|
||||
});
|
||||
}).catch(() => {
|
||||
nextTick(() => proxy.$forceUpdate());
|
||||
});
|
||||
}
|
||||
|
||||
function delBrand(row) {
|
||||
ElMessageBox.confirm("您确认要删除 " + row.name + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return delBrandApi(row.id).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("品牌删除成功!");
|
||||
getDataList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function init() {
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function changePage(v) {
|
||||
searchForm.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function changePageSize(v) {
|
||||
searchForm.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
searchForm.pageNumber = 1;
|
||||
searchForm.pageSize = 20;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
getManagerBrandPage(searchForm).then((res) => {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
data.value = res.result.records;
|
||||
total.value = res.result.total;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true;
|
||||
if (modalType.value === 0) {
|
||||
delete form.value.id;
|
||||
addBrand(form.value).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
getDataList();
|
||||
modalVisible.value = false;
|
||||
}
|
||||
this.getDataList();
|
||||
});
|
||||
}).catch(() => {
|
||||
this.$nextTick(() => this.$forceUpdate());
|
||||
});
|
||||
},
|
||||
delBrand(row) {
|
||||
ElMessageBox.confirm("您确认要删除 " + row.name + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return delBrand(row.id).then((res) => {
|
||||
} else {
|
||||
updateBrand(form.value).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("品牌删除成功!");
|
||||
this.getDataList();
|
||||
ElMessage.success("操作成功");
|
||||
getDataList();
|
||||
modalVisible.value = false;
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getManagerBrandPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.submitLoading = true;
|
||||
if (this.modalType === 0) {
|
||||
delete this.form.id;
|
||||
addBrand(this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updateBrand(this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
add() {
|
||||
this.modalType = 0;
|
||||
this.modalTitle = "添加";
|
||||
this.$refs.form?.resetFields();
|
||||
delete this.form.id;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
edit(v) {
|
||||
this.modalType = 1;
|
||||
this.modalTitle = "编辑";
|
||||
this.$refs.form?.resetFields();
|
||||
for (const attr in v) {
|
||||
if (v[attr] === null) {
|
||||
v[attr] = "";
|
||||
}
|
||||
}
|
||||
const str = JSON.stringify(v);
|
||||
const data = JSON.parse(str);
|
||||
this.form = data;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function add() {
|
||||
modalType.value = 0;
|
||||
modalTitle.value = "添加";
|
||||
formRef.value?.resetFields();
|
||||
delete form.value.id;
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function edit(v) {
|
||||
modalType.value = 1;
|
||||
modalTitle.value = "编辑";
|
||||
formRef.value?.resetFields();
|
||||
for (const attr in v) {
|
||||
if (v[attr] === null) {
|
||||
v[attr] = "";
|
||||
}
|
||||
}
|
||||
const str = JSON.stringify(v);
|
||||
const data = JSON.parse(str);
|
||||
form.value = data;
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form ref="form" :model="formAdd" label-width="110px" :rules="formValidate">
|
||||
<el-form ref="formRef" :model="formAdd" label-width="110px" :rules="formValidate">
|
||||
<el-form-item v-if="showParent" label="上级分类" prop="parentId">
|
||||
{{ parentTitle }}
|
||||
<el-input v-model="formAdd.parentId" style="display: none" />
|
||||
@@ -106,7 +106,7 @@
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="brandForm" :model="brandForm" label-width="100px">
|
||||
<el-form ref="brandFormRef" :model="brandForm" label-width="100px">
|
||||
<el-select v-model="brandForm.categoryBrands" filterable multiple style="width: 100%">
|
||||
<el-option v-for="item in brandWay" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
@@ -120,7 +120,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import {
|
||||
delCategory,
|
||||
disableCategory,
|
||||
@@ -128,241 +129,249 @@ import {
|
||||
getCategoryBrandListData,
|
||||
getCategoryTree,
|
||||
insertCategory,
|
||||
saveCategoryBrand,
|
||||
saveCategoryBrand as apiSaveCategoryBrand,
|
||||
updateCategory,
|
||||
} from "@/api/goods";
|
||||
import uploadPicInput from "@/components/lili/upload-pic-input";
|
||||
import { regular } from "@/utils";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
export default {
|
||||
name: "goods-category",
|
||||
components: {
|
||||
uploadPicInput,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
categoryList: [],
|
||||
loading: false,
|
||||
brands: [],
|
||||
categoryId: "",
|
||||
modalType: 0,
|
||||
modalVisible: false,
|
||||
modalBrandVisible: false,
|
||||
modalTitle: "",
|
||||
showParent: false,
|
||||
parentTitle: "",
|
||||
modalBrandTitle: "",
|
||||
formAdd: {
|
||||
parentId: "",
|
||||
name: "",
|
||||
image: "",
|
||||
sortOrder: 0,
|
||||
deleteFlag: false,
|
||||
commissionRate: 0,
|
||||
level: 0,
|
||||
},
|
||||
brandForm: {
|
||||
categoryBrands: [],
|
||||
},
|
||||
brandWay: [],
|
||||
formValidate: {
|
||||
commissionRate: [regular.REQUIRED, regular.INTEGER],
|
||||
name: [regular.REQUIRED, regular.VARCHAR20],
|
||||
sortOrder: [regular.REQUIRED, regular.INTEGER],
|
||||
},
|
||||
tableData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
normalizeCategoryTree(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return;
|
||||
list.forEach((item) => {
|
||||
if (!item || typeof item !== "object") return;
|
||||
if (item.deleteFlag === 0) item.deleteFlag = false;
|
||||
else if (item.deleteFlag === 1) item.deleteFlag = true;
|
||||
else item.deleteFlag = !!item.deleteFlag;
|
||||
if (Array.isArray(item.children) && item.children.length) {
|
||||
this.normalizeCategoryTree(item.children);
|
||||
}
|
||||
});
|
||||
},
|
||||
onStatusSwitchChange(row, nextDeleteFlag) {
|
||||
const previousDeleteFlag = !nextDeleteFlag;
|
||||
const isClosing = nextDeleteFlag === true;
|
||||
ElMessageBox.confirm(
|
||||
`您是否要${isClosing ? "关闭" : "开启"}当前分类 ${row.name} 及其子分类?`,
|
||||
isClosing ? "确认关闭" : "确认开启",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
row._statusLoading = true;
|
||||
return disableCategory(row.id, { enableOperations: isClosing ? true : 0 }).then((res) => {
|
||||
row._statusLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getAllList();
|
||||
return;
|
||||
}
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
});
|
||||
}).catch(() => {
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.getAllList();
|
||||
this.getBrandList();
|
||||
},
|
||||
getBrandList() {
|
||||
getBrandListData().then((res) => {
|
||||
this.brandWay = res;
|
||||
});
|
||||
},
|
||||
brandOperation(v) {
|
||||
getCategoryBrandListData(v.id).then((res) => {
|
||||
this.categoryId = v.id;
|
||||
this.modalBrandTitle = "品牌关联";
|
||||
this.brandForm.categoryBrands = res.result.map((item) => item.id);
|
||||
this.modalBrandVisible = true;
|
||||
});
|
||||
},
|
||||
saveCategoryBrand() {
|
||||
saveCategoryBrand(this.categoryId, this.brandForm).then((res) => {
|
||||
this.submitLoading = false;
|
||||
defineOptions({ name: "goods-category" });
|
||||
|
||||
const submitLoading = ref(false);
|
||||
const categoryList = ref([]);
|
||||
const loading = ref(false);
|
||||
const brands = ref([]);
|
||||
const categoryId = ref("");
|
||||
const modalType = ref(0);
|
||||
const modalVisible = ref(false);
|
||||
const modalBrandVisible = ref(false);
|
||||
const modalTitle = ref("");
|
||||
const showParent = ref(false);
|
||||
const parentTitle = ref("");
|
||||
const modalBrandTitle = ref("");
|
||||
const formAdd = reactive({
|
||||
parentId: "",
|
||||
name: "",
|
||||
image: "",
|
||||
sortOrder: 0,
|
||||
deleteFlag: false,
|
||||
commissionRate: 0,
|
||||
level: 0,
|
||||
});
|
||||
const brandForm = reactive({
|
||||
categoryBrands: [],
|
||||
});
|
||||
const brandWay = ref([]);
|
||||
const formValidate = reactive({
|
||||
commissionRate: [regular.REQUIRED, regular.INTEGER],
|
||||
name: [regular.REQUIRED, regular.VARCHAR20],
|
||||
sortOrder: [regular.REQUIRED, regular.INTEGER],
|
||||
});
|
||||
const tableData = ref([]);
|
||||
|
||||
const formRef = ref(null);
|
||||
const brandFormRef = ref(null);
|
||||
|
||||
function normalizeCategoryTree(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return;
|
||||
list.forEach((item) => {
|
||||
if (!item || typeof item !== "object") return;
|
||||
if (item.deleteFlag === 0) item.deleteFlag = false;
|
||||
else if (item.deleteFlag === 1) item.deleteFlag = true;
|
||||
else item.deleteFlag = !!item.deleteFlag;
|
||||
if (Array.isArray(item.children) && item.children.length) {
|
||||
normalizeCategoryTree(item.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onStatusSwitchChange(row, nextDeleteFlag) {
|
||||
const previousDeleteFlag = !nextDeleteFlag;
|
||||
const isClosing = nextDeleteFlag === true;
|
||||
ElMessageBox.confirm(
|
||||
`您是否要${isClosing ? "关闭" : "开启"}当前分类 ${row.name} 及其子分类?`,
|
||||
isClosing ? "确认关闭" : "确认开启",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
row._statusLoading = true;
|
||||
return disableCategory(row.id, { enableOperations: isClosing ? true : 0 }).then((res) => {
|
||||
row._statusLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
getAllList();
|
||||
return;
|
||||
}
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
});
|
||||
}).catch(() => {
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
getAllList();
|
||||
getBrandList();
|
||||
}
|
||||
|
||||
function getBrandList() {
|
||||
getBrandListData().then((res) => {
|
||||
brandWay.value = res;
|
||||
});
|
||||
}
|
||||
|
||||
function brandOperation(v) {
|
||||
getCategoryBrandListData(v.id).then((res) => {
|
||||
categoryId.value = v.id;
|
||||
modalBrandTitle.value = "品牌关联";
|
||||
brandForm.categoryBrands = res.result.map((item) => item.id);
|
||||
modalBrandVisible.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
function saveCategoryBrand() {
|
||||
apiSaveCategoryBrand(categoryId.value, brandForm).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
modalBrandVisible.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addChildren(v) {
|
||||
modalType.value = 0;
|
||||
modalTitle.value = "添加子分类";
|
||||
parentTitle.value = v.name;
|
||||
formAdd.level = Number(v.level) + 1;
|
||||
formAdd.commissionRate = v.commissionRate;
|
||||
showParent.value = true;
|
||||
delete formAdd.id;
|
||||
formAdd.parentId = v.id;
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function edit(v) {
|
||||
modalType.value = 1;
|
||||
modalTitle.value = "编辑";
|
||||
formAdd.id = v.id;
|
||||
formAdd.name = v.name;
|
||||
formAdd.level = v.level;
|
||||
formAdd.parentId = v.parentId;
|
||||
formAdd.sortOrder = v.sortOrder;
|
||||
formAdd.commissionRate = v.commissionRate;
|
||||
formAdd.deleteFlag = v.deleteFlag;
|
||||
formAdd.image = v.image;
|
||||
showParent.value = false;
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function addParent() {
|
||||
modalType.value = 0;
|
||||
modalTitle.value = "添加一级分类";
|
||||
parentTitle.value = "顶级分类";
|
||||
showParent.value = true;
|
||||
formRef.value?.resetFields();
|
||||
delete formAdd.id;
|
||||
formAdd.parentId = 0;
|
||||
formAdd.level = 0;
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function Submit() {
|
||||
formRef.value.validate((valid) => {
|
||||
if (!valid) return;
|
||||
submitLoading.value = true;
|
||||
if (modalType.value === 0) {
|
||||
delete formAdd.id;
|
||||
insertCategory(formAdd).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.modalBrandVisible = false;
|
||||
ElMessage.success("添加成功");
|
||||
getAllList();
|
||||
modalVisible.value = false;
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
});
|
||||
},
|
||||
addChildren(v) {
|
||||
this.modalType = 0;
|
||||
this.modalTitle = "添加子分类";
|
||||
this.parentTitle = v.name;
|
||||
this.formAdd.level = Number(v.level) + 1;
|
||||
this.formAdd.commissionRate = v.commissionRate;
|
||||
this.showParent = true;
|
||||
delete this.formAdd.id;
|
||||
this.formAdd.parentId = v.id;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
edit(v) {
|
||||
this.modalType = 1;
|
||||
this.modalTitle = "编辑";
|
||||
this.formAdd.id = v.id;
|
||||
this.formAdd.name = v.name;
|
||||
this.formAdd.level = v.level;
|
||||
this.formAdd.parentId = v.parentId;
|
||||
this.formAdd.sortOrder = v.sortOrder;
|
||||
this.formAdd.commissionRate = v.commissionRate;
|
||||
this.formAdd.deleteFlag = v.deleteFlag;
|
||||
this.formAdd.image = v.image;
|
||||
this.showParent = false;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
addParent() {
|
||||
this.modalType = 0;
|
||||
this.modalTitle = "添加一级分类";
|
||||
this.parentTitle = "顶级分类";
|
||||
this.showParent = true;
|
||||
this.$refs.form?.resetFields();
|
||||
delete this.formAdd.id;
|
||||
this.formAdd.parentId = 0;
|
||||
this.formAdd.level = 0;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
Submit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitLoading = true;
|
||||
if (this.modalType === 0) {
|
||||
delete this.formAdd.id;
|
||||
insertCategory(this.formAdd).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("添加成功");
|
||||
this.getAllList();
|
||||
this.modalVisible = false;
|
||||
this.$refs.form.resetFields();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updateCategory(this.formAdd).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("修改成功");
|
||||
this.getAllList();
|
||||
this.modalVisible = false;
|
||||
this.$refs.form.resetFields();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updateCategory(formAdd).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
ElMessage.success("修改成功");
|
||||
getAllList();
|
||||
modalVisible.value = false;
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
});
|
||||
},
|
||||
remove(v) {
|
||||
ElMessageBox.confirm("您确认要删除 " + v.name + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return delCategory(v.id).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
getAllList() {
|
||||
this.loading = true;
|
||||
getCategoryTree()
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
localStorage.setItem("category", JSON.stringify(res.result));
|
||||
this.normalizeCategoryTree(res.result);
|
||||
this.categoryList = JSON.parse(JSON.stringify(res.result));
|
||||
this.tableData = JSON.parse(JSON.stringify(res.result));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
enable(v) {
|
||||
ElMessageBox.confirm(
|
||||
"您是否要启用当前分类 " + v.name + " 及其子分类?",
|
||||
"确认启用",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
return disableCategory(v.id, { enableOperations: 0 }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
this.getAllList();
|
||||
});
|
||||
},
|
||||
disable(v) {
|
||||
ElMessageBox.confirm(
|
||||
"您是否要禁用当前分类 " + v.name + " 及其子分类?",
|
||||
"确认禁用",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
return disableCategory(v.id, { enableOperations: true }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
this.getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
this.getAllList();
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function remove(v) {
|
||||
ElMessageBox.confirm("您确认要删除 " + v.name + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return delCategory(v.id).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function getAllList() {
|
||||
loading.value = true;
|
||||
getCategoryTree()
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
localStorage.setItem("category", JSON.stringify(res.result));
|
||||
normalizeCategoryTree(res.result);
|
||||
categoryList.value = JSON.parse(JSON.stringify(res.result));
|
||||
tableData.value = JSON.parse(JSON.stringify(res.result));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function enable(v) {
|
||||
ElMessageBox.confirm(
|
||||
"您是否要启用当前分类 " + v.name + " 及其子分类?",
|
||||
"确认启用",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
return disableCategory(v.id, { enableOperations: 0 }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
getAllList();
|
||||
});
|
||||
}
|
||||
|
||||
function disable(v) {
|
||||
ElMessageBox.confirm(
|
||||
"您是否要禁用当前分类 " + v.name + " 及其子分类?",
|
||||
"确认禁用",
|
||||
{ type: "warning", confirmButtonText: "是", cancelButtonText: "否" }
|
||||
).then(() => {
|
||||
return disableCategory(v.id, { enableOperations: true }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("操作成功");
|
||||
getAllList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
getAllList();
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form ref="form" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form ref="formRef" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form-item label="参数名称" prop="paramName">
|
||||
<el-input v-model="form.paramName" clearable style="width: 520px" />
|
||||
</el-form-item>
|
||||
@@ -92,7 +92,9 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import {
|
||||
getCategoryTree,
|
||||
getGoodsParamsDetail,
|
||||
@@ -102,6 +104,11 @@ import {
|
||||
import { regular } from "@/utils";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
defineOptions({ name: "parameterEdit" });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const getOptionText = (value) => {
|
||||
if (value && typeof value === "object") return value.value;
|
||||
return value;
|
||||
@@ -213,228 +220,228 @@ const buildFormState = (source, parameterId) => {
|
||||
return formState;
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "parameterEdit",
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
modalType: 0,
|
||||
categoryModalVisible: false,
|
||||
categoryModalTitle: "关联分类",
|
||||
categoryTreeLoading: false,
|
||||
categoryTreeData: [],
|
||||
categoryTreeSource: [],
|
||||
categoryIdNameMap: {},
|
||||
categoryTreeKey: 0,
|
||||
selectedCategoryIds: [],
|
||||
form: {
|
||||
paramName: "",
|
||||
options: [{ value: "" }],
|
||||
required: 0,
|
||||
isIndex: 0,
|
||||
sort: 0,
|
||||
categoryIds: [],
|
||||
},
|
||||
formValidate: {
|
||||
paramName: [regular.REQUIRED, regular.VARCHAR5],
|
||||
options: [{ required: true, validator: validateOptions, trigger: "change" }],
|
||||
required: [{ required: true, validator: validateRadioRequired("请选择是否必填"), trigger: "change" }],
|
||||
isIndex: [{ required: true, validator: validateRadioRequired("请选择是否索引"), trigger: "change" }],
|
||||
sort: [regular.REQUIRED, regular.INTEGER],
|
||||
categoryIds: [
|
||||
{
|
||||
type: "array",
|
||||
required: true,
|
||||
min: 1,
|
||||
message: "请选择关联分类",
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
id() {
|
||||
return this.$route.query && this.$route.query.id ? String(this.$route.query.id) : "";
|
||||
const formRef = ref(null);
|
||||
const categoryTree = ref(null);
|
||||
|
||||
const submitLoading = ref(false);
|
||||
const modalType = ref(0);
|
||||
const categoryModalVisible = ref(false);
|
||||
const categoryModalTitle = ref("关联分类");
|
||||
const categoryTreeLoading = ref(false);
|
||||
const categoryTreeData = ref([]);
|
||||
const categoryTreeSource = ref([]);
|
||||
const categoryIdNameMap = ref({});
|
||||
const categoryTreeKey = ref(0);
|
||||
const selectedCategoryIds = ref([]);
|
||||
const form = ref({
|
||||
paramName: "",
|
||||
options: [{ value: "" }],
|
||||
required: 0,
|
||||
isIndex: 0,
|
||||
sort: 0,
|
||||
categoryIds: [],
|
||||
});
|
||||
const formValidate = reactive({
|
||||
paramName: [regular.REQUIRED, regular.VARCHAR5],
|
||||
options: [{ required: true, validator: validateOptions, trigger: "change" }],
|
||||
required: [{ required: true, validator: validateRadioRequired("请选择是否必填"), trigger: "change" }],
|
||||
isIndex: [{ required: true, validator: validateRadioRequired("请选择是否索引"), trigger: "change" }],
|
||||
sort: [regular.REQUIRED, regular.INTEGER],
|
||||
categoryIds: [
|
||||
{
|
||||
type: "array",
|
||||
required: true,
|
||||
min: 1,
|
||||
message: "请选择关联分类",
|
||||
trigger: "change",
|
||||
},
|
||||
selectedCategoryNamesText() {
|
||||
if (!Array.isArray(this.categoryTreeSource) || this.categoryTreeSource.length === 0) return "";
|
||||
const selectedSet = new Set(toStringArray(this.selectedCategoryIds));
|
||||
const isSelected = (node) => {
|
||||
if (!node) return false;
|
||||
const nodeId = node.id !== undefined && node.id !== null ? String(node.id) : "";
|
||||
if (nodeId && selectedSet.has(nodeId)) return true;
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
if (children.length === 0) return false;
|
||||
return children.every(isSelected);
|
||||
};
|
||||
const collect = (node, out) => {
|
||||
if (!node) return;
|
||||
if (isSelected(node)) {
|
||||
if (node.name) out.push(node.name);
|
||||
return;
|
||||
}
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
children.forEach((c) => collect(c, out));
|
||||
};
|
||||
const names = [];
|
||||
this.categoryTreeSource.forEach((n) => collect(n, names));
|
||||
return names.join(",");
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"form.required"(val) {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) this.form.required = n;
|
||||
},
|
||||
"form.isIndex"(val) {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) this.form.isIndex = n;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.push({ name: "goods-parameter" });
|
||||
},
|
||||
syncCategoryIds(ids) {
|
||||
const categoryIds = toStringArray(ids);
|
||||
this.selectedCategoryIds = categoryIds;
|
||||
if (!this.form) this.form = {};
|
||||
this.form.categoryIds = categoryIds;
|
||||
},
|
||||
touchOptionsValidate() {
|
||||
this.$nextTick(() => {
|
||||
const form = this.$refs.form;
|
||||
if (form && typeof form.validateField === "function") {
|
||||
// validateField rejects on failure; catch to avoid dev-server [object Object] overlay
|
||||
form.validateField("options", () => {});
|
||||
}
|
||||
});
|
||||
},
|
||||
addOptionRow() {
|
||||
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||
this.form.options.push({ value: "" });
|
||||
},
|
||||
removeOptionRow(index) {
|
||||
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||
this.form.options.splice(index, 1);
|
||||
this.touchOptionsValidate();
|
||||
},
|
||||
buildCategoryTreeNodes(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
children: this.buildCategoryTreeNodes(item.children || []),
|
||||
}));
|
||||
},
|
||||
async loadDetail(parameterId) {
|
||||
if (!parameterId) return;
|
||||
const res = await getGoodsParamsDetail(parameterId).catch(() => null);
|
||||
if (!(res && res.success && res.result)) return;
|
||||
const dto = res.result;
|
||||
this.form = buildFormState(dto, parameterId);
|
||||
this.selectedCategoryIds = [...this.form.categoryIds];
|
||||
},
|
||||
async openCategoryModal() {
|
||||
this.categoryModalVisible = true;
|
||||
this.categoryTreeLoading = true;
|
||||
this.categoryTreeKey += 1;
|
||||
],
|
||||
});
|
||||
|
||||
const id = computed(() =>
|
||||
route.query && route.query.id ? String(route.query.id) : ""
|
||||
);
|
||||
const selectedCategoryNamesText = computed(() => {
|
||||
if (!Array.isArray(categoryTreeSource.value) || categoryTreeSource.value.length === 0) return "";
|
||||
const selectedSet = new Set(toStringArray(selectedCategoryIds.value));
|
||||
const isSelected = (node) => {
|
||||
if (!node) return false;
|
||||
const nodeId = node.id !== undefined && node.id !== null ? String(node.id) : "";
|
||||
if (nodeId && selectedSet.has(nodeId)) return true;
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
if (children.length === 0) return false;
|
||||
return children.every(isSelected);
|
||||
};
|
||||
const collect = (node, out) => {
|
||||
if (!node) return;
|
||||
if (isSelected(node)) {
|
||||
if (node.name) out.push(node.name);
|
||||
return;
|
||||
}
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
children.forEach((c) => collect(c, out));
|
||||
};
|
||||
const names = [];
|
||||
categoryTreeSource.value.forEach((n) => collect(n, names));
|
||||
return names.join(",");
|
||||
});
|
||||
|
||||
watch(
|
||||
() => form.value.required,
|
||||
(val) => {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) form.value.required = n;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => form.value.isIndex,
|
||||
(val) => {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) form.value.isIndex = n;
|
||||
}
|
||||
);
|
||||
|
||||
function back() {
|
||||
router.push({ name: "goods-parameter" });
|
||||
}
|
||||
function syncCategoryIds(ids) {
|
||||
const categoryIds = toStringArray(ids);
|
||||
selectedCategoryIds.value = categoryIds;
|
||||
if (!form.value) form.value = {};
|
||||
form.value.categoryIds = categoryIds;
|
||||
}
|
||||
function touchOptionsValidate() {
|
||||
nextTick(() => {
|
||||
const formEl = formRef.value;
|
||||
if (formEl && typeof formEl.validateField === "function") {
|
||||
// validateField rejects on failure; catch to avoid dev-server [object Object] overlay
|
||||
formEl.validateField("options", () => {});
|
||||
}
|
||||
});
|
||||
}
|
||||
function addOptionRow() {
|
||||
if (!Array.isArray(form.value.options)) form.value.options = [];
|
||||
form.value.options.push({ value: "" });
|
||||
}
|
||||
function removeOptionRow(index) {
|
||||
if (!Array.isArray(form.value.options)) form.value.options = [];
|
||||
form.value.options.splice(index, 1);
|
||||
touchOptionsValidate();
|
||||
}
|
||||
function buildCategoryTreeNodes(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
children: buildCategoryTreeNodes(item.children || []),
|
||||
}));
|
||||
}
|
||||
async function loadDetail(parameterId) {
|
||||
if (!parameterId) return;
|
||||
const res = await getGoodsParamsDetail(parameterId).catch(() => null);
|
||||
if (!(res && res.success && res.result)) return;
|
||||
const dto = res.result;
|
||||
form.value = buildFormState(dto, parameterId);
|
||||
selectedCategoryIds.value = [...form.value.categoryIds];
|
||||
}
|
||||
async function openCategoryModal() {
|
||||
categoryModalVisible.value = true;
|
||||
categoryTreeLoading.value = true;
|
||||
categoryTreeKey.value += 1;
|
||||
try {
|
||||
if (!Array.isArray(categoryTreeSource.value) || categoryTreeSource.value.length === 0) {
|
||||
const treeRes = await getCategoryTree();
|
||||
categoryTreeSource.value = treeRes && treeRes.success ? treeRes.result || [] : [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(categoryTreeSource.value, map);
|
||||
categoryIdNameMap.value = map;
|
||||
}
|
||||
categoryTreeData.value = buildCategoryTreeNodes(categoryTreeSource.value || []);
|
||||
} finally {
|
||||
categoryTreeLoading.value = false;
|
||||
}
|
||||
}
|
||||
function onCategoryTreeCheckChange(_data, checkedInfo) {
|
||||
syncCategoryIds(checkedInfo?.checkedKeys || []);
|
||||
nextTick(() => {
|
||||
const formEl = formRef.value;
|
||||
if (formEl && typeof formEl.validateField === "function") {
|
||||
formEl.validateField("categoryIds", () => {});
|
||||
}
|
||||
});
|
||||
}
|
||||
function initForm() {
|
||||
if (id.value) {
|
||||
modalType.value = 1;
|
||||
const cached = window.sessionStorage.getItem(cacheKey(id.value));
|
||||
if (cached) {
|
||||
try {
|
||||
if (!Array.isArray(this.categoryTreeSource) || this.categoryTreeSource.length === 0) {
|
||||
const treeRes = await getCategoryTree();
|
||||
this.categoryTreeSource = treeRes && treeRes.success ? treeRes.result || [] : [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(this.categoryTreeSource, map);
|
||||
this.categoryIdNameMap = map;
|
||||
}
|
||||
this.categoryTreeData = this.buildCategoryTreeNodes(this.categoryTreeSource || []);
|
||||
} finally {
|
||||
this.categoryTreeLoading = false;
|
||||
const row = JSON.parse(cached);
|
||||
form.value = buildFormState(row, row.id);
|
||||
selectedCategoryIds.value = [...form.value.categoryIds];
|
||||
} catch (e) {
|
||||
modalType.value = 0;
|
||||
}
|
||||
},
|
||||
onCategoryTreeCheckChange(_data, checkedInfo) {
|
||||
this.syncCategoryIds(checkedInfo?.checkedKeys || []);
|
||||
this.$nextTick(() => {
|
||||
const form = this.$refs.form;
|
||||
if (form && typeof form.validateField === "function") {
|
||||
form.validateField("categoryIds", () => {});
|
||||
}
|
||||
});
|
||||
},
|
||||
initForm() {
|
||||
if (this.id) {
|
||||
this.modalType = 1;
|
||||
const cached = window.sessionStorage.getItem(cacheKey(this.id));
|
||||
if (cached) {
|
||||
try {
|
||||
const row = JSON.parse(cached);
|
||||
this.form = buildFormState(row, row.id);
|
||||
this.selectedCategoryIds = [...this.form.categoryIds];
|
||||
} catch (e) {
|
||||
this.modalType = 0;
|
||||
}
|
||||
}
|
||||
this.loadDetail(String(this.id));
|
||||
} else {
|
||||
this.modalType = 0;
|
||||
if (!Array.isArray(this.form.options) || this.form.options.length === 0) {
|
||||
this.form.options = [{ value: "" }];
|
||||
}
|
||||
this.syncCategoryIds([]);
|
||||
}
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitLoading = true;
|
||||
const options = normalizeOptions(this.form.options);
|
||||
const categoryIds = toStringArray(this.form.categoryIds);
|
||||
const payload = {
|
||||
...this.form,
|
||||
options: options.join(","),
|
||||
required: Number(this.form.required),
|
||||
isIndex: Number(this.form.isIndex),
|
||||
sort: Number(this.form.sort || 0),
|
||||
categoryParameterList: categoryIds.map((categoryId) => ({ categoryId })),
|
||||
};
|
||||
if (this.modalType === 0) {
|
||||
delete payload.id;
|
||||
insertGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
ElMessage.success("操作成功");
|
||||
this.back();
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
} else {
|
||||
updateGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
ElMessage.success("操作成功");
|
||||
this.back();
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
getCategoryTree().then((res) => {
|
||||
if (res && res.success) {
|
||||
this.categoryTreeSource = res.result || [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(this.categoryTreeSource, map);
|
||||
this.categoryIdNameMap = map;
|
||||
}
|
||||
});
|
||||
this.initForm();
|
||||
},
|
||||
};
|
||||
}
|
||||
loadDetail(String(id.value));
|
||||
} else {
|
||||
modalType.value = 0;
|
||||
if (!Array.isArray(form.value.options) || form.value.options.length === 0) {
|
||||
form.value.options = [{ value: "" }];
|
||||
}
|
||||
syncCategoryIds([]);
|
||||
}
|
||||
}
|
||||
function handleSubmit() {
|
||||
formRef.value.validate((valid) => {
|
||||
if (!valid) return;
|
||||
submitLoading.value = true;
|
||||
const options = normalizeOptions(form.value.options);
|
||||
const categoryIds = toStringArray(form.value.categoryIds);
|
||||
const payload = {
|
||||
...form.value,
|
||||
options: options.join(","),
|
||||
required: Number(form.value.required),
|
||||
isIndex: Number(form.value.isIndex),
|
||||
sort: Number(form.value.sort || 0),
|
||||
categoryParameterList: categoryIds.map((categoryId) => ({ categoryId })),
|
||||
};
|
||||
if (modalType.value === 0) {
|
||||
delete payload.id;
|
||||
insertGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
ElMessage.success("操作成功");
|
||||
back();
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
updateGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
ElMessage.success("操作成功");
|
||||
back();
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getCategoryTree().then((res) => {
|
||||
if (res && res.success) {
|
||||
categoryTreeSource.value = res.result || [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(categoryTreeSource.value, map);
|
||||
categoryIdNameMap.value = map;
|
||||
}
|
||||
});
|
||||
initForm();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="operation padding-row">
|
||||
<el-button type="primary" @click="goAdd">添加</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" border :data="data" ref="table" style="width: 100%">
|
||||
<el-table v-loading="loading" border :data="data" ref="tableRef" style="width: 100%">
|
||||
<el-table-column prop="paramName" label="参数名称" width="300" />
|
||||
<el-table-column prop="options" label="参数值" min-width="260" show-overflow-tooltip />
|
||||
<el-table-column label="必填" width="300" align="center">
|
||||
@@ -65,83 +65,93 @@
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { deleteParams, getGoodsParamsPage } from "@/api/goods";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
export default {
|
||||
name: "categoryParams",
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
loading: true,
|
||||
total: 0,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
paramName: "",
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
isTruthyFlag(val) {
|
||||
return val === 1 || val === "1" || val === true;
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getGoodsParamsPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success) {
|
||||
this.data = (res.result && res.result.records) || [];
|
||||
this.total = (res.result && res.result.total) || 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
goAdd() {
|
||||
this.$router.push({ name: "goods-parameter-edit" });
|
||||
},
|
||||
goEdit(row) {
|
||||
if (!row || !row.id) return;
|
||||
try {
|
||||
window.sessionStorage.setItem(`goods-parameter-edit:${row.id}`, JSON.stringify(row));
|
||||
} catch (e) {}
|
||||
this.$router.push({ name: "goods-parameter-edit", query: { id: row.id } });
|
||||
},
|
||||
remove(row) {
|
||||
ElMessageBox.confirm("您确认要删除 " + (row.paramName || "") + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return deleteParams(row.id).then((res) => {
|
||||
if (res && res.success) {
|
||||
ElMessage.success("删除成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
defineOptions({ name: "categoryParams" });
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const submitLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const total = ref(0);
|
||||
const searchForm = reactive({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
paramName: "",
|
||||
});
|
||||
const data = ref([]);
|
||||
|
||||
const searchFormRef = ref(null);
|
||||
const tableRef = ref(null);
|
||||
|
||||
function isTruthyFlag(val) {
|
||||
return val === 1 || val === "1" || val === true;
|
||||
}
|
||||
|
||||
function init() {
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function changePage(v) {
|
||||
searchForm.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function changePageSize(v) {
|
||||
searchForm.pageNumber = 1;
|
||||
searchForm.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
searchForm.pageNumber = 1;
|
||||
searchForm.pageSize = 20;
|
||||
getDataList();
|
||||
}
|
||||
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
getGoodsParamsPage(searchForm).then((res) => {
|
||||
loading.value = false;
|
||||
if (res && res.success) {
|
||||
data.value = (res.result && res.result.records) || [];
|
||||
total.value = (res.result && res.result.total) || 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function goAdd() {
|
||||
router.push({ name: "goods-parameter-edit" });
|
||||
}
|
||||
|
||||
function goEdit(row) {
|
||||
if (!row || !row.id) return;
|
||||
try {
|
||||
window.sessionStorage.setItem(`goods-parameter-edit:${row.id}`, JSON.stringify(row));
|
||||
} catch (e) {}
|
||||
router.push({ name: "goods-parameter-edit", query: { id: row.id } });
|
||||
}
|
||||
|
||||
function remove(row) {
|
||||
ElMessageBox.confirm("您确认要删除 " + (row.paramName || "") + " ?", "确认删除", { type: "warning" }).then(() => {
|
||||
return deleteParams(row.id).then((res) => {
|
||||
if (res && res.success) {
|
||||
ElMessage.success("删除成功");
|
||||
getDataList();
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.link-text {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -170,145 +170,144 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { nextTick, onMounted, ref } from "vue";
|
||||
import * as API_Member from "@/api/member";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
export default {
|
||||
name: "goods-review",
|
||||
data() {
|
||||
return {
|
||||
infoData: {},
|
||||
infoFlag: false,
|
||||
infoTitle: "",
|
||||
currentReviewId: "",
|
||||
detailStatusReady: false,
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
goodsName: "",
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
gradeTagType(grade) {
|
||||
if (grade === "GOOD") return "success";
|
||||
if (grade === "MODERATE") return "warning";
|
||||
return "danger";
|
||||
},
|
||||
gradeText(grade) {
|
||||
if (grade === "GOOD") return "好评";
|
||||
if (grade === "MODERATE") return "中评";
|
||||
return "差评";
|
||||
},
|
||||
changeSwitchView(status) {
|
||||
if (!this.detailStatusReady || !this.currentReviewId) {
|
||||
return;
|
||||
defineOptions({ name: "goods-review" });
|
||||
|
||||
// 模板中的 el-form ref(原 ref="searchForm",为避免与数据 searchForm 同名互相覆盖而改名),script 内未使用
|
||||
const searchFormRef = ref(null);
|
||||
|
||||
const infoData = ref({});
|
||||
const infoFlag = ref(false);
|
||||
const infoTitle = ref("");
|
||||
const currentReviewId = ref("");
|
||||
const detailStatusReady = ref(false);
|
||||
const loading = ref(true);
|
||||
const searchForm = ref({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
goodsName: "",
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
});
|
||||
const data = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
function gradeTagType(grade) {
|
||||
if (grade === "GOOD") return "success";
|
||||
if (grade === "MODERATE") return "warning";
|
||||
return "danger";
|
||||
}
|
||||
function gradeText(grade) {
|
||||
if (grade === "GOOD") return "好评";
|
||||
if (grade === "MODERATE") return "中评";
|
||||
return "差评";
|
||||
}
|
||||
function changeSwitchView(status) {
|
||||
if (!detailStatusReady.value || !currentReviewId.value) {
|
||||
return;
|
||||
}
|
||||
API_Member.updateMemberReview(currentReviewId.value, { status }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("修改成功!");
|
||||
getDataList();
|
||||
}
|
||||
});
|
||||
}
|
||||
function init() {
|
||||
getDataList();
|
||||
}
|
||||
function changePage(v) {
|
||||
searchForm.value.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
function changePageSize(v) {
|
||||
searchForm.value.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
function handleSearch() {
|
||||
searchForm.value.pageNumber = 1;
|
||||
searchForm.value.pageSize = 20;
|
||||
getDataList();
|
||||
}
|
||||
function changeSwitch(row) {
|
||||
if (!row || !row.id) {
|
||||
return;
|
||||
}
|
||||
API_Member.updateMemberReview(row.id, { status: row.status }).then((res) => {
|
||||
if (res.success) {
|
||||
getDataList();
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateTop(v) {
|
||||
const top = !v.top;
|
||||
API_Member.updateMemberReviewTop(v.id, { top }).then((res) => {
|
||||
if (res.success) {
|
||||
data.value = data.value.map((item) => {
|
||||
if (item.goodsId !== v.goodsId) {
|
||||
return item;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
top: item.id === v.id ? top : false,
|
||||
};
|
||||
});
|
||||
ElMessage.success(top ? "置顶成功!" : "取消置顶成功!");
|
||||
init();
|
||||
}
|
||||
});
|
||||
}
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
API_Member.getMemberReview(searchForm.value)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
data.value = res.result.records;
|
||||
total.value = res.result.total;
|
||||
}
|
||||
API_Member.updateMemberReview(this.currentReviewId, { status }).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("修改成功!");
|
||||
this.getDataList();
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
function info(v) {
|
||||
currentReviewId.value = v.id;
|
||||
detailStatusReady.value = false;
|
||||
infoData.value = {};
|
||||
infoFlag.value = true;
|
||||
infoTitle.value = `用户${v.memberName}的评价详情`;
|
||||
API_Member.getMemberInfoReview(v.id).then((res) => {
|
||||
if (res.result) {
|
||||
infoData.value = res.result;
|
||||
nextTick(() => {
|
||||
detailStatusReady.value = true;
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
changeSwitch(row) {
|
||||
if (!row || !row.id) {
|
||||
return;
|
||||
}
|
||||
API_Member.updateMemberReview(row.id, { status: row.status }).then((res) => {
|
||||
if (res.success) {
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
updateTop(v) {
|
||||
const top = !v.top;
|
||||
API_Member.updateMemberReviewTop(v.id, { top }).then((res) => {
|
||||
if (res.success) {
|
||||
this.data = this.data.map((item) => {
|
||||
if (item.goodsId !== v.goodsId) {
|
||||
return item;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
top: item.id === v.id ? top : false,
|
||||
};
|
||||
});
|
||||
ElMessage.success(top ? "置顶成功!" : "取消置顶成功!");
|
||||
this.init();
|
||||
}
|
||||
});
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
API_Member.getMemberReview(this.searchForm)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
info(v) {
|
||||
this.currentReviewId = v.id;
|
||||
this.detailStatusReady = false;
|
||||
this.infoData = {};
|
||||
this.infoFlag = true;
|
||||
this.infoTitle = `用户${v.memberName}的评价详情`;
|
||||
API_Member.getMemberInfoReview(v.id).then((res) => {
|
||||
if (res.result) {
|
||||
this.infoData = res.result;
|
||||
this.$nextTick(() => {
|
||||
this.detailStatusReady = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
onInfoDialogClosed() {
|
||||
this.detailStatusReady = false;
|
||||
this.currentReviewId = "";
|
||||
this.infoData = {};
|
||||
},
|
||||
remove(v) {
|
||||
ElMessageBox.confirm("您确认要删除客户" + v.memberName + "的评论?", "确认删除", { type: "warning" }).then(() => {
|
||||
return API_Member.delMemberReview(v.id).then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
this.init();
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
function onInfoDialogClosed() {
|
||||
detailStatusReady.value = false;
|
||||
currentReviewId.value = "";
|
||||
infoData.value = {};
|
||||
}
|
||||
function remove(v) {
|
||||
ElMessageBox.confirm("您确认要删除客户" + v.memberName + "的评论?", "确认删除", { type: "warning" }).then(() => {
|
||||
return API_Member.delMemberReview(v.id).then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
init();
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="addFlag" title="添加商品分组" width="500px" :close-on-click-modal="false" destroy-on-close>
|
||||
<el-form ref="addForm" :model="formAdd" :rules="rulesAdd" label-width="90px">
|
||||
<el-form ref="addFormRef" :model="formAdd" :rules="rulesAdd" label-width="90px">
|
||||
<el-form-item label="分组名称" prop="groupName" style="width: 90%">
|
||||
<el-input v-model="formAdd.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
</el-form-item>
|
||||
@@ -51,7 +51,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="editFlag" title="编辑商品分组" width="500px" :close-on-click-modal="false" destroy-on-close>
|
||||
<el-form ref="editForm" :model="formEdit" :rules="rulesEdit" label-width="90px">
|
||||
<el-form ref="editFormRef" :model="formEdit" :rules="rulesEdit" label-width="90px">
|
||||
<el-input v-model="formEdit.id" style="display: none" />
|
||||
<el-form-item label="分组名称" prop="groupName" style="width: 90%">
|
||||
<el-input v-model="formEdit.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
@@ -68,166 +68,173 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, nextTick, onMounted } from "vue";
|
||||
import * as API_Goods from "@/api/goods.js";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
export default {
|
||||
name: "goodsGroup",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
addFlag: false,
|
||||
editFlag: false,
|
||||
submitAddLoading: false,
|
||||
submitEditLoading: false,
|
||||
formAdd: {
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
formEdit: {
|
||||
id: "",
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
rulesAdd: {
|
||||
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
|
||||
},
|
||||
rulesEdit: {
|
||||
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getData();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getData();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
API_Goods.getGoodsGroupByPage(this.searchForm)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success && res.result) {
|
||||
this.data = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
ElMessage.error("加载商品分组失败");
|
||||
});
|
||||
},
|
||||
openAdd() {
|
||||
this.addFlag = true;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm) this.$refs.addForm.resetFields();
|
||||
this.formAdd = { groupName: "", description: "" };
|
||||
defineOptions({ name: "goodsGroup" });
|
||||
|
||||
const loading = ref(true);
|
||||
const searchForm = reactive({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const data = ref([]);
|
||||
const total = ref(0);
|
||||
const addFlag = ref(false);
|
||||
const editFlag = ref(false);
|
||||
const submitAddLoading = ref(false);
|
||||
const submitEditLoading = ref(false);
|
||||
const formAdd = ref({
|
||||
groupName: "",
|
||||
description: "",
|
||||
});
|
||||
const formEdit = ref({
|
||||
id: "",
|
||||
groupName: "",
|
||||
description: "",
|
||||
});
|
||||
const rulesAdd = reactive({
|
||||
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
|
||||
});
|
||||
const rulesEdit = reactive({
|
||||
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const addFormRef = ref(null);
|
||||
const editFormRef = ref(null);
|
||||
|
||||
function init() {
|
||||
getData();
|
||||
}
|
||||
|
||||
function changePage(v) {
|
||||
searchForm.pageNumber = v;
|
||||
getData();
|
||||
}
|
||||
|
||||
function changePageSize(v) {
|
||||
searchForm.pageNumber = 1;
|
||||
searchForm.pageSize = v;
|
||||
getData();
|
||||
}
|
||||
|
||||
function getData() {
|
||||
loading.value = true;
|
||||
API_Goods.getGoodsGroupByPage(searchForm)
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res && res.success && res.result) {
|
||||
data.value = res.result.records || [];
|
||||
total.value = res.result.total || 0;
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
ElMessage.error("加载商品分组失败");
|
||||
});
|
||||
}
|
||||
|
||||
function openAdd() {
|
||||
addFlag.value = true;
|
||||
nextTick(() => {
|
||||
if (addFormRef.value) addFormRef.value.resetFields();
|
||||
formAdd.value = { groupName: "", description: "" };
|
||||
});
|
||||
}
|
||||
|
||||
function submitAdd() {
|
||||
addFormRef.value.validate((valid) => {
|
||||
if (!valid) return;
|
||||
submitAddLoading.value = true;
|
||||
API_Goods.addGoodsGroup(formAdd.value)
|
||||
.then((res) => {
|
||||
submitAddLoading.value = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("添加成功");
|
||||
addFlag.value = false;
|
||||
getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
submitAddLoading.value = false;
|
||||
ElMessage.error("添加失败,请检查权限或后端接口");
|
||||
});
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitAddLoading = true;
|
||||
API_Goods.addGoodsGroup(this.formAdd)
|
||||
.then((res) => {
|
||||
this.submitAddLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("添加成功");
|
||||
this.addFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.submitAddLoading = false;
|
||||
ElMessage.error("添加失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openEdit(row) {
|
||||
editFlag.value = true;
|
||||
submitEditLoading.value = false;
|
||||
API_Goods.getGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
formEdit.value = {
|
||||
id: res.result.id,
|
||||
groupName: res.result.groupName || "",
|
||||
description: res.result.description || "",
|
||||
};
|
||||
} else {
|
||||
formEdit.value = {
|
||||
id: row.id,
|
||||
groupName: row.groupName || "",
|
||||
description: row.description || "",
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("获取分组详情失败");
|
||||
});
|
||||
}
|
||||
|
||||
function submitEdit() {
|
||||
editFormRef.value.validate((valid) => {
|
||||
if (!valid) return;
|
||||
submitEditLoading.value = true;
|
||||
const { id, groupName, description } = formEdit.value;
|
||||
API_Goods.updateGoodsGroup(id, { id, groupName, description })
|
||||
.then((res) => {
|
||||
submitEditLoading.value = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("修改成功");
|
||||
editFlag.value = false;
|
||||
getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
submitEditLoading.value = false;
|
||||
ElMessage.error("修改失败,请检查权限或后端接口");
|
||||
});
|
||||
},
|
||||
openEdit(row) {
|
||||
this.editFlag = true;
|
||||
this.submitEditLoading = false;
|
||||
API_Goods.getGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.formEdit = {
|
||||
id: res.result.id,
|
||||
groupName: res.result.groupName || "",
|
||||
description: res.result.description || "",
|
||||
};
|
||||
} else {
|
||||
this.formEdit = {
|
||||
id: row.id,
|
||||
groupName: row.groupName || "",
|
||||
description: row.description || "",
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("获取分组详情失败");
|
||||
});
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitEditLoading = true;
|
||||
const { id, groupName, description } = this.formEdit;
|
||||
API_Goods.updateGoodsGroup(id, { id, groupName, description })
|
||||
.then((res) => {
|
||||
this.submitEditLoading = false;
|
||||
if (res && res.success) {
|
||||
ElMessage.success("修改成功");
|
||||
this.editFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.submitEditLoading = false;
|
||||
ElMessage.error("修改失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function remove(row) {
|
||||
ElMessageBox.confirm("确定删除该分组?", "提示", { type: "warning" }).then(() => {
|
||||
return API_Goods.deleteGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
ElMessage.success("删除成功");
|
||||
getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("删除失败,请检查权限或后端接口");
|
||||
});
|
||||
},
|
||||
remove(row) {
|
||||
ElMessageBox.confirm("确定删除该分组?", "提示", { type: "warning" }).then(() => {
|
||||
return API_Goods.deleteGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
ElMessage.success("删除成功");
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("删除失败,请检查权限或后端接口");
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
ref="searchFormRef"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
@@ -68,7 +68,7 @@
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="data"
|
||||
class="mt_10"
|
||||
@@ -208,7 +208,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import {
|
||||
batchUpdateGoodsSkuVirtualSales,
|
||||
getGoodsSkuData,
|
||||
@@ -225,223 +226,222 @@ const VIRTUAL_SALES_FIELDS = [
|
||||
"salesVolume",
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "goodsVirtualSales",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
editModalVisible: false,
|
||||
modalSubmitting: false,
|
||||
modalMode: "single",
|
||||
currentSku: null,
|
||||
currentIndex: -1,
|
||||
selectedRows: [],
|
||||
editForm: {
|
||||
virtualSales: 0,
|
||||
},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
};
|
||||
this.getDataList();
|
||||
},
|
||||
changeSort({ prop, order }) {
|
||||
if (!order) {
|
||||
this.searchForm.sort = "create_time";
|
||||
this.searchForm.order = "desc";
|
||||
} else {
|
||||
this.searchForm.sort = prop;
|
||||
this.searchForm.order = order === "ascending" ? "asc" : "desc";
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.selectedRows = selection;
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getGoodsSkuData(this.searchForm)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.data = (res.result.records || []).map((item) => ({
|
||||
...item,
|
||||
virtualSalesInput: this.getVirtualSalesValue(item),
|
||||
saving: false,
|
||||
}));
|
||||
this.total = res.result.total || 0;
|
||||
this.selectedRows = [];
|
||||
} else {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
this.selectedRows = [];
|
||||
ElMessage.error((res && res.message) || "加载规格列表失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
this.selectedRows = [];
|
||||
ElMessage.error("加载规格列表失败");
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
getVirtualSalesValue(row) {
|
||||
const field = VIRTUAL_SALES_FIELDS.find(
|
||||
(item) => row[item] !== undefined && row[item] !== null && row[item] !== ""
|
||||
);
|
||||
return field ? Number(row[field]) || 0 : 0;
|
||||
},
|
||||
openVirtualSalesModal(row, index) {
|
||||
this.modalMode = "single";
|
||||
this.currentSku = { ...row };
|
||||
this.currentIndex = index;
|
||||
this.editForm.virtualSales = this.getVirtualSalesValue(row);
|
||||
this.editModalVisible = true;
|
||||
},
|
||||
openBatchVirtualSalesModal() {
|
||||
if (!this.selectedRows.length) {
|
||||
ElMessage.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
}
|
||||
this.modalMode = "batch";
|
||||
this.currentSku = null;
|
||||
this.currentIndex = -1;
|
||||
this.editForm.virtualSales = 0;
|
||||
this.editModalVisible = true;
|
||||
},
|
||||
handleCancelVirtualSales() {
|
||||
if (this.modalSubmitting) return;
|
||||
this.resetVirtualSalesModal();
|
||||
},
|
||||
resetVirtualSalesModal() {
|
||||
this.editModalVisible = false;
|
||||
this.modalMode = "single";
|
||||
this.currentSku = null;
|
||||
this.currentIndex = -1;
|
||||
this.editForm.virtualSales = 0;
|
||||
},
|
||||
handleSubmitVirtualSales() {
|
||||
const virtualSales = Number(this.editForm.virtualSales);
|
||||
if (!Number.isInteger(virtualSales) || virtualSales < 0) {
|
||||
ElMessage.warning("请输入大于等于 0 的整数虚拟销量");
|
||||
return;
|
||||
}
|
||||
if (this.modalMode === "batch") {
|
||||
this.handleBatchSubmitVirtualSales(virtualSales);
|
||||
return;
|
||||
}
|
||||
if (!this.currentSku || this.currentIndex < 0) return;
|
||||
defineOptions({ name: "goodsVirtualSales" });
|
||||
|
||||
const currentIndex = this.currentIndex;
|
||||
const currentSkuId = this.currentSku.id;
|
||||
this.modalSubmitting = true;
|
||||
if (this.data[currentIndex]) {
|
||||
this.data[currentIndex].saving = true;
|
||||
// 模板 ref(避免与同名数据字段冲突而改名)
|
||||
const searchFormRef = ref(null);
|
||||
const tableRef = ref(null);
|
||||
|
||||
const loading = ref(true);
|
||||
const editModalVisible = ref(false);
|
||||
const modalSubmitting = ref(false);
|
||||
const modalMode = ref("single");
|
||||
const currentSku = ref(null);
|
||||
const currentIndex = ref(-1);
|
||||
const selectedRows = ref([]);
|
||||
const editForm = reactive({
|
||||
virtualSales: 0,
|
||||
});
|
||||
const searchForm = ref({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
});
|
||||
const data = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
function init() {
|
||||
getDataList();
|
||||
}
|
||||
function changePage(v) {
|
||||
searchForm.value.pageNumber = v;
|
||||
getDataList();
|
||||
}
|
||||
function changePageSize(v) {
|
||||
searchForm.value.pageNumber = 1;
|
||||
searchForm.value.pageSize = v;
|
||||
getDataList();
|
||||
}
|
||||
function handleSearch() {
|
||||
searchForm.value.pageNumber = 1;
|
||||
getDataList();
|
||||
}
|
||||
function handleReset() {
|
||||
searchForm.value = {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
};
|
||||
getDataList();
|
||||
}
|
||||
function changeSort({ prop, order }) {
|
||||
if (!order) {
|
||||
searchForm.value.sort = "create_time";
|
||||
searchForm.value.order = "desc";
|
||||
} else {
|
||||
searchForm.value.sort = prop;
|
||||
searchForm.value.order = order === "ascending" ? "asc" : "desc";
|
||||
}
|
||||
getDataList();
|
||||
}
|
||||
function handleSelectionChange(selection) {
|
||||
selectedRows.value = selection;
|
||||
}
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
getGoodsSkuData(searchForm.value)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
data.value = (res.result.records || []).map((item) => ({
|
||||
...item,
|
||||
virtualSalesInput: getVirtualSalesValue(item),
|
||||
saving: false,
|
||||
}));
|
||||
total.value = res.result.total || 0;
|
||||
selectedRows.value = [];
|
||||
} else {
|
||||
data.value = [];
|
||||
total.value = 0;
|
||||
selectedRows.value = [];
|
||||
ElMessage.error((res && res.message) || "加载规格列表失败");
|
||||
}
|
||||
updateGoodsSkuVirtualSales(currentSkuId, { virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
if (this.data[currentIndex]) {
|
||||
this.data[currentIndex].virtualSales = virtualSales;
|
||||
this.data[currentIndex].virtualSalesInput = virtualSales;
|
||||
}
|
||||
ElMessage.success("虚拟销量设置成功");
|
||||
this.resetVirtualSalesModal();
|
||||
} else {
|
||||
ElMessage.error((res && res.message) || "规格虚拟销量设置失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("规格虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
if (this.data[currentIndex]) {
|
||||
this.data[currentIndex].saving = false;
|
||||
}
|
||||
this.modalSubmitting = false;
|
||||
});
|
||||
},
|
||||
handleBatchSubmitVirtualSales(virtualSales) {
|
||||
const skuIds = this.selectedRows.map((item) => item.id).filter(Boolean);
|
||||
if (!skuIds.length) {
|
||||
ElMessage.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
})
|
||||
.catch(() => {
|
||||
data.value = [];
|
||||
total.value = 0;
|
||||
selectedRows.value = [];
|
||||
ElMessage.error("加载规格列表失败");
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
function getVirtualSalesValue(row) {
|
||||
const field = VIRTUAL_SALES_FIELDS.find(
|
||||
(item) => row[item] !== undefined && row[item] !== null && row[item] !== ""
|
||||
);
|
||||
return field ? Number(row[field]) || 0 : 0;
|
||||
}
|
||||
function openVirtualSalesModal(row, index) {
|
||||
modalMode.value = "single";
|
||||
currentSku.value = { ...row };
|
||||
currentIndex.value = index;
|
||||
editForm.virtualSales = getVirtualSalesValue(row);
|
||||
editModalVisible.value = true;
|
||||
}
|
||||
function openBatchVirtualSalesModal() {
|
||||
if (!selectedRows.value.length) {
|
||||
ElMessage.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
}
|
||||
modalMode.value = "batch";
|
||||
currentSku.value = null;
|
||||
currentIndex.value = -1;
|
||||
editForm.virtualSales = 0;
|
||||
editModalVisible.value = true;
|
||||
}
|
||||
function handleCancelVirtualSales() {
|
||||
if (modalSubmitting.value) return;
|
||||
resetVirtualSalesModal();
|
||||
}
|
||||
function resetVirtualSalesModal() {
|
||||
editModalVisible.value = false;
|
||||
modalMode.value = "single";
|
||||
currentSku.value = null;
|
||||
currentIndex.value = -1;
|
||||
editForm.virtualSales = 0;
|
||||
}
|
||||
function handleSubmitVirtualSales() {
|
||||
const virtualSales = Number(editForm.virtualSales);
|
||||
if (!Number.isInteger(virtualSales) || virtualSales < 0) {
|
||||
ElMessage.warning("请输入大于等于 0 的整数虚拟销量");
|
||||
return;
|
||||
}
|
||||
if (modalMode.value === "batch") {
|
||||
handleBatchSubmitVirtualSales(virtualSales);
|
||||
return;
|
||||
}
|
||||
if (!currentSku.value || currentIndex.value < 0) return;
|
||||
|
||||
const curIndex = currentIndex.value;
|
||||
const currentSkuId = currentSku.value.id;
|
||||
modalSubmitting.value = true;
|
||||
if (data.value[curIndex]) {
|
||||
data.value[curIndex].saving = true;
|
||||
}
|
||||
updateGoodsSkuVirtualSales(currentSkuId, { virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
if (data.value[curIndex]) {
|
||||
data.value[curIndex].virtualSales = virtualSales;
|
||||
data.value[curIndex].virtualSalesInput = virtualSales;
|
||||
}
|
||||
ElMessage.success("虚拟销量设置成功");
|
||||
resetVirtualSalesModal();
|
||||
} else {
|
||||
ElMessage.error((res && res.message) || "规格虚拟销量设置失败");
|
||||
}
|
||||
this.modalSubmitting = true;
|
||||
batchUpdateGoodsSkuVirtualSales({ skuIds, virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.data = this.data.map((item) => {
|
||||
if (!skuIds.includes(item.id)) return item;
|
||||
return {
|
||||
...item,
|
||||
virtualSales,
|
||||
virtualSalesInput: virtualSales,
|
||||
};
|
||||
});
|
||||
this.selectedRows = [];
|
||||
this.$refs.table?.clearSelection();
|
||||
ElMessage.success("虚拟销量设置成功");
|
||||
this.resetVirtualSalesModal();
|
||||
} else {
|
||||
ElMessage.error((res && res.message) || "虚拟销量设置失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
this.modalSubmitting = false;
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("规格虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
if (data.value[curIndex]) {
|
||||
data.value[curIndex].saving = false;
|
||||
}
|
||||
modalSubmitting.value = false;
|
||||
});
|
||||
}
|
||||
function handleBatchSubmitVirtualSales(virtualSales) {
|
||||
const skuIds = selectedRows.value.map((item) => item.id).filter(Boolean);
|
||||
if (!skuIds.length) {
|
||||
ElMessage.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
}
|
||||
modalSubmitting.value = true;
|
||||
batchUpdateGoodsSkuVirtualSales({ skuIds, virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
data.value = data.value.map((item) => {
|
||||
if (!skuIds.includes(item.id)) return item;
|
||||
return {
|
||||
...item,
|
||||
virtualSales,
|
||||
virtualSalesInput: virtualSales,
|
||||
};
|
||||
});
|
||||
},
|
||||
getTotalSales(row) {
|
||||
return (Number(row.buyCount) || 0) + (Number(row.virtualSalesInput) || 0);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
selectedRows.value = [];
|
||||
tableRef.value?.clearSelection();
|
||||
ElMessage.success("虚拟销量设置成功");
|
||||
resetVirtualSalesModal();
|
||||
} else {
|
||||
ElMessage.error((res && res.message) || "虚拟销量设置失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error("虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
modalSubmitting.value = false;
|
||||
});
|
||||
}
|
||||
function getTotalSales(row) {
|
||||
return (Number(row.buyCount) || 0) + (Number(row.virtualSalesInput) || 0);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user