mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2025-12-23 03:15:54 +08:00
feat(商品参数): 新增参数管理功能并优化相关页面
- 新增参数编辑页面,支持参数名称、必填、索引等属性配置 - 优化参数列表页面,增加搜索和分页功能 - 重构商品发布页面的参数展示逻辑 - 移除商品模板相关功能 - 优化品牌管理页面的分类关联功能 - 调整商品详情页参数展示样式
This commit is contained in:
@@ -87,14 +87,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane label="商品参数">
|
<TabPane label="商品参数">
|
||||||
<template v-if="detail.goodsParamsDTOList && detail.goodsParamsDTOList.length">
|
<template v-if="goodsParamsList.length">
|
||||||
<div class="goods-params" style="height:inherit;" v-for="item in detail.goodsParamsDTOList" :key="item.groupId">
|
<div class="item-param-container">
|
||||||
<span class="ml_10">{{item.groupName}}</span>
|
<div class="item-param-box" v-for="param in goodsParamsList" :key="param.paramId || param.paramName">
|
||||||
<table class="mb_10" cellpadding='0' cellspacing="0" >
|
<span class="item-param-title">{{ param.paramName }}:</span>
|
||||||
<tr v-for="param in item.goodsParamsItemDTOList" :key="param.paramId">
|
<span class="item-param-content">{{ param.paramValue || '-' }}</span>
|
||||||
<td style="text-align: center">{{param.paramName}}</td><td>{{param.paramValue}}</td>
|
</div>
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else>暂无商品参数</div>
|
<div v-else>暂无商品参数</div>
|
||||||
@@ -134,6 +132,29 @@ export default {
|
|||||||
// 商品详情
|
// 商品详情
|
||||||
skuDetail () {
|
skuDetail () {
|
||||||
return this.detail.data;
|
return this.detail.data;
|
||||||
|
},
|
||||||
|
goodsParamsList () {
|
||||||
|
const list = this.detail && Array.isArray(this.detail.goodsParamsDTOList) ? this.detail.goodsParamsDTOList : [];
|
||||||
|
const flat = [];
|
||||||
|
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (!item) return;
|
||||||
|
if (Array.isArray(item.goodsParamsItemDTOList)) {
|
||||||
|
flat.push(...item.goodsParamsItemDTOList);
|
||||||
|
} else {
|
||||||
|
flat.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cleaned = flat.filter((p) => p && (p.paramName || p.paramId));
|
||||||
|
const hasSort = cleaned.some((p) => p && p.sort !== undefined && p.sort !== null);
|
||||||
|
if (!hasSort) return cleaned;
|
||||||
|
|
||||||
|
return cleaned.slice().sort((a, b) => {
|
||||||
|
const sa = Number(a && a.sort) || 0;
|
||||||
|
const sb = Number(b && b.sort) || 0;
|
||||||
|
return sa - sb;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -336,14 +357,12 @@ export default {
|
|||||||
/************* 商品参数 *************/
|
/************* 商品参数 *************/
|
||||||
.item-param-container {
|
.item-param-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: column;
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
.item-param-box {
|
.item-param-box {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
width: 240px;
|
width: 100%;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,26 @@ export const getCategoryBrandListData = (category_id, params) => {
|
|||||||
export const saveCategoryBrand = (category_id, params) => {
|
export const saveCategoryBrand = (category_id, params) => {
|
||||||
return postRequest(`/goods/categoryBrand/${category_id}`, params)
|
return postRequest(`/goods/categoryBrand/${category_id}`, params)
|
||||||
}
|
}
|
||||||
|
// 根据品牌id获取关联分类
|
||||||
|
export const getBrandCategoryListData = (brand_id, params) => {
|
||||||
|
return getRequest(`/goods/categoryBrand/${brand_id}`, params)
|
||||||
|
}
|
||||||
|
// 保存品牌分类关联
|
||||||
|
export const saveBrandCategory = (brand_id, categoryIds) => {
|
||||||
|
return postRequest(`/goods/categoryBrand/${brand_id}`, categoryIds, {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getParameterCategoryListData = (parameter_id, params) => {
|
||||||
|
return getRequest(`/goods/parameters/category/${parameter_id}`, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const saveParameterCategory = (parameter_id, categoryIds) => {
|
||||||
|
return postRequest(`/goods/parameters/category/${parameter_id}`, categoryIds, {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
})
|
||||||
|
}
|
||||||
//保存获取关联规格
|
//保存获取关联规格
|
||||||
export const saveCategorySpec = (category_id, params) => {
|
export const saveCategorySpec = (category_id, params) => {
|
||||||
return postRequest(`/goods/categorySpec/${category_id}`, params)
|
return postRequest(`/goods/categorySpec/${category_id}`, params)
|
||||||
@@ -140,17 +160,28 @@ export const getCategoryParamsListData = (id, params) => {
|
|||||||
return getRequest(`/goods/categoryParameters/${id}`, params)
|
return getRequest(`/goods/categoryParameters/${id}`, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 参数组分页列表
|
||||||
|
export const getCategoryParametersGroupPage = (params) => {
|
||||||
|
return getRequest(`/goods/categoryParameters`, params)
|
||||||
|
}
|
||||||
|
|
||||||
//查询商品绑定参数信息
|
//查询商品绑定参数信息
|
||||||
export const getCategoryParamsByGoodsId = (goodsId, categoryId) => {
|
export const getCategoryParamsByGoodsId = (goodsId, categoryId) => {
|
||||||
return getRequest(`/goods/parameters/${goodsId}/${categoryId}`)
|
return getRequest(`/goods/parameters/${goodsId}/${categoryId}`)
|
||||||
}
|
}
|
||||||
|
export const getGoodsParamsPage = (params) => {
|
||||||
|
return getRequest(`/goods/parameters`, params)
|
||||||
|
}
|
||||||
|
export const getGoodsParamsDetail = (id, params) => {
|
||||||
|
return getRequest(`/goods/parameters/${id}`, params)
|
||||||
|
}
|
||||||
//保存参数
|
//保存参数
|
||||||
export const insertGoodsParams = (params) => {
|
export const insertGoodsParams = (params, headers) => {
|
||||||
return postRequest('/goods/parameters', params)
|
return postRequest('/goods/parameters', params, headers)
|
||||||
}
|
}
|
||||||
//更新参数
|
//更新参数
|
||||||
export const updateGoodsParams = (params) => {
|
export const updateGoodsParams = (params, headers) => {
|
||||||
return putRequest('/goods/parameters', params)
|
return putRequest('/goods/parameters', params, headers)
|
||||||
}
|
}
|
||||||
//删除参数
|
//删除参数
|
||||||
export const deleteParams = (id, params) => {
|
export const deleteParams = (id, params) => {
|
||||||
|
|||||||
@@ -97,6 +97,12 @@ export const otherRouter = {
|
|||||||
name: "goods-parameter",
|
name: "goods-parameter",
|
||||||
component: () => import("@/views/goods/goods-manage/parameter.vue")
|
component: () => import("@/views/goods/goods-manage/parameter.vue")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "goods-parameter-edit",
|
||||||
|
title: "商品参数维护",
|
||||||
|
name: "goods-parameter-edit",
|
||||||
|
component: () => import("@/views/goods/goods-manage/parameter-edit.vue")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "goods-spec",
|
path: "goods-spec",
|
||||||
title: "商品参数",
|
title: "商品参数",
|
||||||
|
|||||||
@@ -26,7 +26,14 @@
|
|||||||
<Input v-model="form.name" clearable style="width: 100%"/>
|
<Input v-model="form.name" clearable style="width: 100%"/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="品牌图标" prop="logo">
|
<FormItem label="品牌图标" prop="logo">
|
||||||
<upload-pic-input v-model="form.logo" style="width: 100%"></upload-pic-input>
|
<div style="display: flex; align-items: center; gap: 12px;">
|
||||||
|
<img
|
||||||
|
:src="form.logo || defaultPic"
|
||||||
|
alt="品牌图标"
|
||||||
|
style="width: 80px; height: 60px; object-fit: contain; border: 1px solid #dcdee2; border-radius: 4px; background: #fff;"
|
||||||
|
/>
|
||||||
|
<Button type="text" @click="openLogoPicker">修改</Button>
|
||||||
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</Form>
|
</Form>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
@@ -34,6 +41,34 @@
|
|||||||
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
|
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
<Modal width="1200px" v-model="picModelFlag" footer-hide>
|
||||||
|
<ossManage @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" ref="ossManage" />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
:title="categoryModalTitle"
|
||||||
|
v-model="categoryModalVisible"
|
||||||
|
:mask-closable="false"
|
||||||
|
:width="700"
|
||||||
|
>
|
||||||
|
<div style="position: relative; max-height: 520px; overflow: auto;">
|
||||||
|
<Spin size="large" fix v-if="categoryTreeLoading"></Spin>
|
||||||
|
<Tree
|
||||||
|
ref="categoryTree"
|
||||||
|
:key="categoryTreeKey"
|
||||||
|
:data="categoryTreeData"
|
||||||
|
show-checkbox
|
||||||
|
@on-check-change="onCategoryTreeCheckChange"
|
||||||
|
></Tree>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<Button type="text" @click="categoryModalVisible = false">取消</Button>
|
||||||
|
<Button type="primary" :loading="categorySubmitLoading" @click="submitBrandCategory"
|
||||||
|
>提交</Button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -44,22 +79,35 @@ import {
|
|||||||
updateBrand,
|
updateBrand,
|
||||||
disableBrand,
|
disableBrand,
|
||||||
delBrand,
|
delBrand,
|
||||||
|
getCategoryTree,
|
||||||
|
getBrandCategoryListData,
|
||||||
|
saveBrandCategory,
|
||||||
} from "@/api/goods";
|
} from "@/api/goods";
|
||||||
import uploadPicInput from "@/components/lili/upload-pic-input";
|
import ossManage from "@/views/sys/oss-manage/ossManage";
|
||||||
|
|
||||||
import {regular} from "@/utils";
|
import {regular} from "@/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "brand",
|
name: "brand",
|
||||||
components: {
|
components: {
|
||||||
uploadPicInput
|
ossManage
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
defaultPic: require("@/assets/default.png"),
|
||||||
loading: true, // 表单加载状态
|
loading: true, // 表单加载状态
|
||||||
modalType: 0, // 添加或编辑标识
|
modalType: 0, // 添加或编辑标识
|
||||||
modalVisible: false, // 添加或编辑显示
|
modalVisible: false, // 添加或编辑显示
|
||||||
modalTitle: "", // 添加或编辑标题
|
modalTitle: "", // 添加或编辑标题
|
||||||
|
picModelFlag: false, // 图片选择器
|
||||||
|
categoryModalVisible: false,
|
||||||
|
categoryModalTitle: "关联分类",
|
||||||
|
categoryTreeLoading: false,
|
||||||
|
categoryTreeData: [],
|
||||||
|
categoryTreeKey: 0,
|
||||||
|
categorySubmitLoading: false,
|
||||||
|
currentBrandId: "",
|
||||||
|
selectedCategoryIds: [],
|
||||||
searchForm: {
|
searchForm: {
|
||||||
// 搜索框初始化对象
|
// 搜索框初始化对象
|
||||||
pageNumber: 1, // 当前页数
|
pageNumber: 1, // 当前页数
|
||||||
@@ -118,11 +166,24 @@ export default {
|
|||||||
key: "deleteFlag",
|
key: "deleteFlag",
|
||||||
align: "left",
|
align: "left",
|
||||||
render: (h, params) => {
|
render: (h, params) => {
|
||||||
if (params.row.deleteFlag == 0) {
|
return h(
|
||||||
return h("Tag", {props: {color: "green",},}, "启用");
|
"i-switch",
|
||||||
} else if (params.row.deleteFlag == 1) {
|
{
|
||||||
return h("Tag", {props: {color: "volcano",},}, "禁用");
|
props: {
|
||||||
}
|
value: params.row.deleteFlag == 0,
|
||||||
|
size: "large",
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
"on-change": (checked) => {
|
||||||
|
this.handleStatusSwitchChange(params.row, checked);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
h("span", { slot: "open" }, "启用"),
|
||||||
|
h("span", { slot: "close" }, "禁用"),
|
||||||
|
]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
@@ -146,48 +207,10 @@ export default {
|
|||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
key: "action",
|
key: "action",
|
||||||
width: 180,
|
width: 210,
|
||||||
align: "center",
|
align: "center",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
render: (h, params) => {
|
render: (h, params) => {
|
||||||
let enableOrDisable = "";
|
|
||||||
if (params.row.deleteFlag == 0) {
|
|
||||||
enableOrDisable = h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
color: "#2d8cf0",
|
|
||||||
cursor: "pointer",
|
|
||||||
textDecoration: "none",
|
|
||||||
marginRight: "5px",
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
click: () => {
|
|
||||||
this.disable(params.row);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"禁用"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
enableOrDisable = h(
|
|
||||||
"a",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
color: "#2d8cf0",
|
|
||||||
cursor: "pointer",
|
|
||||||
textDecoration: "none",
|
|
||||||
marginRight: "5px",
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
click: () => {
|
|
||||||
this.enable(params.row);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"启用"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return h("div", [
|
return h("div", [
|
||||||
h(
|
h(
|
||||||
"a",
|
"a",
|
||||||
@@ -196,7 +219,6 @@ export default {
|
|||||||
color: "#2d8cf0",
|
color: "#2d8cf0",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
marginRight: "5px",
|
|
||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -211,7 +233,22 @@ export default {
|
|||||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||||
"|"
|
"|"
|
||||||
),
|
),
|
||||||
enableOrDisable,
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "#2d8cf0",
|
||||||
|
cursor: "pointer",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: () => {
|
||||||
|
this.openCategoryModal(params.row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"关联分类"
|
||||||
|
),
|
||||||
h(
|
h(
|
||||||
"span",
|
"span",
|
||||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||||
@@ -242,6 +279,100 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openLogoPicker() {
|
||||||
|
this.$refs.ossManage.selectImage = true;
|
||||||
|
this.picModelFlag = true;
|
||||||
|
},
|
||||||
|
callbackSelected(val) {
|
||||||
|
this.picModelFlag = false;
|
||||||
|
this.form.logo = val.url;
|
||||||
|
},
|
||||||
|
buildCategoryTreeNodes(list, selectedSet) {
|
||||||
|
if (!Array.isArray(list) || list.length === 0) return [];
|
||||||
|
return list.map((item) => {
|
||||||
|
const children = this.buildCategoryTreeNodes(item.children || [], selectedSet);
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.name,
|
||||||
|
expand: true,
|
||||||
|
checked: selectedSet.has(item.id),
|
||||||
|
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;
|
||||||
|
const selectedSet = new Set(selectedIds);
|
||||||
|
this.categoryTreeData = treeRes && treeRes.success
|
||||||
|
? this.buildCategoryTreeNodes(treeRes.result || [], selectedSet)
|
||||||
|
: [];
|
||||||
|
} finally {
|
||||||
|
this.categoryTreeLoading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCategoryTreeCheckChange(checkedNodes) {
|
||||||
|
if (!Array.isArray(checkedNodes)) {
|
||||||
|
this.selectedCategoryIds = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedCategoryIds = checkedNodes
|
||||||
|
.map((node) => node && node.id)
|
||||||
|
.filter(Boolean);
|
||||||
|
},
|
||||||
|
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) {
|
||||||
|
this.$Message.success("操作成功");
|
||||||
|
this.categoryModalVisible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.categorySubmitLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleStatusSwitchChange(row, checked) {
|
||||||
|
const disable = !checked;
|
||||||
|
this.$Modal.confirm({
|
||||||
|
title: disable ? "确认禁用" : "确认启用",
|
||||||
|
content: "您确认要" + (disable ? "禁用" : "启用") + "品牌 " + row.name + " ?",
|
||||||
|
loading: true,
|
||||||
|
onOk: () => {
|
||||||
|
disableBrand(row.id, { disable }).then((res) => {
|
||||||
|
this.$Modal.remove();
|
||||||
|
if (res.success) {
|
||||||
|
this.$Message.success("操作成功");
|
||||||
|
}
|
||||||
|
this.getDataList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
this.$nextTick(() => this.$forceUpdate());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
// 删除品牌
|
// 删除品牌
|
||||||
async delBrand(id) {
|
async delBrand(id) {
|
||||||
let res = await delBrand(id);
|
let res = await delBrand(id);
|
||||||
@@ -337,40 +468,6 @@ export default {
|
|||||||
this.form = data;
|
this.form = data;
|
||||||
this.modalVisible = true;
|
this.modalVisible = true;
|
||||||
},
|
},
|
||||||
// 启用品牌
|
|
||||||
enable(v) {
|
|
||||||
this.$Modal.confirm({
|
|
||||||
title: "确认启用",
|
|
||||||
content: "您确认要启用品牌 " + v.name + " ?",
|
|
||||||
loading: true,
|
|
||||||
onOk: () => {
|
|
||||||
disableBrand(v.id, {disable: false}).then((res) => {
|
|
||||||
this.$Modal.remove();
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("操作成功");
|
|
||||||
this.getDataList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 禁用
|
|
||||||
disable(v) {
|
|
||||||
this.$Modal.confirm({
|
|
||||||
title: "确认禁用",
|
|
||||||
content: "您确认要禁用品牌 " + v.name + " ?",
|
|
||||||
loading: true,
|
|
||||||
onOk: () => {
|
|
||||||
disableBrand(v.id, {disable: true}).then((res) => {
|
|
||||||
this.$Modal.remove();
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("操作成功");
|
|
||||||
this.getDataList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init();
|
this.init();
|
||||||
|
|||||||
@@ -14,32 +14,14 @@
|
|||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template slot="action" slot-scope="scope">
|
<template slot="action" slot-scope="scope">
|
||||||
<Dropdown v-show="scope.row.level == 2" trigger="click">
|
<div class="ops">
|
||||||
<a class="ops-link">
|
<template v-if="scope.row.level == 2">
|
||||||
绑定
|
<a class="ops-link" @click="parameterOperation(scope.row)">编辑绑定参数</a>
|
||||||
<Icon type="ios-arrow-down"></Icon>
|
</template>
|
||||||
</a>
|
<a class="ops-link" @click="edit(scope.row)">编辑</a>
|
||||||
<DropdownMenu slot="list">
|
<a class="ops-link" @click="remove(scope.row)">删除</a>
|
||||||
<DropdownItem @click.native="brandOperation(scope.row)">编辑绑定品牌</DropdownItem>
|
<a v-show="scope.row.level != 2" class="ops-link" @click="addChildren(scope.row)">添加子分类</a>
|
||||||
<DropdownItem @click.native="specOperation(scope.row)">编辑绑定规格</DropdownItem>
|
</div>
|
||||||
<DropdownItem @click.native="parameterOperation(scope.row)">编辑绑定参数</DropdownItem>
|
|
||||||
</DropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
<span class="ops-sep">|</span>
|
|
||||||
<Dropdown trigger="click">
|
|
||||||
<a class="ops-link">
|
|
||||||
操作
|
|
||||||
<Icon type="ios-arrow-down"></Icon>
|
|
||||||
</a>
|
|
||||||
<DropdownMenu slot="list">
|
|
||||||
<DropdownItem @click.native="edit(scope.row)">编辑</DropdownItem>
|
|
||||||
<DropdownItem v-if="scope.row.deleteFlag == 1" @click.native="enable(scope.row)">启用</DropdownItem>
|
|
||||||
<DropdownItem v-if="scope.row.deleteFlag == 0" @click.native="disable(scope.row)">禁用</DropdownItem>
|
|
||||||
<DropdownItem @click.native="remove(scope.row)">删除</DropdownItem>
|
|
||||||
</DropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
<span v-if="scope.row.level != 2" class="ops-sep">|</span>
|
|
||||||
<a v-show="scope.row.level != 2" class="ops-link" @click="addChildren(scope.row)">添加子分类</a>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template slot="commissionRate" slot-scope="scope">
|
<template slot="commissionRate" slot-scope="scope">
|
||||||
@@ -49,12 +31,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template slot="deleteFlag" slot-scope="{ row }">
|
<template slot="deleteFlag" slot-scope="{ row }">
|
||||||
<Tag
|
<i-switch
|
||||||
:class="{ ml_10: row.deleteFlag }"
|
size="large"
|
||||||
:color="row.deleteFlag == false ? 'success' : 'error'"
|
v-model="row.deleteFlag"
|
||||||
>
|
:true-value="false"
|
||||||
{{ row.deleteFlag == false ? "正常启用" : "禁用" }}</Tag
|
:false-value="true"
|
||||||
|
:loading="row._statusLoading"
|
||||||
|
@on-change="onStatusSwitchChange(row, $event)"
|
||||||
>
|
>
|
||||||
|
<span slot="open">开启</span>
|
||||||
|
<span slot="close">关闭</span>
|
||||||
|
</i-switch>
|
||||||
</template>
|
</template>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
@@ -249,6 +236,52 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
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;
|
||||||
|
this.$Modal.confirm({
|
||||||
|
title: isClosing ? "确认关闭" : "确认开启",
|
||||||
|
content:
|
||||||
|
"您是否要" +
|
||||||
|
(isClosing ? "关闭" : "开启") +
|
||||||
|
"当前分类 " +
|
||||||
|
row.name +
|
||||||
|
" 及其子分类?",
|
||||||
|
loading: true,
|
||||||
|
okText: "是",
|
||||||
|
cancelText: "否",
|
||||||
|
onOk: () => {
|
||||||
|
this.$set(row, "_statusLoading", true);
|
||||||
|
disableCategory(row.id, { enableOperations: isClosing ? true : 0 }).then(
|
||||||
|
(res) => {
|
||||||
|
this.$Modal.remove();
|
||||||
|
this.$set(row, "_statusLoading", false);
|
||||||
|
if (res && res.success) {
|
||||||
|
this.$Message.success("操作成功");
|
||||||
|
this.getAllList(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.deleteFlag = previousDeleteFlag;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
row.deleteFlag = previousDeleteFlag;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
// 初始化数据
|
// 初始化数据
|
||||||
init() {
|
init() {
|
||||||
this.getAllList(0);
|
this.getAllList(0);
|
||||||
@@ -411,6 +444,7 @@ export default {
|
|||||||
child._loading = false;
|
child._loading = false;
|
||||||
child.children = [];
|
child.children = [];
|
||||||
});
|
});
|
||||||
|
this.normalizeCategoryTree(val.children);
|
||||||
// 模拟加载
|
// 模拟加载
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
callback(val.children);
|
callback(val.children);
|
||||||
@@ -419,6 +453,7 @@ export default {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.deepCategoryChildren(item.id, this.categoryList);
|
this.deepCategoryChildren(item.id, this.categoryList);
|
||||||
|
this.normalizeCategoryTree(this.checkedCategoryChildren);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
callback(this.checkedCategoryChildren);
|
callback(this.checkedCategoryChildren);
|
||||||
}, 100);
|
}, 100);
|
||||||
@@ -446,6 +481,7 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
localStorage.setItem("category", JSON.stringify(res.result));
|
localStorage.setItem("category", JSON.stringify(res.result));
|
||||||
|
this.normalizeCategoryTree(res.result);
|
||||||
this.categoryList = JSON.parse(JSON.stringify(res.result));
|
this.categoryList = JSON.parse(JSON.stringify(res.result));
|
||||||
this.tableData = res.result.map((item) => {
|
this.tableData = res.result.map((item) => {
|
||||||
if(this.recordLevel[0] && item.id === this.recordLevel[0]) {
|
if(this.recordLevel[0] && item.id === this.recordLevel[0]) {
|
||||||
@@ -532,9 +568,18 @@ export default {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.ops-sep {
|
.ops {
|
||||||
display: inline-block;
|
display: flex;
|
||||||
margin: 0 8px;
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.ops-link + .ops-link {
|
||||||
|
margin-left: 16px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ops-link + .ops-link::before {
|
||||||
|
content: "|";
|
||||||
|
position: absolute;
|
||||||
|
left: -10px;
|
||||||
color: #dcdee2;
|
color: #dcdee2;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
442
manager/src/views/goods/goods-manage/parameter-edit.vue
Normal file
442
manager/src/views/goods/goods-manage/parameter-edit.vue
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search">
|
||||||
|
<Card>
|
||||||
|
<Form ref="form" :model="form" :label-width="100" :rules="formValidate">
|
||||||
|
<FormItem label="参数名称" prop="paramName">
|
||||||
|
<Input v-model="form.paramName" clearable style="width: 520px" />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="是否必填" prop="required">
|
||||||
|
<RadioGroup v-model="form.required">
|
||||||
|
<Radio :label="0">否</Radio>
|
||||||
|
<Radio :label="1">是</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
<span style="margin-left: 10px; color: #999; font-size: 12px"
|
||||||
|
>商品发布时参数是否必填</span
|
||||||
|
>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="是否索引" prop="isIndex">
|
||||||
|
<RadioGroup v-model="form.isIndex">
|
||||||
|
<Radio :label="0">否</Radio>
|
||||||
|
<Radio :label="1">是</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
<span style="margin-left: 10px; color: #999; font-size: 12px"
|
||||||
|
>开启索引后,用户将可以通过该参数筛选商品,索引开关不影响商详页的参数展示</span
|
||||||
|
>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="排序" prop="sort">
|
||||||
|
<InputNumber :min="0" type="number" v-model="form.sort" style="width: 520px" />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="参数值" prop="options">
|
||||||
|
<Table :columns="optionColumns" :data="form.options" border size="small" style="width: 520px" />
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<Button type="primary" @click="addOptionRow">新增</Button>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="关联分类">
|
||||||
|
<Button type="default" @click="openCategoryModal">选择分类</Button>
|
||||||
|
<span v-if="selectedCategoryNamesText" style="margin-left: 10px; color: #999; font-size: 12px"
|
||||||
|
>{{ selectedCategoryNamesText }}</span
|
||||||
|
>
|
||||||
|
<span v-else style="margin-left: 10px; color: #999; font-size: 12px"
|
||||||
|
>已选择{{ selectedCategoryIds.length }}个分类</span
|
||||||
|
>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem>
|
||||||
|
<Button type="default" @click="back">返回</Button>
|
||||||
|
<Button type="primary" :loading="submitLoading" @click="handleSubmit">保存</Button>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
:title="categoryModalTitle"
|
||||||
|
v-model="categoryModalVisible"
|
||||||
|
:mask-closable="false"
|
||||||
|
:width="700"
|
||||||
|
>
|
||||||
|
<div style="position: relative; max-height: 520px; overflow: auto;">
|
||||||
|
<Spin size="large" fix v-if="categoryTreeLoading"></Spin>
|
||||||
|
<Tree
|
||||||
|
:key="categoryTreeKey"
|
||||||
|
:data="categoryTreeData"
|
||||||
|
show-checkbox
|
||||||
|
@on-check-change="onCategoryTreeCheckChange"
|
||||||
|
></Tree>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<Button type="text" @click="categoryModalVisible = false">取消</Button>
|
||||||
|
<Button type="primary" style="margin-left: 8px" @click="categoryModalVisible = false">确定</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
getCategoryTree,
|
||||||
|
getGoodsParamsDetail,
|
||||||
|
insertGoodsParams,
|
||||||
|
updateGoodsParams,
|
||||||
|
} from "@/api/goods";
|
||||||
|
import { regular } from "@/utils";
|
||||||
|
|
||||||
|
const getOptionText = (value) => {
|
||||||
|
if (value && typeof value === "object") return value.value;
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeOptions = (value) => {
|
||||||
|
const arr = Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: typeof value === "string"
|
||||||
|
? value.split(",")
|
||||||
|
: [];
|
||||||
|
const cleaned = arr
|
||||||
|
.map((x) => String(getOptionText(x) ?? "").trim())
|
||||||
|
.filter((x) => x.length > 0);
|
||||||
|
return Array.from(new Set(cleaned));
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateOptions = (rule, value, callback) => {
|
||||||
|
const arr = Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: typeof value === "string"
|
||||||
|
? value.split(",")
|
||||||
|
: [];
|
||||||
|
const options = normalizeOptions(arr);
|
||||||
|
if (options.length === 0) {
|
||||||
|
callback(new Error("请填写参数值"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const joined = options.join(",");
|
||||||
|
if (!/^.{1,255}$/.test(joined)) {
|
||||||
|
callback(new Error("超出最大长度限制"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalize01 = (value, fallback = 0) => {
|
||||||
|
const n = Number(value);
|
||||||
|
if (n === 0 || n === 1) return n;
|
||||||
|
return fallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildSpringFormPayload = (payload) => {
|
||||||
|
const out = {};
|
||||||
|
if (payload && payload.id !== undefined && payload.id !== null && String(payload.id)) {
|
||||||
|
out.id = String(payload.id);
|
||||||
|
}
|
||||||
|
out.paramName = payload && payload.paramName !== undefined && payload.paramName !== null ? String(payload.paramName) : "";
|
||||||
|
out.options = payload && payload.options !== undefined && payload.options !== null ? String(payload.options) : "";
|
||||||
|
out.required = payload ? Number(payload.required) : 0;
|
||||||
|
out.isIndex = payload ? Number(payload.isIndex) : 0;
|
||||||
|
out.sort = payload ? Number(payload.sort) : 0;
|
||||||
|
|
||||||
|
const categoryList = payload && Array.isArray(payload.categoryParameterList) ? payload.categoryParameterList : [];
|
||||||
|
const categoryIds = categoryList
|
||||||
|
.map((x) => (x && x.categoryId !== undefined && x.categoryId !== null ? String(x.categoryId) : ""))
|
||||||
|
.filter((x) => x.length > 0);
|
||||||
|
categoryIds.forEach((categoryId, index) => {
|
||||||
|
out[`categoryParameterList[${index}].categoryId`] = categoryId;
|
||||||
|
});
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateRadioRequired = (message) => (rule, value, callback) => {
|
||||||
|
const n = normalize01(value, NaN);
|
||||||
|
if (!(n === 0 || n === 1)) {
|
||||||
|
callback(new Error(message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toStringArray = (arr) => {
|
||||||
|
if (!Array.isArray(arr)) return [];
|
||||||
|
return arr.map((x) => String(x)).filter((x) => x.length > 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cacheKey = (id) => `goods-parameter-edit:${id}`;
|
||||||
|
|
||||||
|
const buildCategoryIdNameMap = (list, map) => {
|
||||||
|
if (!Array.isArray(list) || list.length === 0) return;
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (!item) return;
|
||||||
|
const id = item.id !== undefined && item.id !== null ? String(item.id) : "";
|
||||||
|
if (id) map[id] = item.name;
|
||||||
|
buildCategoryIdNameMap(item.children || [], map);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
optionColumns: [
|
||||||
|
{
|
||||||
|
title: "参数值",
|
||||||
|
key: "value",
|
||||||
|
minWidth: 420,
|
||||||
|
render: (h, params) => {
|
||||||
|
return h("Input", {
|
||||||
|
props: {
|
||||||
|
value: params.row.value,
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
input: (val) => {
|
||||||
|
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||||
|
if (!this.form.options[params.index]) return;
|
||||||
|
this.form.options[params.index].value = val;
|
||||||
|
},
|
||||||
|
"on-blur": () => {
|
||||||
|
this.touchOptionsValidate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 90,
|
||||||
|
align: "center",
|
||||||
|
render: (h, params) => {
|
||||||
|
return h(
|
||||||
|
"Button",
|
||||||
|
{
|
||||||
|
props: {
|
||||||
|
type: "error",
|
||||||
|
size: "small",
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: () => this.removeOptionRow(params.index),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"删除",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
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],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
id() {
|
||||||
|
return this.$route.query && this.$route.query.id ? String(this.$route.query.id) : "";
|
||||||
|
},
|
||||||
|
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 id = node.id !== undefined && node.id !== null ? String(node.id) : "";
|
||||||
|
if (id && selectedSet.has(id)) 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.$set(this.form, "required", n);
|
||||||
|
},
|
||||||
|
"form.isIndex"(val) {
|
||||||
|
const n = normalize01(val, 0);
|
||||||
|
if (val !== n) this.$set(this.form, "isIndex", n);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
back() {
|
||||||
|
this.$router.push({ name: "goods-parameter" });
|
||||||
|
},
|
||||||
|
touchOptionsValidate() {
|
||||||
|
if (this.$refs.form && this.$refs.form.validateField) {
|
||||||
|
this.$refs.form.validateField("options");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addOptionRow() {
|
||||||
|
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||||
|
this.form.options.push({ value: "" });
|
||||||
|
this.touchOptionsValidate();
|
||||||
|
},
|
||||||
|
removeOptionRow(index) {
|
||||||
|
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||||
|
this.form.options.splice(index, 1);
|
||||||
|
this.touchOptionsValidate();
|
||||||
|
},
|
||||||
|
buildCategoryTreeNodes(list, selectedSet) {
|
||||||
|
if (!Array.isArray(list) || list.length === 0) return [];
|
||||||
|
return list.map((item) => {
|
||||||
|
const children = this.buildCategoryTreeNodes(item.children || [], selectedSet);
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.name,
|
||||||
|
expand: true,
|
||||||
|
checked: selectedSet.has(String(item.id)),
|
||||||
|
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;
|
||||||
|
const opts = normalizeOptions(dto.options);
|
||||||
|
this.form = {
|
||||||
|
id: dto.id || parameterId,
|
||||||
|
paramName: dto.paramName || "",
|
||||||
|
options: opts.map((x) => ({ value: x })),
|
||||||
|
required: normalize01(dto.required, 0),
|
||||||
|
isIndex: normalize01(dto.isIndex, 0),
|
||||||
|
sort: Number(dto.sort ?? 0) || 0,
|
||||||
|
};
|
||||||
|
const list = Array.isArray(dto.categoryParameterList) ? dto.categoryParameterList : [];
|
||||||
|
this.selectedCategoryIds = toStringArray(list.map((x) => x && x.categoryId).filter(Boolean));
|
||||||
|
},
|
||||||
|
async openCategoryModal() {
|
||||||
|
this.categoryModalVisible = true;
|
||||||
|
this.categoryTreeLoading = true;
|
||||||
|
this.categoryTreeKey += 1;
|
||||||
|
try {
|
||||||
|
const selectedSet = new Set(toStringArray(this.selectedCategoryIds));
|
||||||
|
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 || [], selectedSet);
|
||||||
|
} finally {
|
||||||
|
this.categoryTreeLoading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCategoryTreeCheckChange(checkedNodes) {
|
||||||
|
if (!Array.isArray(checkedNodes)) {
|
||||||
|
this.selectedCategoryIds = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedCategoryIds = toStringArray(checkedNodes.map((node) => node && node.id).filter(Boolean));
|
||||||
|
},
|
||||||
|
initForm() {
|
||||||
|
if (this.id) {
|
||||||
|
this.modalType = 1;
|
||||||
|
const cached = window.sessionStorage.getItem(cacheKey(this.id));
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
const row = JSON.parse(cached);
|
||||||
|
const opts = normalizeOptions(row.options);
|
||||||
|
this.form = {
|
||||||
|
id: row.id,
|
||||||
|
paramName: row.paramName || "",
|
||||||
|
options: opts.map((x) => ({ value: x })),
|
||||||
|
required: normalize01(row.required, 0),
|
||||||
|
isIndex: normalize01(row.isIndex, 0),
|
||||||
|
sort: Number(row.sort ?? 0) || 0,
|
||||||
|
};
|
||||||
|
} 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.selectedCategoryIds = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.form.validate((valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
this.submitLoading = true;
|
||||||
|
const options = normalizeOptions(this.form.options);
|
||||||
|
const categoryIds = toStringArray(this.selectedCategoryIds);
|
||||||
|
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;
|
||||||
|
this.$Message.success("操作成功");
|
||||||
|
this.back();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.submitLoading = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateGoodsParams(buildSpringFormPayload(payload))
|
||||||
|
.then((res) => {
|
||||||
|
if (!(res && res.success)) return;
|
||||||
|
this.$Message.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();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss"></style>
|
||||||
@@ -1,385 +1,202 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 100%">
|
<div class="search">
|
||||||
<Card>
|
<Card>
|
||||||
<Button @click="handleAddParamsGroup" type="primary">添加</Button>
|
<Form
|
||||||
|
ref="searchForm"
|
||||||
|
@submit.native.prevent
|
||||||
|
@keydown.enter.native="handleSearch"
|
||||||
|
:model="searchForm"
|
||||||
|
inline
|
||||||
|
:label-width="70"
|
||||||
|
class="search-form"
|
||||||
|
>
|
||||||
|
<Form-item label="参数名称">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="searchForm.paramName"
|
||||||
|
placeholder="请输入参数名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</Form-item>
|
||||||
|
<Button @click="handleSearch" type="primary">搜索</Button>
|
||||||
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<div class="row">
|
<Card>
|
||||||
<Card v-if="paramsGroup.length == 0"> 暂无参数绑定信息 </Card>
|
<Row class="operation padding-row">
|
||||||
<div class="paramsGroup" v-else>
|
<Button @click="goAdd" type="primary">添加</Button>
|
||||||
<Card
|
</Row>
|
||||||
style="width: 350px; margin: 7px"
|
<Table :loading="loading" border :columns="columns" :data="data" ref="table"></Table>
|
||||||
v-for="(group, index) in paramsGroup"
|
<Row type="flex" justify="end" class="mt_10">
|
||||||
:key="index"
|
<Page
|
||||||
:bordered="false"
|
:current="searchForm.pageNumber"
|
||||||
>
|
:total="total"
|
||||||
<p slot="title">
|
:page-size="searchForm.pageSize"
|
||||||
<Icon type="ios-film-outline"></Icon> {{ group.groupName }}
|
@on-change="changePage"
|
||||||
</p>
|
@on-page-size-change="changePageSize"
|
||||||
<p slot="extra">
|
:page-size-opts="[20, 50, 100]"
|
||||||
<Dropdown slot="extra">
|
size="small"
|
||||||
<a href="javascript:void(0)">
|
show-total
|
||||||
操作
|
show-elevator
|
||||||
<Icon type="ios-arrow-down"></Icon>
|
show-sizer
|
||||||
</a>
|
></Page>
|
||||||
<Dropdown-menu slot="list">
|
</Row>
|
||||||
<Dropdown-item @click.native="handleEditParamsGroup(group)"
|
</Card>
|
||||||
>编辑</Dropdown-item
|
|
||||||
>
|
|
||||||
<Dropdown-item @click.native="handleDeleteParamGroup(group)"
|
|
||||||
>删除</Dropdown-item
|
|
||||||
>
|
|
||||||
</Dropdown-menu>
|
|
||||||
</Dropdown>
|
|
||||||
<Icon type="arrow-down-b"></Icon>
|
|
||||||
</p>
|
|
||||||
<template v-if="group.params && group.params.length > 0">
|
|
||||||
<div
|
|
||||||
v-for="(param, paramId) in group.params"
|
|
||||||
:key="paramId"
|
|
||||||
class="params"
|
|
||||||
>
|
|
||||||
<span>{{ param.paramName }}</span>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<i-button type="text" @click="handleEditParams(group, param)"
|
|
||||||
>编辑</i-button
|
|
||||||
>
|
|
||||||
<i-button
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
style="color: #f56c6c"
|
|
||||||
@click="handleDeleteParam(group, param)"
|
|
||||||
>删除</i-button
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div v-else style="align-content: center">暂无数据...</div>
|
|
||||||
<div style="text-align: center">
|
|
||||||
<i-button type="text" @click="handleAddParams(group)"
|
|
||||||
>添加</i-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
:title="modalTitle"
|
|
||||||
v-model="dialogParamsVisible"
|
|
||||||
:mask-closable="false"
|
|
||||||
:width="500"
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
ref="paramForm"
|
|
||||||
:model="paramForm"
|
|
||||||
:label-width="100"
|
|
||||||
:rules="formValidate"
|
|
||||||
>
|
|
||||||
<FormItem label="参数名称" prop="paramName">
|
|
||||||
<Input v-model="paramForm.paramName" style="width: 100%" />
|
|
||||||
</FormItem>
|
|
||||||
<FormItem label="可选值" prop="options">
|
|
||||||
<Select
|
|
||||||
v-model="paramForm.options"
|
|
||||||
placeholder="输入后回车添加"
|
|
||||||
multiple
|
|
||||||
filterable
|
|
||||||
allow-create
|
|
||||||
:popper-append-to-body="false"
|
|
||||||
popper-class="spec-values-popper"
|
|
||||||
style="width: 100%; text-align: left; margin-right: 10px"
|
|
||||||
>
|
|
||||||
<Option
|
|
||||||
v-for="(item, itemIndex) in ops.options"
|
|
||||||
:value="item"
|
|
||||||
:key="itemIndex"
|
|
||||||
:label="item"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</Option>
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
<FormItem label="选项" prop="specName3">
|
|
||||||
<Checkbox label="1" v-model="paramForm.required">必填</Checkbox>
|
|
||||||
<Checkbox label="1" v-model="paramForm.isIndex">可索引</Checkbox>
|
|
||||||
</FormItem>
|
|
||||||
<FormItem label="排序" prop="sort">
|
|
||||||
<InputNumber
|
|
||||||
:min="0"
|
|
||||||
type="number"
|
|
||||||
v-model="paramForm.sort"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
<div slot="footer">
|
|
||||||
<Button type="text" @click="dialogParamsVisible = false">取消</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
:loading="submitLoading"
|
|
||||||
@click="submitParamForm"
|
|
||||||
>提交</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
:title="modalTitle"
|
|
||||||
v-model="dialogParamsGroupVisible"
|
|
||||||
:mask-closable="false"
|
|
||||||
:width="500"
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
@submit.native.prevent
|
|
||||||
@keydown.enter.native="submitParamGroupForm"
|
|
||||||
ref="paramGroupForm"
|
|
||||||
:model="paramGroupForm"
|
|
||||||
:label-width="100"
|
|
||||||
:rules="paramGroupValidate"
|
|
||||||
>
|
|
||||||
<FormItem label="参数名称" prop="groupName">
|
|
||||||
<Input v-model="paramGroupForm.groupName" style="width: 100%" />
|
|
||||||
</FormItem>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
<div slot="footer">
|
|
||||||
<Button type="text" @click="dialogParamsGroupVisible = false"
|
|
||||||
>取消</Button
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
:loading="submitLoading"
|
|
||||||
@click="submitParamGroupForm"
|
|
||||||
>提交</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
getCategoryParamsListData,
|
|
||||||
insertGoodsParams,
|
|
||||||
updateGoodsParams,
|
|
||||||
deleteParams,
|
deleteParams,
|
||||||
insertParamsGroup,
|
getGoodsParamsPage,
|
||||||
updateParamsGroup,
|
|
||||||
deleteParamsGroup,
|
|
||||||
} from "@/api/goods";
|
} from "@/api/goods";
|
||||||
|
|
||||||
import { regular } from "@/utils";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "categoryParams",
|
name: "categoryParams",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
/** 分类ID */
|
loading: true,
|
||||||
categoryId: this.$route.query.id,
|
total: 0,
|
||||||
/** 参数组 */
|
searchForm: {
|
||||||
paramsGroup: [],
|
pageNumber: 1,
|
||||||
/** 添加或编辑标识 */
|
pageSize: 20,
|
||||||
modalType: 0,
|
sort: "createTime",
|
||||||
/** 添加或编辑标题 */
|
order: "desc",
|
||||||
modalTitle: "",
|
paramName: "",
|
||||||
/** 参数添加或编辑弹出框 */
|
|
||||||
dialogParamsVisible: false,
|
|
||||||
/** 参数组添加或编辑弹出框 */
|
|
||||||
dialogParamsGroupVisible: false,
|
|
||||||
//参数表单
|
|
||||||
paramForm: {
|
|
||||||
sort: 1,
|
|
||||||
},
|
|
||||||
/** 参数值 **/
|
|
||||||
ops: {
|
|
||||||
options: [],
|
|
||||||
},
|
|
||||||
// 参数表单
|
|
||||||
paramGroupForm: {},
|
|
||||||
/** 添加、编辑参数 规格 */
|
|
||||||
formValidate: {
|
|
||||||
paramName: [regular.REQUIRED, regular.VARCHAR5],
|
|
||||||
options: [regular.REQUIRED, regular.VARCHAR255],
|
|
||||||
sort: [regular.REQUIRED, regular.INTEGER],
|
|
||||||
},
|
|
||||||
/** 参数组*/
|
|
||||||
paramGroupValidate: {
|
|
||||||
groupName: [regular.REQUIRED, regular.VARCHAR5],
|
|
||||||
},
|
},
|
||||||
|
data: [],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: "参数名称",
|
||||||
|
key: "paramName",
|
||||||
|
width: 300,
|
||||||
|
resizable: true,
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "参数值",
|
||||||
|
key: "options",
|
||||||
|
minWidth: 260,
|
||||||
|
tooltip: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "必填",
|
||||||
|
key: "required",
|
||||||
|
width: 300,
|
||||||
|
align: "center",
|
||||||
|
render: (h, params) => {
|
||||||
|
const val = params.row.required;
|
||||||
|
const on = val === 1 || val === "1" || val === true;
|
||||||
|
return h("span", on ? "是" : "否");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "可索引",
|
||||||
|
key: "isIndex",
|
||||||
|
width: 300,
|
||||||
|
align: "center",
|
||||||
|
render: (h, params) => {
|
||||||
|
const val = params.row.isIndex;
|
||||||
|
const on = val === 1 || val === "1" || val === true;
|
||||||
|
return h("span", on ? "是" : "否");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
width: 300,
|
||||||
|
align: "center",
|
||||||
|
fixed: "right",
|
||||||
|
render: (h, params) => {
|
||||||
|
return h("div", [
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "#2d8cf0",
|
||||||
|
cursor: "pointer",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: () => {
|
||||||
|
this.goEdit(params.row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"编辑"
|
||||||
|
),
|
||||||
|
h("span", { style: { margin: "0 8px", color: "#dcdee2" } }, "|"),
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "#2d8cf0",
|
||||||
|
cursor: "pointer",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: () => {
|
||||||
|
this.remove(params.row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"删除"
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
filters: {
|
|
||||||
paramTypeFilter(val) {
|
|
||||||
return val === 1 ? "输入项" : "选择项";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 初始化数据
|
|
||||||
init() {
|
init() {
|
||||||
this.getDataList();
|
this.getDataList();
|
||||||
},
|
},
|
||||||
//弹出添加参数框
|
changePage(v) {
|
||||||
handleAddParams(group) {
|
this.searchForm.pageNumber = v;
|
||||||
this.paramForm = {
|
this.getDataList();
|
||||||
paramName: "",
|
|
||||||
paramType: 1,
|
|
||||||
options: "",
|
|
||||||
required: false,
|
|
||||||
isIndex: false,
|
|
||||||
sort: 0,
|
|
||||||
groupId: group.groupId,
|
|
||||||
categoryId: this.categoryId,
|
|
||||||
};
|
|
||||||
this.modalTitle = "添加参数";
|
|
||||||
this.modalType = 0;
|
|
||||||
this.dialogParamsVisible = true;
|
|
||||||
},
|
},
|
||||||
//弹出修改参数框
|
changePageSize(v) {
|
||||||
handleEditParams(group, param) {
|
this.searchForm.pageNumber = 1;
|
||||||
console.log(group, param);
|
this.searchForm.pageSize = v;
|
||||||
this.paramForm = {
|
this.getDataList();
|
||||||
paramName: param.paramName,
|
|
||||||
options: param.options.split(","),
|
|
||||||
required: param.required == 1 ? true : false,
|
|
||||||
isIndex: param.isIndex == 1 ? true : false,
|
|
||||||
groupId: param.groupId || "",
|
|
||||||
categoryId: param.categoryId || "",
|
|
||||||
sort: param.sort || 1,
|
|
||||||
id: param.id,
|
|
||||||
};
|
|
||||||
this.ops.options = this.paramForm.options;
|
|
||||||
this.modalType = 1;
|
|
||||||
this.modalTitle = "修改参数";
|
|
||||||
this.dialogParamsVisible = true;
|
|
||||||
},
|
},
|
||||||
//弹出修改参数组框
|
handleSearch() {
|
||||||
handleEditParamsGroup(group) {
|
this.searchForm.pageNumber = 1;
|
||||||
this.paramGroupForm = {
|
this.searchForm.pageSize = 20;
|
||||||
groupName: group.groupName,
|
this.getDataList();
|
||||||
categoryId: this.categoryId,
|
|
||||||
id: group.groupId,
|
|
||||||
};
|
|
||||||
this.modalType = 1;
|
|
||||||
this.modalTitle = "修改参数组";
|
|
||||||
this.dialogParamsGroupVisible = true;
|
|
||||||
},
|
},
|
||||||
// 添加参数
|
|
||||||
handleAddParamsGroup() {
|
|
||||||
this.paramGroupForm = {};
|
|
||||||
this.ops = {};
|
|
||||||
(this.paramGroupForm.categoryId = this.categoryId), (this.modalType = 0);
|
|
||||||
|
|
||||||
this.modalTitle = "添加参数组";
|
|
||||||
this.dialogParamsGroupVisible = true;
|
|
||||||
},
|
|
||||||
//保存参数组
|
|
||||||
submitParamGroupForm() {
|
|
||||||
this.$refs.paramGroupForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
if (this.modalType === 0) {
|
|
||||||
insertParamsGroup(this.paramGroupForm).then((res) => {
|
|
||||||
this.submitLoading = false;
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("参数组修改成功");
|
|
||||||
this.getDataList();
|
|
||||||
this.dialogParamsVisible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.warn(this.paramGroupForm);
|
|
||||||
updateParamsGroup(this.paramGroupForm).then((res) => {
|
|
||||||
this.submitLoading = false;
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("参数组修改成功");
|
|
||||||
this.getDataList();
|
|
||||||
this.dialogParamsVisible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.dialogParamsGroupVisible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//保存参数
|
|
||||||
submitParamForm() {
|
|
||||||
this.$refs.paramForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.submitLoading = true;
|
|
||||||
let data = JSON.parse(JSON.stringify(this.paramForm));
|
|
||||||
data.isIndex = Number(data.isIndex);
|
|
||||||
data.required = Number(data.required);
|
|
||||||
if (this.modalType === 0) {
|
|
||||||
insertGoodsParams(data).then((res) => {
|
|
||||||
this.submitLoading = false;
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("参数添加成功");
|
|
||||||
this.getDataList();
|
|
||||||
this.dialogParamsVisible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.warn(data.isIndex);
|
|
||||||
data.isIndex = Number(data.isIndex);
|
|
||||||
data.required = Number(data.required);
|
|
||||||
updateGoodsParams(data).then((res) => {
|
|
||||||
this.submitLoading = false;
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("参数修改成功");
|
|
||||||
this.getDataList();
|
|
||||||
this.dialogParamsVisible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 获取分类列表
|
|
||||||
getDataList() {
|
getDataList() {
|
||||||
getCategoryParamsListData(this.categoryId).then((res) => {
|
this.loading = true;
|
||||||
if (res.success) {
|
getGoodsParamsPage(this.searchForm).then((res) => {
|
||||||
this.paramsGroup = res.result;
|
this.loading = false;
|
||||||
|
if (res && res.success) {
|
||||||
|
this.data = (res.result && res.result.records) || [];
|
||||||
|
this.total = (res.result && res.result.total) || 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//删除参数方法
|
goAdd() {
|
||||||
handleDeleteParam(group, param) {
|
this.$router.push({ name: "goods-parameter-edit" });
|
||||||
this.$Modal.confirm({
|
|
||||||
title: "确认删除",
|
|
||||||
// 记得确认修改此处
|
|
||||||
content: "您确认要删除 " + param.paramName + " ?",
|
|
||||||
loading: true,
|
|
||||||
onOk: () => {
|
|
||||||
// 删除
|
|
||||||
deleteParams(param.id).then((res) => {
|
|
||||||
this.$Modal.remove();
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.success("删除参数成功");
|
|
||||||
this.getDataList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
//删除参数组方法
|
goEdit(row) {
|
||||||
handleDeleteParamGroup(group) {
|
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) {
|
||||||
this.$Modal.confirm({
|
this.$Modal.confirm({
|
||||||
title: "确认删除",
|
title: "确认删除",
|
||||||
// 记得确认修改此处
|
content: "您确认要删除 " + (row.paramName || "") + " ?",
|
||||||
content: "您确认要删除 " + group.groupName + " ?",
|
|
||||||
loading: true,
|
loading: true,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
// 删除
|
deleteParams(row.id).then((res) => {
|
||||||
deleteParamsGroup(group.groupId).then((res) => {
|
|
||||||
this.$Modal.remove();
|
this.$Modal.remove();
|
||||||
if (res.success) {
|
if (res && res.success) {
|
||||||
this.$Message.success("删除参数成功");
|
this.$Message.success("删除成功");
|
||||||
this.getDataList();
|
this.getDataList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -392,33 +209,4 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss"></style>
|
||||||
.row {
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.params {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
padding: 3px;
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
font-size: 14px;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ivu-card-head {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ivu-btn {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paramsGroup {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<!-- 选择商品类型 -->
|
<!-- 选择商品类型 -->
|
||||||
<Modal v-model="selectGoodsType" width="550" :closable="false">
|
<Modal v-model="selectGoodsType" width="550" :closable="false">
|
||||||
<div class="goods-type-list" v-if="!showGoodsTemplates">
|
<div class="goods-type-list">
|
||||||
<div
|
<div
|
||||||
class="goods-type-item"
|
class="goods-type-item"
|
||||||
:class="{ 'active-goods-type': item.check }"
|
:class="{ 'active-goods-type': item.check }"
|
||||||
@@ -17,25 +17,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="goods-type-list">
|
|
||||||
<h2 @click="showGoodsTemplates = !showGoodsTemplates">返回</h2>
|
|
||||||
<div class="goods-list-box">
|
|
||||||
<Scroll :on-reach-bottom="handleReachBottom">
|
|
||||||
<div
|
|
||||||
class="goods-type-item template-item"
|
|
||||||
@click="handleClickGoodsTemplate(item)"
|
|
||||||
v-for="(item, tempIndex) in goodsTemplates"
|
|
||||||
:key="tempIndex"
|
|
||||||
>
|
|
||||||
<img :src="item.thumbnail" />
|
|
||||||
<div>
|
|
||||||
<h2>{{ item.goodsName }}</h2>
|
|
||||||
<p>{{ item.sellingPoint || "" }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Scroll>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
<!-- 商品分类 -->
|
<!-- 商品分类 -->
|
||||||
<div class="content-goods-publish">
|
<div class="content-goods-publish">
|
||||||
@@ -79,9 +60,6 @@
|
|||||||
<span v-show="category[1].name">> {{ category[1].name }}</span>
|
<span v-show="category[1].name">> {{ category[1].name }}</span>
|
||||||
<span v-show="category[2].name">> {{ category[2].name }}</span>
|
<span v-show="category[2].name">> {{ category[2].name }}</span>
|
||||||
</p>
|
</p>
|
||||||
<template v-if="selectedTemplate.goodsName">
|
|
||||||
<Divider>已选商品模版:{{ selectedTemplate.goodsName }}</Divider>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@@ -97,10 +75,7 @@ import * as API_GOODS from "@/api/goods";
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedTemplate: {}, // 已选模板
|
|
||||||
selectGoodsType: false, // 展示选择商品分类modal
|
selectGoodsType: false, // 展示选择商品分类modal
|
||||||
goodsTemplates: [], // 商品模板列表
|
|
||||||
showGoodsTemplates: false, //是否显示选择商品模板
|
|
||||||
goodsTypeWay: [
|
goodsTypeWay: [
|
||||||
{
|
{
|
||||||
title: "实物商品",
|
title: "实物商品",
|
||||||
@@ -116,12 +91,6 @@ export default {
|
|||||||
type: "VIRTUAL_GOODS",
|
type: "VIRTUAL_GOODS",
|
||||||
check: false,
|
check: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "商品模板导入",
|
|
||||||
img: require("@/assets/goodsTypeTpl.png"),
|
|
||||||
desc: "商品模板,一键导入",
|
|
||||||
check: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
// 商品分类选择数组
|
// 商品分类选择数组
|
||||||
category: [
|
category: [
|
||||||
@@ -137,29 +106,9 @@ export default {
|
|||||||
categoryListLevel2: [],
|
categoryListLevel2: [],
|
||||||
/** 3级分类列表*/
|
/** 3级分类列表*/
|
||||||
categoryListLevel3: [],
|
categoryListLevel3: [],
|
||||||
searchParams: {
|
|
||||||
saveType: "TEMPLATE",
|
|
||||||
sort: "create_time",
|
|
||||||
order: "desc",
|
|
||||||
pageSize: 10,
|
|
||||||
pageNumber: 1,
|
|
||||||
},
|
|
||||||
templateTotal: 0,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 商品模版触底加载
|
|
||||||
handleReachBottom() {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (
|
|
||||||
this.searchParams.pageNumber * this.searchParams.pageSize <=
|
|
||||||
this.templateTotal
|
|
||||||
) {
|
|
||||||
this.searchParams.pageNumber++;
|
|
||||||
this.GET_GoodsTemplate();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
// 点击商品类型
|
// 点击商品类型
|
||||||
handleClickGoodsType(val) {
|
handleClickGoodsType(val) {
|
||||||
this.goodsTypeWay.map((item) => {
|
this.goodsTypeWay.map((item) => {
|
||||||
@@ -167,28 +116,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
val.check = !val.check;
|
val.check = !val.check;
|
||||||
if (!val.type) {
|
this.goodsType = val.type;
|
||||||
this.GET_GoodsTemplate();
|
|
||||||
this.showGoodsTemplates = true;
|
|
||||||
} else {
|
|
||||||
this.goodsType = val.type;
|
|
||||||
this.selectedTemplate = {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 点击商品模板
|
|
||||||
handleClickGoodsTemplate(val) {
|
|
||||||
this.selectedTemplate = val;
|
|
||||||
this.selectGoodsType = false;
|
|
||||||
this.$emit("change", { tempId: val.id });
|
|
||||||
},
|
|
||||||
// 获取商品模板
|
|
||||||
GET_GoodsTemplate() {
|
|
||||||
API_GOODS.getDraftGoodsListData(this.searchParams).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
this.goodsTemplates.push(...res.result.records);
|
|
||||||
this.templateTotal = res.result.total;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
/** 选择商城商品分类 */
|
/** 选择商城商品分类 */
|
||||||
handleSelectCategory(row, index, level) {
|
handleSelectCategory(row, index, level) {
|
||||||
@@ -223,7 +151,7 @@ export default {
|
|||||||
// 下一步
|
// 下一步
|
||||||
next() {
|
next() {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
if (!this.goodsType && !this.selectedTemplate.goodsName) {
|
if (!this.goodsType) {
|
||||||
this.$Message.error("请选择商品类型");
|
this.$Message.error("请选择商品类型");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -238,12 +166,7 @@ export default {
|
|||||||
category: this.category,
|
category: this.category,
|
||||||
goodsType: this.goodsType,
|
goodsType: this.goodsType,
|
||||||
};
|
};
|
||||||
if (this.selectedTemplate.id) {
|
this.$emit("change", params);
|
||||||
params.tempId = this.selectedTemplate.id;
|
|
||||||
this.$emit("change", params);
|
|
||||||
} else {
|
|
||||||
this.$emit("change", params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -254,7 +177,4 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./addGoods.scss";
|
@import "./addGoods.scss";
|
||||||
::v-deep .ivu-scroll-container {
|
|
||||||
height: 450px !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -32,10 +32,8 @@
|
|||||||
<Button class="refresh-icon" icon="md-refresh" shape="circle" type="text"
|
<Button class="refresh-icon" icon="md-refresh" shape="circle" type="text"
|
||||||
@click="refresh('brand')"></Button>
|
@click="refresh('brand')"></Button>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
|
||||||
<h4>商品交易信息</h4>
|
<FormItem class="form-item-view-el" label="计量单位" prop="goodsUnit">
|
||||||
<div class="form-item-view">
|
|
||||||
<FormItem class="form-item-view-el" label="计量单位" prop="goodsUnit">
|
|
||||||
<Select v-model="baseInfoForm.goodsUnit" style="width: 100px">
|
<Select v-model="baseInfoForm.goodsUnit" style="width: 100px">
|
||||||
<Option v-for="(item, index) in goodsUnitList" :key="index" :value="item">{{ item }}
|
<Option v-for="(item, index) in goodsUnitList" :key="index" :value="item">{{ item }}
|
||||||
</Option>
|
</Option>
|
||||||
@@ -97,7 +95,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
<FormItem class="form-item-view-el" label="商品发布" prop="release">
|
||||||
|
<RadioGroup v-model="baseInfoForm.release" button-style="solid" type="button">
|
||||||
|
<Radio :label="1" title="上架">
|
||||||
|
<span>上架</span>
|
||||||
|
</Radio>
|
||||||
|
<Radio :label="0" title="下架">
|
||||||
|
<span>下架</span>
|
||||||
|
</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>商品规格及图片</h4>
|
<h4>商品规格及图片</h4>
|
||||||
<div class="form-item-view">
|
<div class="form-item-view">
|
||||||
<FormItem class="form-item-view-el required" label="主图" prop="goodsGalleryFiles">
|
<FormItem class="form-item-view-el required" label="主图" prop="goodsGalleryFiles">
|
||||||
@@ -380,56 +389,18 @@
|
|||||||
<span slot="append">kg</span></Input>
|
<span slot="append">kg</span></Input>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
<h4>其他信息</h4>
|
<h4>参数信息</h4>
|
||||||
<div class="form-item-view">
|
<div class="form-item-view">
|
||||||
<FormItem class="form-item-view-el" label="商品发布" prop="release">
|
<FormItem v-for="(paramsItem, paramsIndex) in goodsParams" :key="paramsItem.id || paramsIndex"
|
||||||
<RadioGroup v-model="baseInfoForm.release" button-style="solid" type="button">
|
:label="`${paramsItem.paramName}:`"
|
||||||
<Radio :label="1" title="立即发布">
|
:rules="{ required: !!paramsItem.required, message: '参数不能为空', trigger: 'change' }">
|
||||||
<span>立即发布</span>
|
<Select v-model="paramsItem.paramValue" clearable placeholder="请选择" style="width: 200px"
|
||||||
</Radio>
|
@on-change="(val) => selectParams(paramsItem, val)">
|
||||||
<Radio :label="0" title="放入仓库">
|
<Option v-for="option in getParamOptions(paramsItem.options)" :key="option" :label="option"
|
||||||
<span>放入仓库</span>
|
:value="option">
|
||||||
</Radio>
|
</Option>
|
||||||
</RadioGroup>
|
</Select>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem class="form-item-view-el" label="商品推荐" prop="skuList">
|
|
||||||
<RadioGroup v-model="baseInfoForm.recommend" button-style="solid" type="button">
|
|
||||||
<Radio :label="1" title="推荐">
|
|
||||||
<span>推荐</span>
|
|
||||||
</Radio>
|
|
||||||
<Radio :label="0" title="不推荐">
|
|
||||||
<span>不推荐</span>
|
|
||||||
</Radio>
|
|
||||||
</RadioGroup>
|
|
||||||
</FormItem>
|
|
||||||
</div>
|
|
||||||
<div class="form-item-view-bottom">
|
|
||||||
<Collapse v-for="(paramsGroup, groupIndex) in goodsParams" :key="paramsGroup.groupName"
|
|
||||||
v-model="params_panel" :title="paramsGroup.groupName" class="mb_10" style="text-align: left">
|
|
||||||
<Panel :name="paramsGroup.groupName">
|
|
||||||
{{ paramsGroup.groupName }}
|
|
||||||
<p slot="content">
|
|
||||||
<FormItem v-for="(paramsItem, paramsIndex) in paramsGroup.params" :key="paramsIndex"
|
|
||||||
:label="`${paramsItem.paramName}:`"
|
|
||||||
:rules="{ required: paramsItem.required, message: '参数不能为空', trigger: 'blur' }">
|
|
||||||
<Select v-model="paramsItem.paramValue" clearable placeholder="请选择" style="width: 200px"
|
|
||||||
@on-change="
|
|
||||||
selectParams(
|
|
||||||
paramsGroup,
|
|
||||||
groupIndex,
|
|
||||||
paramsItem,
|
|
||||||
paramsIndex,
|
|
||||||
paramsItem.paramValue
|
|
||||||
)
|
|
||||||
">
|
|
||||||
<Option v-for="option in paramsItem.options.split(',')" :key="option" :label="option"
|
|
||||||
:value="option">
|
|
||||||
</Option>
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
</p>
|
|
||||||
</Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -442,7 +413,6 @@
|
|||||||
<Button :loading="submitLoading" type="primary" @click="save">
|
<Button :loading="submitLoading" type="primary" @click="save">
|
||||||
{{ this.$route.query.id ? "保存" : "保存商品" }}
|
{{ this.$route.query.id ? "保存" : "保存商品" }}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" @click="saveToDraft">保存为模版</Button>
|
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -519,7 +489,7 @@ export default {
|
|||||||
previewImage: '', // 预览图片地址
|
previewImage: '', // 预览图片地址
|
||||||
global: 0,
|
global: 0,
|
||||||
accessToken: "", //令牌token
|
accessToken: "", //令牌token
|
||||||
goodsParams: "",
|
goodsParams: [],
|
||||||
categoryId: "", // 商品分类第三级id
|
categoryId: "", // 商品分类第三级id
|
||||||
//提交状态
|
//提交状态
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
@@ -763,54 +733,41 @@ export default {
|
|||||||
mouseLeave() {
|
mouseLeave() {
|
||||||
// this.showContent = false
|
// this.showContent = false
|
||||||
},
|
},
|
||||||
/**
|
getParamOptions(options) {
|
||||||
* 选择参数
|
if (!options) return [];
|
||||||
* @paramsGroup 参数分组
|
return String(options)
|
||||||
* @groupIndex 参数分组下标
|
.split(",")
|
||||||
* @params 参数选项
|
.map((i) => i.trim())
|
||||||
* @paramIndex 参数下标值
|
.filter((i) => i);
|
||||||
* @value 参数选项值
|
},
|
||||||
*/
|
selectParams(params, value) {
|
||||||
selectParams(paramsGroup, groupIndex, params, paramsIndex, value) {
|
if (!Array.isArray(this.baseInfoForm.goodsParamsDTOList)) {
|
||||||
if (!this.baseInfoForm.goodsParamsDTOList[groupIndex]) {
|
this.$set(this.baseInfoForm, "goodsParamsDTOList", []);
|
||||||
this.baseInfoForm.goodsParamsDTOList[groupIndex] = {
|
|
||||||
groupId: "",
|
|
||||||
groupName: "",
|
|
||||||
goodsParamsItemDTOList: [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
//赋予分组id、分组名称
|
const list = this.baseInfoForm.goodsParamsDTOList;
|
||||||
this.baseInfoForm.goodsParamsDTOList[groupIndex].groupId =
|
const paramId = params && params.id ? String(params.id) : "";
|
||||||
paramsGroup.groupId;
|
const index = list.findIndex((i) => String(i.paramId) === paramId);
|
||||||
this.baseInfoForm.goodsParamsDTOList[groupIndex].groupName =
|
|
||||||
paramsGroup.groupName;
|
|
||||||
|
|
||||||
//参数详细为空,则赋予
|
if (!value && value !== 0) {
|
||||||
if (
|
if (index >= 0) {
|
||||||
!this.baseInfoForm.goodsParamsDTOList[groupIndex]
|
list.splice(index, 1);
|
||||||
.goodsParamsItemDTOList[paramsIndex]
|
}
|
||||||
) {
|
return;
|
||||||
this.baseInfoForm.goodsParamsDTOList[groupIndex].goodsParamsItemDTOList[
|
|
||||||
paramsIndex
|
|
||||||
] = {
|
|
||||||
paramName: "",
|
|
||||||
paramValue: "",
|
|
||||||
isIndex: "",
|
|
||||||
// required: "",
|
|
||||||
paramId: "",
|
|
||||||
sort: "",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
this.baseInfoForm.goodsParamsDTOList[groupIndex].goodsParamsItemDTOList[
|
const newItem = {
|
||||||
paramsIndex
|
paramId,
|
||||||
] = {
|
|
||||||
paramName: params.paramName,
|
paramName: params.paramName,
|
||||||
paramValue: value,
|
paramValue: value,
|
||||||
isIndex: params.isIndex,
|
isIndex: params.isIndex || 0,
|
||||||
// required: params.required,
|
required: params.required || 0,
|
||||||
paramId: params.id,
|
sort: params.sort || 0,
|
||||||
sort: params.sort,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
this.$set(list, index, newItem);
|
||||||
|
} else {
|
||||||
|
list.push(newItem);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 编辑sku图片
|
// 编辑sku图片
|
||||||
editSkuPicture(row) {
|
editSkuPicture(row) {
|
||||||
@@ -1191,40 +1148,75 @@ export default {
|
|||||||
|
|
||||||
/** 根据当前分类id查询商品应包含的参数 */
|
/** 根据当前分类id查询商品应包含的参数 */
|
||||||
GET_GoodsParams() {
|
GET_GoodsParams() {
|
||||||
this.goodsParams = []
|
this.goodsParams = [];
|
||||||
|
this.params_panel = [];
|
||||||
API_GOODS.getCategoryParamsListDataSeller(this.categoryId).then(
|
API_GOODS.getCategoryParamsListDataSeller(this.categoryId).then(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (!response || response.length <= 0) {
|
if (!response || response.length <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.goodsParams = response;
|
|
||||||
|
|
||||||
//展开选项卡
|
if (!Array.isArray(this.baseInfoForm.goodsParamsDTOList)) {
|
||||||
this.goodsParams.forEach((item) => {
|
|
||||||
this.params_panel.push(item.groupName);
|
|
||||||
});
|
|
||||||
if (this.baseInfoForm.goodsParamsDTOList) {
|
|
||||||
// 已选值集合
|
|
||||||
const paramsArr = [];
|
|
||||||
this.baseInfoForm.goodsParamsDTOList.forEach((group) => {
|
|
||||||
group.goodsParamsItemDTOList.forEach((param) => {
|
|
||||||
param.groupId = group.groupId;
|
|
||||||
paramsArr.push(param);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// 循环参数分组
|
|
||||||
this.goodsParams.forEach((paramsGroup) => {
|
|
||||||
paramsGroup.params.forEach((param) => {
|
|
||||||
paramsArr.forEach((arr) => {
|
|
||||||
if (param.paramName === arr.paramName) {
|
|
||||||
param.paramValue = arr.paramValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.baseInfoForm.goodsParamsDTOList = [];
|
this.baseInfoForm.goodsParamsDTOList = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mergedSelected = new Map();
|
||||||
|
const selectedList = [];
|
||||||
|
this.baseInfoForm.goodsParamsDTOList.forEach((item) => {
|
||||||
|
if (!item) return;
|
||||||
|
if (Array.isArray(item.goodsParamsItemDTOList)) {
|
||||||
|
selectedList.push(...item.goodsParamsItemDTOList);
|
||||||
|
} else if (item.paramId || item.paramName) {
|
||||||
|
selectedList.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectedList.forEach((param) => {
|
||||||
|
if (!param) return;
|
||||||
|
const key = param.paramId ? String(param.paramId) : param.paramName;
|
||||||
|
if (!key) return;
|
||||||
|
mergedSelected.set(key, param);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.baseInfoForm.goodsParamsDTOList = Array.from(mergedSelected.values()).map((p) => {
|
||||||
|
return {
|
||||||
|
paramId: p.paramId ? String(p.paramId) : "",
|
||||||
|
paramName: p.paramName,
|
||||||
|
paramValue: p.paramValue,
|
||||||
|
isIndex: p.isIndex || 0,
|
||||||
|
required: p.required || 0,
|
||||||
|
sort: p.sort || 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const findSelectedValue = (param) => {
|
||||||
|
if (!param) return undefined;
|
||||||
|
const byId = mergedSelected.get(String(param.id));
|
||||||
|
if (byId) return byId.paramValue;
|
||||||
|
const byName = mergedSelected.get(param.paramName);
|
||||||
|
if (byName) return byName.paramValue;
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isGrouped = response[0] && Array.isArray(response[0].params);
|
||||||
|
const flatParams = isGrouped
|
||||||
|
? response.reduce((acc, g) => {
|
||||||
|
if (g && Array.isArray(g.params)) {
|
||||||
|
acc.push(...g.params);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, [])
|
||||||
|
: response;
|
||||||
|
|
||||||
|
this.goodsParams = flatParams
|
||||||
|
.map((p) => {
|
||||||
|
const selectedValue = findSelectedValue(p);
|
||||||
|
return {
|
||||||
|
...p,
|
||||||
|
paramValue:
|
||||||
|
selectedValue !== undefined ? selectedValue : p.paramValue,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => Number(a.sort || 0) - Number(b.sort || 0));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -1935,18 +1927,16 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let checkFlag = false;
|
let checkFlag = false;
|
||||||
this.goodsParams.forEach(group => {
|
this.goodsParams.forEach((param) => {
|
||||||
group.params.forEach(param => {
|
if (!param || !param.required) return;
|
||||||
if (param.required) {
|
const check = this.baseInfoForm.goodsParamsDTOList.some((paramsItem) => {
|
||||||
const check = this.baseInfoForm.goodsParamsDTOList.some(paramsGroup =>
|
if (String(paramsItem.paramId) !== String(param.id)) return false;
|
||||||
paramsGroup.goodsParamsItemDTOList.some(paramsItem => paramsItem.paramId === param.id)
|
return !!paramsItem.paramValue;
|
||||||
);
|
});
|
||||||
if (!check) {
|
if (!check) {
|
||||||
checkFlag = !check;
|
checkFlag = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
})
|
|
||||||
if (checkFlag) {
|
if (checkFlag) {
|
||||||
this.$Message.error("存在未填写的参数项");
|
this.$Message.error("存在未填写的参数项");
|
||||||
return;
|
return;
|
||||||
@@ -2078,57 +2068,6 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 保存为模板 */
|
|
||||||
saveToDraft() {
|
|
||||||
this.baseInfoForm.skuList = this.skuTableData;
|
|
||||||
if (this.baseInfoForm.goodsGalleryFiles.length > 0) {
|
|
||||||
this.baseInfoForm.goodsGalleryList =
|
|
||||||
this.baseInfoForm.goodsGalleryFiles.map((i) => i);
|
|
||||||
}
|
|
||||||
this.baseInfoForm.categoryName = [];
|
|
||||||
this.baseInfoForm.saveType = "TEMPLATE";
|
|
||||||
|
|
||||||
if (this.$route.query.draftId) {
|
|
||||||
this.baseInfoForm.id = this.$route.query.draftId;
|
|
||||||
this.$Modal.confirm({
|
|
||||||
title: "当前模板已存在",
|
|
||||||
content: "当前模板已存在,保存为新模板或替换原模板",
|
|
||||||
okText: "保存新模板",
|
|
||||||
cancelText: "替换旧模板",
|
|
||||||
closable: true,
|
|
||||||
onOk: () => {
|
|
||||||
delete this.baseInfoForm.id;
|
|
||||||
this.SAVE_DRAFT_GOODS();
|
|
||||||
},
|
|
||||||
onCancel: () => {
|
|
||||||
this.SAVE_DRAFT_GOODS();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$Modal.confirm({
|
|
||||||
title: "保存模板",
|
|
||||||
content: "是否确定保存",
|
|
||||||
okText: "保存",
|
|
||||||
closable: true,
|
|
||||||
onOk: () => {
|
|
||||||
this.SAVE_DRAFT_GOODS();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
SAVE_DRAFT_GOODS() {
|
|
||||||
if (this.baseInfoForm.salesModel === "WHOLESALE") {
|
|
||||||
this.baseInfoForm.wholesaleList = this.wholesaleData;
|
|
||||||
}
|
|
||||||
// 保存模板
|
|
||||||
API_GOODS.saveDraftGoods(this.baseInfoForm).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
this.$Message.info("保存成功!");
|
|
||||||
this.$router.push({ name: "template-goods" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
GET_ShipTemplate(type) {
|
GET_ShipTemplate(type) {
|
||||||
// 获取物流模板
|
// 获取物流模板
|
||||||
API_Shop.getShipTemplate().then((res) => {
|
API_Shop.getShipTemplate().then((res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user