2025-03-26
This commit is contained in:
62
src/views/productManagement/attributeList/constant/edit.ts
Normal file
62
src/views/productManagement/attributeList/constant/edit.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
disabled?: boolean;
|
||||
}
|
||||
export const EDIT_FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "attr_name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "属性: ",
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
prop: "propsStr",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "属性值: ",
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
prop: "addAttribute",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "新增属性值: "
|
||||
}
|
||||
];
|
||||
|
||||
export const ADD_FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "attr_name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "属性: "
|
||||
},
|
||||
{
|
||||
prop: "propsStr",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "属性值: ",
|
||||
disabled: false
|
||||
}
|
||||
];
|
||||
|
||||
export const EDIT_RULE_FORM = {
|
||||
attr_name: "", //属性
|
||||
propsStr: "", //属性值
|
||||
addAttribute: "" //新增
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { SEARCH_DATA, RULE_FORM } from "./search";
|
||||
import { COLUMNS } from "./table";
|
||||
import { RULES } from "./rules";
|
||||
import { EDIT_FORM_DATA, EDIT_RULE_FORM, ADD_FORM_DATA } from "./edit";
|
||||
export { SEARCH_DATA, RULE_FORM, COLUMNS, RULES, EDIT_FORM_DATA, EDIT_RULE_FORM, ADD_FORM_DATA };
|
||||
@@ -0,0 +1,4 @@
|
||||
export const RULES = {
|
||||
attr_name: [{ required: true, message: "产品属性不能为空 ! ", trigger: "blur" }]
|
||||
// attributeValue: [{ required: true, message: "产品属性值不能为空 ! ", trigger: "blur" }]
|
||||
};
|
||||
30
src/views/productManagement/attributeList/constant/search.ts
Normal file
30
src/views/productManagement/attributeList/constant/search.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
}
|
||||
export const SEARCH_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "keywords",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "属性: "
|
||||
}
|
||||
];
|
||||
|
||||
export const RULE_FORM = {
|
||||
page: 1,
|
||||
size: 50
|
||||
};
|
||||
33
src/views/productManagement/attributeList/constant/table.ts
Normal file
33
src/views/productManagement/attributeList/constant/table.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { RenderScope } from "@/components/ProTable/interface";
|
||||
export const COLUMNS = [
|
||||
{
|
||||
align: "center",
|
||||
fixed: true,
|
||||
label: "ID",
|
||||
prop: "id"
|
||||
},
|
||||
|
||||
{
|
||||
align: "left",
|
||||
label: "属性",
|
||||
prop: "attr_name"
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "属性值",
|
||||
prop: "props",
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
let arr: any = [];
|
||||
if (scope.row.props.length) {
|
||||
scope.row.props.forEach((item: any) => {
|
||||
arr.push(item.prop_name);
|
||||
});
|
||||
return arr.join(",");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{ prop: "operation", label: "操作", fixed: "right", width: 160 }
|
||||
];
|
||||
202
src/views/productManagement/attributeList/index.vue
Normal file
202
src/views/productManagement/attributeList/index.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<!-- 属性列表 -->
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<div style="padding-bottom: 16px">
|
||||
<el-button type="primary" @click="handleAdd"> 添加 </el-button>
|
||||
</div>
|
||||
<ProTable
|
||||
ref="proTableRef"
|
||||
:formData="dataStore.formData"
|
||||
:columns="dataStore.columns"
|
||||
:request-api="getProductAttrListApi"
|
||||
:init-param="dataStore.initParam"
|
||||
>
|
||||
<template #operation="scope">
|
||||
<el-button size="small" type="primary" @click="handleBtnClick(scope.row)" v-if="scope.row.id !== 1"
|
||||
>编辑</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
<!-- :show-close="false" -->
|
||||
<el-drawer
|
||||
v-model="dataStore.visible"
|
||||
:show-close="true"
|
||||
:size="600"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:before-close="handleBeforeClone"
|
||||
destroy-on-close
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<h4 :id="titleId" :class="titleClass">{{ dataStore.title }}</h4>
|
||||
</template>
|
||||
<div>
|
||||
<rulesForm
|
||||
:ruleForm="dataStore.editRuleForm"
|
||||
:formData="dataStore.editFormData"
|
||||
:rules="dataStore.rules"
|
||||
ref="formRef"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="handleResetClick">重置</el-button>
|
||||
<el-button type="primary" @click="handleConfirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productAttributeListIndex">
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import rulesForm from "@/components/rulesForm/index.vue";
|
||||
import qs from "qs";
|
||||
//接口
|
||||
import {
|
||||
getProductAttrListApi,
|
||||
getProductAttrDetailsApi,
|
||||
getProductAttrUpApi,
|
||||
getProductAttrAddApi
|
||||
} from "@/api/modules/productAttributeList";
|
||||
//深拷贝方法
|
||||
import { cloneDeep } from "lodash-es";
|
||||
//表格和搜索條件
|
||||
import { RULE_FORM, COLUMNS, RULES, SEARCH_DATA, EDIT_FORM_DATA, EDIT_RULE_FORM, ADD_FORM_DATA } from "./constant/index";
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||||
const proTableRef = ref<any>(null);
|
||||
// 数据源
|
||||
const dataStore = reactive<any>({
|
||||
title: "编辑产品属性",
|
||||
rules: cloneDeep(RULES), //抽屉表单验证
|
||||
row: {},
|
||||
editRuleForm: cloneDeep(EDIT_RULE_FORM),
|
||||
editFormData: cloneDeep(EDIT_FORM_DATA), //抽屉表单配置项
|
||||
visible: false, //抽屉控制
|
||||
columns: COLUMNS, //列表配置项
|
||||
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
|
||||
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
|
||||
formData: SEARCH_DATA //搜索配置项
|
||||
});
|
||||
const formRef: any = ref(null);
|
||||
//设置表单
|
||||
const handleSetRuleForm = () => {
|
||||
dataStore.editRuleForm.attributeKey = dataStore.row.productName;
|
||||
dataStore.editRuleForm.attributeValue = dataStore.row.model;
|
||||
};
|
||||
|
||||
//编辑
|
||||
const handleBtnClick = (row: any) => {
|
||||
dataStore.visible = true;
|
||||
dataStore.title = "编辑产品属性";
|
||||
dataStore.editFormData = cloneDeep(EDIT_FORM_DATA);
|
||||
dataStore.row = cloneDeep(row);
|
||||
dataStore.editFormData[0].disabled = true;
|
||||
handleSetRuleForm();
|
||||
getProductAttrDetails(row.id);
|
||||
};
|
||||
//更新
|
||||
const getProductAttrUp = async () => {
|
||||
let obj = {
|
||||
prop_name: dataStore.editRuleForm.addAttribute,
|
||||
prop_value: dataStore.editRuleForm.addAttribute
|
||||
};
|
||||
if (obj.prop_name) {
|
||||
dataStore.editRuleForm.props.push(obj);
|
||||
}
|
||||
const result = await getProductAttrUpApi(dataStore.editRuleForm);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
dataStore.visible = false;
|
||||
handleClear();
|
||||
// getProductAttrDetails(dataStore.editRuleForm.id);
|
||||
}
|
||||
};
|
||||
//添加
|
||||
const getProductAttrAdd = async () => {
|
||||
let params = {
|
||||
attr_name: dataStore.editRuleForm.attr_name,
|
||||
props: JSON.stringify([
|
||||
{
|
||||
prop_name: dataStore.editRuleForm.propsStr,
|
||||
prop_value: dataStore.editRuleForm.propsStr
|
||||
}
|
||||
])
|
||||
};
|
||||
const result = await getProductAttrAddApi(qs.stringify(params));
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
dataStore.visible = false;
|
||||
handleClear();
|
||||
}
|
||||
};
|
||||
//详情
|
||||
const getProductAttrDetails = async (id: any) => {
|
||||
const result = await getProductAttrDetailsApi(id);
|
||||
if (result?.code === 0) {
|
||||
dataStore.editRuleForm = cloneDeep(result?.data);
|
||||
|
||||
if (dataStore.editRuleForm.props.length) {
|
||||
let arr: any = [];
|
||||
|
||||
dataStore.editRuleForm.props.forEach((item: any) => {
|
||||
arr.push(item.prop_name);
|
||||
});
|
||||
|
||||
dataStore.editRuleForm.propsStr = arr.length ? arr.join(",") : [];
|
||||
}
|
||||
}
|
||||
};
|
||||
//清空表单数据
|
||||
const handleClear = () => {
|
||||
for (let key in dataStore.editRuleForm) {
|
||||
dataStore.editRuleForm[key] = "";
|
||||
}
|
||||
};
|
||||
//添加
|
||||
const handleAdd = () => {
|
||||
dataStore.visible = true;
|
||||
dataStore.title = "添加产品属性";
|
||||
dataStore.editFormData = cloneDeep(ADD_FORM_DATA);
|
||||
handleClear();
|
||||
};
|
||||
//重置验证
|
||||
const resetFields = () => {
|
||||
if (!formRef.value!.ruleFormRef) return;
|
||||
formRef!.value!.ruleFormRef.resetFields();
|
||||
};
|
||||
//抽屉关闭前的钩子
|
||||
const handleBeforeClone = () => {
|
||||
dataStore.visible = false;
|
||||
dataStore.editRuleForm.addAttribute = "";
|
||||
resetFields();
|
||||
handleClear();
|
||||
};
|
||||
//重置按钮
|
||||
const handleResetClick = () => {
|
||||
if (dataStore.title === "添加产品属性") {
|
||||
dataStore.editRuleForm.addAttribute = "";
|
||||
handleSetRuleForm();
|
||||
resetFields();
|
||||
} else {
|
||||
getProductAttrDetails(dataStore.row.id);
|
||||
}
|
||||
};
|
||||
//确认
|
||||
const handleConfirmClick = async () => {
|
||||
if (!formRef.value!.ruleFormRef) return;
|
||||
formRef!.value!.ruleFormRef!.validate((valid: any) => {
|
||||
if (valid) {
|
||||
dataStore.title === "添加产品属性" ? getProductAttrAdd() : getProductAttrUp();
|
||||
} else {
|
||||
console.log("error submit!");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,3 @@
|
||||
import { handleSubmit } from "./submit";
|
||||
import { handleReset } from "./reset";
|
||||
export { handleSubmit, handleReset };
|
||||
@@ -0,0 +1,7 @@
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
export const handleReset = (dataStore: any) => {
|
||||
messageBox("该操作会将数据重置为初始状态", () => {
|
||||
dataStore.basicInfoRuleForm = cloneDeep(dataStore.resetBasicInfoRuleForm);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
const WARN: any = {
|
||||
name: "产品名称不能为空 !",
|
||||
model: "型号不能为空 !",
|
||||
type: "产品分类不能为空 !",
|
||||
sort: "产品排序不能为空 !"
|
||||
};
|
||||
const warnFunction = (data: any) => {
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["name"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.model) {
|
||||
useMsg("warning", WARN["model"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.type) {
|
||||
useMsg("warning", WARN["type"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["sort"]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
export const handleSubmit = async (infoRef: any) => {
|
||||
console.log(infoRef.ruleForm, "============ruleForm===========");
|
||||
|
||||
let is = await warnFunction(infoRef.ruleForm);
|
||||
if (!is) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ElMessageBox } from "element-plus";
|
||||
|
||||
export const messageBox = (message: any, callback: any) => {
|
||||
ElMessageBox.confirm(message, "警告", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
console.log("132323");
|
||||
callback && callback();
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("取消323232");
|
||||
});
|
||||
};
|
||||
123
src/views/productManagement/classList/constant/form.ts
Normal file
123
src/views/productManagement/classList/constant/form.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
//新增产品分类
|
||||
export const FORM_DATA_LV1: any[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品分类名称: "
|
||||
},
|
||||
{
|
||||
prop: "pid",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelect",
|
||||
label: "所属分类: ",
|
||||
options: []
|
||||
},
|
||||
{
|
||||
prop: "sort",
|
||||
placeholder: "请输入",
|
||||
type: "inputNumber",
|
||||
label: "产品分类排序: "
|
||||
},
|
||||
{
|
||||
prop: "is_show",
|
||||
placeholder: "请输入",
|
||||
type: "radio",
|
||||
label: "是否显示: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
//编辑产品分类
|
||||
export const EDIT_FORM_DATA_LV1: any[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品分类名称: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "pid",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelect",
|
||||
label: "所属分类: ",
|
||||
options: []
|
||||
},
|
||||
{
|
||||
prop: "sort",
|
||||
placeholder: "请输入",
|
||||
type: "inputNumber",
|
||||
label: "产品分类排序: "
|
||||
},
|
||||
{
|
||||
prop: "is_show",
|
||||
placeholder: "请输入",
|
||||
type: "radio",
|
||||
label: "是否显示: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const FORM_DATA_LV2: any[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品分类名称: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "pid",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelect",
|
||||
label: "所属分类: ",
|
||||
options: []
|
||||
},
|
||||
{
|
||||
prop: "related_tco_category",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelects",
|
||||
label: "对应成本系统分类: ",
|
||||
options: []
|
||||
},
|
||||
{
|
||||
prop: "sort",
|
||||
placeholder: "请输入",
|
||||
type: "inputNumber",
|
||||
label: "产品分类排序: "
|
||||
},
|
||||
{
|
||||
prop: "is_show",
|
||||
placeholder: "请输入",
|
||||
type: "radio",
|
||||
label: "是否显示: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
5
src/views/productManagement/classList/constant/index.ts
Normal file
5
src/views/productManagement/classList/constant/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { FORM_DATA_LV1, FORM_DATA_LV2 } from "./form";
|
||||
import { RULES_LV1, RULES_LV2 } from "./rules";
|
||||
import { RULE_FORM_LV1, RULE_FORM_LV2 } from "./ruleForm";
|
||||
import { SEARCH } from "./search";
|
||||
export { FORM_DATA_LV1, FORM_DATA_LV2, RULES_LV1, RULES_LV2, RULE_FORM_LV1, RULE_FORM_LV2, SEARCH };
|
||||
@@ -0,0 +1,6 @@
|
||||
export const RULE_FORM_LV1: any = {
|
||||
sort: 1
|
||||
};
|
||||
export const RULE_FORM_LV2: any = {
|
||||
sort: 1
|
||||
};
|
||||
15
src/views/productManagement/classList/constant/rules.ts
Normal file
15
src/views/productManagement/classList/constant/rules.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export const RULES_LV1 = {
|
||||
name: [{ required: true, message: "产品分类名称不能为空 ! ", trigger: "blur" }],
|
||||
pid: [{ required: true, message: "所属分类不能为空 ! ", trigger: "change" }],
|
||||
sort: [{ required: true, message: "产品分类排序不能为空 ! ", trigger: "blur" }],
|
||||
is_show: [{ required: true, message: "请选择是否展示 ! ", trigger: "change" }],
|
||||
related_tco_category: [{ required: true, message: "所属分类不能为空 ! ", trigger: "change" }]
|
||||
};
|
||||
export const RULES_LV2 = {
|
||||
name: [{ required: true, message: "产品分类名称不能为空 ! ", trigger: "blur" }],
|
||||
// id: [{ required: true, message: "产品分类ID不能为空 ! ", trigger: "blur" }],
|
||||
pid: [{ required: true, message: "所属分类不能为空 ! ", trigger: "change" }],
|
||||
costSystemType: [{ required: true, message: "对应成本系统分类不能为空 ! ", trigger: "change" }],
|
||||
sort: [{ required: true, message: "产品分类排序不能为空 ! ", trigger: "blur" }],
|
||||
is_show: [{ required: true, message: "请选择是否展示 ! ", trigger: "change" }]
|
||||
};
|
||||
9
src/views/productManagement/classList/constant/search.ts
Normal file
9
src/views/productManagement/classList/constant/search.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export const SEARCH = [
|
||||
{
|
||||
prop: "keywords",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "分类名称"
|
||||
}
|
||||
];
|
||||
291
src/views/productManagement/classList/index.vue
Normal file
291
src/views/productManagement/classList/index.vue
Normal file
@@ -0,0 +1,291 @@
|
||||
<!-- 分类列表 -->
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<div class="card table-main">
|
||||
<SearchForm
|
||||
:search="search"
|
||||
:reset="reset"
|
||||
:formData="dataStore.searchFormData"
|
||||
:search-param="dataStore.searchParam"
|
||||
/>
|
||||
<el-table
|
||||
:data="dataStore.tableData"
|
||||
style="width: 100%; margin-bottom: 20px; font-size: 14px"
|
||||
row-key="id"
|
||||
border
|
||||
default-expand-all
|
||||
>
|
||||
<el-table-column prop="id" label="id" />
|
||||
<el-table-column prop="name" label="分类名称" />
|
||||
<el-table-column prop="sort" label="分类排序">
|
||||
<template #default="{ row }">
|
||||
<div @click.stop="">
|
||||
<el-input v-model="row.sort" @blur="handleBlur(row)" @input="handleInput(row)" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="is_show" label="是否显示">
|
||||
<template #default="{ row }">
|
||||
{{ row.is_show === 1 ? "✔️" : "❌" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" :width="350">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleAddChild(scope.$index, scope.row)"
|
||||
v-if="scope.row.level != 3"
|
||||
>添加子类</el-button
|
||||
>
|
||||
<el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button
|
||||
type="info"
|
||||
size="small"
|
||||
style="cursor: not-allowed"
|
||||
@click="handleAddProduct(scope.$index, scope.row)"
|
||||
>添加产品</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="info"
|
||||
style="cursor: not-allowed"
|
||||
@click="handleDelete(scope.$index, scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-drawer
|
||||
v-model="dataStore.visible"
|
||||
:show-close="true"
|
||||
:size="600"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:before-close="handleBeforeClone"
|
||||
destroy-on-close
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<h4 :id="titleId" :class="titleClass">{{ dataStore.title }}</h4>
|
||||
</template>
|
||||
<rulesForm
|
||||
:ruleForm="dataStore.ruleForm"
|
||||
:formData="dataStore.formData"
|
||||
:rules="dataStore.rules"
|
||||
ref="formRef"
|
||||
@handleSelectChangeEmits="handleSelectChangeEmits"
|
||||
@handleTreesSelectChangeEmits="handleTreesSelectChangeEmits"
|
||||
/>
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="handleResetClick">重置</el-button>
|
||||
<el-button type="primary" @click="handleConfirmClick">提交</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productClassListIndex">
|
||||
import SearchForm from "@/components/SearchForm/index.vue";
|
||||
import rulesForm from "@/components/rulesForm/index.vue";
|
||||
import { integerRexg } from "@/utils/regexp/index";
|
||||
//getProductCategoryDelApi
|
||||
import {
|
||||
getProductCategoryListApi,
|
||||
getArticleCategorySaveApi,
|
||||
getProductClassCategoryReadApi,
|
||||
getProductCategoryUpdateApi,
|
||||
getArticleCategorySortApi,
|
||||
getProductClassTcoTreeApi
|
||||
} from "@/api/modules/productClass";
|
||||
import { addLabelValue } from "../list/utils/common/addLabelValue";
|
||||
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
|
||||
import { FORM_DATA_LV1, FORM_DATA_LV2, RULE_FORM_LV1, RULE_FORM_LV2, RULES_LV1, RULES_LV2, SEARCH } from "./constant/index";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const dataStore = reactive<any>({
|
||||
visible: false,
|
||||
title: "添加产品分类",
|
||||
selectLevel: 1,
|
||||
searchParam: {}, //搜索参数
|
||||
searchFormData: cloneDeep(SEARCH), //搜索配置
|
||||
ruleForm: cloneDeep(RULE_FORM_LV1),
|
||||
rules: cloneDeep(RULES_LV1),
|
||||
formData: cloneDeep(FORM_DATA_LV1),
|
||||
row: {},
|
||||
tableData: [],
|
||||
treeData: []
|
||||
});
|
||||
//成本系统
|
||||
const getProductClassTcoTree = async () => {
|
||||
const result = await getProductClassTcoTreeApi();
|
||||
if (result?.code === 0) {
|
||||
FORM_DATA_LV2[2].options = addLabelValue(result?.data);
|
||||
}
|
||||
};
|
||||
getProductClassTcoTree();
|
||||
//列表接口
|
||||
const getProductCategoryList = async () => {
|
||||
const result = await getProductCategoryListApi(dataStore.searchParam);
|
||||
if (result?.code === 0) {
|
||||
let tableData = cloneDeep(result?.data);
|
||||
dataStore.tableData = tableData;
|
||||
dataStore.treeData = [];
|
||||
dataStore.treeData = addLabelValue(tableData);
|
||||
dataStore.treeData.unshift({ value: 0, label: "无" });
|
||||
}
|
||||
};
|
||||
getProductCategoryList();
|
||||
//添加子类
|
||||
const getArticleCategorySave = async (params: any) => {
|
||||
const result = await getArticleCategorySaveApi(params);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
dataStore.visible = false;
|
||||
resetFrom();
|
||||
formRef!.value!.ruleFormRef.resetFields();
|
||||
getProductCategoryList();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectChangeEmits = (value: any) => {
|
||||
dataStore.ruleForm.pid = value.id;
|
||||
};
|
||||
const handleTreesSelectChangeEmits = (value: any) => {
|
||||
console.log(value, "=========value=========");
|
||||
};
|
||||
//更新接口
|
||||
const getProductCategoryUpdate = async () => {
|
||||
dataStore.ruleForm.related_tco_category = dataStore.ruleForm.related_tco_category
|
||||
? dataStore.ruleForm.related_tco_category.join(",")
|
||||
: dataStore.ruleForm.related_tco_category;
|
||||
const result = await getProductCategoryUpdateApi(dataStore.ruleForm);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
dataStore.visible = false;
|
||||
resetFrom();
|
||||
getProductCategoryList();
|
||||
}
|
||||
};
|
||||
//产品详情
|
||||
const getProductClassCategoryRead = async (id: any) => {
|
||||
const result = await getProductClassCategoryReadApi(id);
|
||||
if (result?.code === 0) {
|
||||
dataStore.ruleForm = result?.data;
|
||||
if (dataStore.ruleForm.related_tco_category) {
|
||||
dataStore.ruleForm.related_tco_category = dataStore.ruleForm.related_tco_category
|
||||
.split(",")
|
||||
.map((item: any) => Number(item));
|
||||
}
|
||||
setFormDatOptions();
|
||||
getProductCategoryList();
|
||||
}
|
||||
};
|
||||
//排序
|
||||
const getArticleCategorySort = async (row: any) => {
|
||||
const result = await getArticleCategorySortApi({ id: row.id, sort: row.sort });
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
getProductCategoryList();
|
||||
}
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
getProductCategoryList();
|
||||
};
|
||||
const reset = () => {
|
||||
dataStore.searchParam.keywords = "";
|
||||
getProductCategoryList();
|
||||
};
|
||||
//重置表单配置
|
||||
const resetFrom = () => {
|
||||
if (dataStore.selectLevel === 1 || dataStore.selectLevel === 2) {
|
||||
dataStore.ruleForm = cloneDeep(RULE_FORM_LV1);
|
||||
dataStore.formData = cloneDeep(FORM_DATA_LV1);
|
||||
dataStore.rules = RULES_LV1;
|
||||
}
|
||||
if (dataStore.selectLevel === 3) {
|
||||
dataStore.ruleForm = cloneDeep(RULE_FORM_LV2);
|
||||
dataStore.formData = cloneDeep(FORM_DATA_LV2);
|
||||
dataStore.rules = RULES_LV2;
|
||||
}
|
||||
};
|
||||
const setFormDatOptions = () => {
|
||||
// dataStore.formData[1].options = [];
|
||||
dataStore.formData[1].options = dataStore.treeData;
|
||||
// dataStore.formData[1].options.unshift({ value: 0, label: "无" });
|
||||
// console.log("12323");
|
||||
};
|
||||
//添加子类
|
||||
const handleAddChild = (index: any, row: any) => {
|
||||
dataStore.selectLevel = row.level;
|
||||
resetFrom();
|
||||
dataStore.visible = true;
|
||||
dataStore.title = "添加产品分类";
|
||||
setFormDatOptions();
|
||||
// dataStore.formData[1].options.unshift({ value: 0, label: "无" });
|
||||
// dataStore.formData[1].options = dataStore.treeData;
|
||||
};
|
||||
|
||||
//before-close
|
||||
const handleBeforeClone = () => {
|
||||
resetFrom();
|
||||
formRef!.value!.ruleFormRef.resetFields();
|
||||
dataStore.visible = false;
|
||||
};
|
||||
const handleEdit = (row: any) => {
|
||||
dataStore.selectLevel = row.level;
|
||||
dataStore.visible = true;
|
||||
dataStore.title = "编辑产品分类";
|
||||
dataStore.row = row;
|
||||
resetFrom();
|
||||
getProductClassCategoryRead(row.id);
|
||||
};
|
||||
//重置
|
||||
const handleResetClick = () => {
|
||||
if (dataStore.title === "添加产品分类") {
|
||||
formRef!.value!.ruleFormRef.resetFields();
|
||||
resetFrom();
|
||||
} else {
|
||||
getProductClassCategoryRead(dataStore.row.id);
|
||||
}
|
||||
};
|
||||
//提交
|
||||
const handleConfirmClick = () => {
|
||||
if (!formRef.value!.ruleFormRef) return;
|
||||
formRef!.value!.ruleFormRef!.validate((valid: any) => {
|
||||
if (valid) {
|
||||
dataStore.title === "编辑产品分类" ? getProductCategoryUpdate() : getArticleCategorySave(dataStore.ruleForm);
|
||||
console.log("submit!");
|
||||
} else {
|
||||
console.log("error submit!");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
//排序input框失焦
|
||||
const handleBlur = (row: any) => {
|
||||
getArticleCategorySort(row);
|
||||
};
|
||||
//
|
||||
const handleInput = (row: any) => {
|
||||
row.sort = integerRexg(row.sort);
|
||||
};
|
||||
|
||||
//添加产品
|
||||
const handleAddProduct = (index: any, row: any) => {
|
||||
console.log(index, row, "=========row========");
|
||||
};
|
||||
//删除
|
||||
const handleDelete = (index: any, row: any) => {
|
||||
// getProductCategoryDel(row.id);
|
||||
console.log(index, row, "=========row========");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
4
src/views/productManagement/link/constant/index.ts
Normal file
4
src/views/productManagement/link/constant/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { FORM_DATA, RULE_FORM } from "./search";
|
||||
import { COLUMNS } from "./table";
|
||||
import { OPERATIONS } from "./operations";
|
||||
export { FORM_DATA, RULE_FORM, COLUMNS, OPERATIONS };
|
||||
26
src/views/productManagement/link/constant/operations.ts
Normal file
26
src/views/productManagement/link/constant/operations.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export const OPERATIONS = [
|
||||
{
|
||||
name: "下架",
|
||||
name1: "上架",
|
||||
id: 1,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "添加SKU",
|
||||
name1: "添加SKU",
|
||||
id: 2,
|
||||
type: "info"
|
||||
},
|
||||
{
|
||||
name: "编辑",
|
||||
name1: "编辑",
|
||||
id: 3,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "删除",
|
||||
name1: "删除",
|
||||
id: 4,
|
||||
type: "info"
|
||||
}
|
||||
];
|
||||
38
src/views/productManagement/link/constant/search.ts
Normal file
38
src/views/productManagement/link/constant/search.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
}
|
||||
export const FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "产品名称: "
|
||||
},
|
||||
{
|
||||
prop: "spu",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "型号: "
|
||||
}
|
||||
];
|
||||
|
||||
export const RULE_FORM = {
|
||||
page: 1,
|
||||
size: 50
|
||||
};
|
||||
40
src/views/productManagement/link/constant/table.ts
Normal file
40
src/views/productManagement/link/constant/table.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
//import { RenderScope } from "@/components/ProTable/interface";
|
||||
export const COLUMNS = [
|
||||
{
|
||||
align: "center",
|
||||
fixed: true,
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
width: 80
|
||||
},
|
||||
|
||||
{
|
||||
align: "left",
|
||||
label: "产品名称",
|
||||
prop: "name",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "型号",
|
||||
prop: "spu",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "上架状态",
|
||||
prop: "is_show"
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "平台",
|
||||
prop: "platform_name",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "购买链接",
|
||||
prop: "link",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
213
src/views/productManagement/link/index.vue
Normal file
213
src/views/productManagement/link/index.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<!-- 购买链接 -->
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<div></div>
|
||||
<div style="display: flex; padding-bottom: 16px">
|
||||
<el-button type="primary" @click="handleImport"> 导入 </el-button>
|
||||
<el-button type="primary" @click="handleExport" style="margin-left: 20px"> 导出 </el-button>
|
||||
</div>
|
||||
|
||||
<ProTable
|
||||
ref="proTableRef"
|
||||
:formData="dataStore.formData"
|
||||
:columns="dataStore.columns"
|
||||
:request-api="getProductBuypassListApi"
|
||||
:init-param="dataStore.initParam"
|
||||
>
|
||||
<template #imgUrl="scope">
|
||||
<el-image :src="scope.row.imgUrl" style="width: 60px; height: 60px" />
|
||||
</template>
|
||||
<template #status="scope">
|
||||
<el-tag type="success" effect="dark">{{ scope.row.status }}</el-tag>
|
||||
</template>
|
||||
<template #is_show="scope">
|
||||
<el-tag :type="scope.row.is_show === 1 ? 'success' : 'danger'" effect="dark">{{
|
||||
scope.row.is_show === 1 ? "已上架" : "未上架"
|
||||
}}</el-tag>
|
||||
</template>
|
||||
<template #platform_name="scope">
|
||||
<div v-for="(it, itIndex) in scope.row.rowspan" :key="itIndex" style="margin-bottom: 10px">
|
||||
<el-select
|
||||
v-model="it.platform_name"
|
||||
class="m-2"
|
||||
placeholder="请选择"
|
||||
@change="handleInputOrChange(it, scope, itIndex)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dataStore.options"
|
||||
:key="item.id"
|
||||
:label="item.platform"
|
||||
:value="item.platform"
|
||||
@click="handleOptionItemClick(item, scope)"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<template #link="scope">
|
||||
<div v-for="(it, itIndex) in scope.row.rowspan" :key="itIndex" style="margin-bottom: 10px">
|
||||
<el-input v-model="it.link" @blur="handleInputOrChange(it, scope, itIndex)"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
</ProTable>
|
||||
<ImportExcel ref="importRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productLinkIndex">
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { useExport } from "@/hooks/useExport";
|
||||
// import type { UploadInstance } from "element-plus";
|
||||
import ImportExcel from "@/components/ImportExcel/index.vue";
|
||||
import { useUserStore } from "@/stores/modules/user";
|
||||
//列表接口
|
||||
// getProductBuypassListImportApi
|
||||
import {
|
||||
getProductBuypassListApi,
|
||||
getProductPlatformsListApi,
|
||||
getProductBuypassListExportApi,
|
||||
getProductBuypassUpdateApi,
|
||||
getProductBuypassListImportApi
|
||||
} from "@/api/modules/productLink";
|
||||
const importRef = ref();
|
||||
|
||||
//深拷贝方法
|
||||
import { cloneDeep } from "lodash-es";
|
||||
//表格和搜索條件
|
||||
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
|
||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||||
const proTableRef = ref<any>(null);
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 数据源
|
||||
const dataStore = reactive<any>({
|
||||
importUrl: import.meta.env.VITE_APP_API_BASE_UPLOAD_URL + "/product/buypass/import",
|
||||
uploadHeaders: {
|
||||
Authorization: "Bearer" + " " + userStore.token
|
||||
},
|
||||
fileType: [".xlsx", ".xls"],
|
||||
options: [],
|
||||
columns: COLUMNS, //列表配置项
|
||||
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
|
||||
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
|
||||
formData: FORM_DATA //搜索配置项
|
||||
});
|
||||
|
||||
//更新
|
||||
const getProductBuypassUpdate = async (params: any) => {
|
||||
const result = await getProductBuypassUpdateApi(params);
|
||||
if (result?.code === 0) {
|
||||
console.log(result?.data);
|
||||
} else {
|
||||
}
|
||||
};
|
||||
// const handleChange=()=>{
|
||||
|
||||
// }
|
||||
|
||||
// const up=(it: any, scope: any, itIndex: any)=>{
|
||||
// const { link, platform_name, link_id } = it;
|
||||
// let is = scope.row.rowspan.some((item: any, index: number) => {
|
||||
// if (index !== itIndex && item.platform_name === platform_name) {
|
||||
// return true;
|
||||
// }
|
||||
// });
|
||||
// if (is) {
|
||||
// useMsg("warning", "同型号平台不能重复 !");
|
||||
// return;
|
||||
// }
|
||||
// if (!platform_name) {
|
||||
// useMsg("warning", "平台不能为空 !");
|
||||
// return;
|
||||
// }
|
||||
// if (!link) {
|
||||
// useMsg("warning", "链接不能为空 !");
|
||||
// return;
|
||||
// }
|
||||
// //获取ID
|
||||
// let platform_id: any = null;
|
||||
// dataStore.options.forEach((item: any) => {
|
||||
// if (item.platform === platform_name) {
|
||||
// platform_id = item.id;
|
||||
// }
|
||||
// });
|
||||
// getProductBuypassUpdate({
|
||||
// id: link_id,
|
||||
// param: {
|
||||
// platform_id,
|
||||
// link
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//输入框失焦
|
||||
const handleInputOrChange = (it: any, scope: any, itIndex: any) => {
|
||||
const { link, platform_name, link_id } = it;
|
||||
let is = scope.row.rowspan.some((item: any, index: number) => {
|
||||
if (index !== itIndex && item.platform_name === platform_name) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (is) {
|
||||
useMsg("warning", "同型号平台不能重复 !");
|
||||
return;
|
||||
}
|
||||
if (!platform_name) {
|
||||
useMsg("warning", "平台不能为空 !");
|
||||
return;
|
||||
}
|
||||
if (!link) {
|
||||
useMsg("warning", "链接不能为空 !");
|
||||
return;
|
||||
}
|
||||
//获取ID
|
||||
let platform_id: any = null;
|
||||
dataStore.options.forEach((item: any) => {
|
||||
if (item.platform === platform_name) {
|
||||
platform_id = item.id;
|
||||
}
|
||||
});
|
||||
getProductBuypassUpdate({
|
||||
id: link_id,
|
||||
param: {
|
||||
platform_id,
|
||||
link
|
||||
}
|
||||
});
|
||||
};
|
||||
//平台
|
||||
const getProductPlatformsList = async () => {
|
||||
const result = await getProductPlatformsListApi();
|
||||
if (result?.code === 0) {
|
||||
dataStore.options = result?.data;
|
||||
}
|
||||
};
|
||||
getProductPlatformsList();
|
||||
|
||||
const handleOptionItemClick = (item: any, scope: any) => {
|
||||
console.log(item, "=1=");
|
||||
console.log(scope, "=2=");
|
||||
};
|
||||
|
||||
//导出
|
||||
const handleExport = () => {
|
||||
getProductBuypassListExport();
|
||||
};
|
||||
|
||||
//导出接口
|
||||
const getProductBuypassListExport = async () => {
|
||||
const result = await getProductBuypassListExportApi(dataStore.ruleForm);
|
||||
await useExport(result);
|
||||
};
|
||||
|
||||
const handleImport = () => {
|
||||
let params = {
|
||||
title: "数据",
|
||||
tempApi: "",
|
||||
importApi: getProductBuypassListImportApi,
|
||||
proTableRef: proTableRef
|
||||
};
|
||||
importRef.value.acceptParams(params);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
3
src/views/productManagement/link/utils/edit/index.ts
Normal file
3
src/views/productManagement/link/utils/edit/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { handleSubmit } from "./submit";
|
||||
import { handleReset } from "./reset";
|
||||
export { handleSubmit, handleReset };
|
||||
7
src/views/productManagement/link/utils/edit/reset.ts
Normal file
7
src/views/productManagement/link/utils/edit/reset.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
export const handleReset = (dataStore: any) => {
|
||||
messageBox("该操作会将数据重置为初始状态", () => {
|
||||
dataStore.basicInfoRuleForm = cloneDeep(dataStore.resetBasicInfoRuleForm);
|
||||
});
|
||||
};
|
||||
34
src/views/productManagement/link/utils/edit/submit.ts
Normal file
34
src/views/productManagement/link/utils/edit/submit.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
const WARN: any = {
|
||||
name: "产品名称不能为空 !",
|
||||
model: "型号不能为空 !",
|
||||
type: "产品分类不能为空 !",
|
||||
sort: "产品排序不能为空 !"
|
||||
};
|
||||
const warnFunction = (data: any) => {
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["name"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.model) {
|
||||
useMsg("warning", WARN["model"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.type) {
|
||||
useMsg("warning", WARN["type"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["sort"]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
export const handleSubmit = async (infoRef: any) => {
|
||||
console.log(infoRef.ruleForm, "============ruleForm===========");
|
||||
|
||||
let is = await warnFunction(infoRef.ruleForm);
|
||||
if (!is) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
16
src/views/productManagement/link/utils/messageBox.ts
Normal file
16
src/views/productManagement/link/utils/messageBox.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ElMessageBox } from "element-plus";
|
||||
|
||||
export const messageBox = (message: any, callback: any) => {
|
||||
ElMessageBox.confirm(message, "警告", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
console.log("132323");
|
||||
callback && callback();
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("取消323232");
|
||||
});
|
||||
};
|
||||
100
src/views/productManagement/list/components/basicInfo.vue
Normal file
100
src/views/productManagement/list/components/basicInfo.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<!-- 基本信息 -->
|
||||
<template>
|
||||
<div>
|
||||
<el-form ref="ruleFormRef" :model="_ruleFormParam" label-width="140">
|
||||
<el-form-item label="产品名称" required>
|
||||
<el-input v-model="_ruleFormParam.name" style="width: 440px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="副标题名称">
|
||||
<el-input v-model="_ruleFormParam.short_name" style="width: 440px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="型号" required>
|
||||
<el-input v-model="_ruleFormParam.spu" style="width: 440px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品分类" style="width: 440px" required>
|
||||
<!-- <el-input v-model="_ruleFormParam.category_id" /> -->
|
||||
|
||||
<el-tree-select
|
||||
clearable
|
||||
v-model="_ruleFormParam.category_id"
|
||||
:data="options"
|
||||
:render-after-expand="false"
|
||||
show-checkbox
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="产品参数">
|
||||
<el-input v-model="_ruleFormParam.params" style="width: 440px" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="产品排序" style="width: 440px" required>
|
||||
<!-- <el-input v-model="_ruleFormParam.sort" /> -->
|
||||
|
||||
<el-input-number
|
||||
:min="1"
|
||||
:max="9999"
|
||||
:controls="true"
|
||||
v-model.trim="_ruleFormParam.sort"
|
||||
step-strictly
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否上架" style="width: 440px">
|
||||
<el-radio-group v-model="_ruleFormParam.is_show">
|
||||
<el-radio :value="1" :label="1">是</el-radio>
|
||||
<el-radio :value="0" :label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否新品" style="width: 440px">
|
||||
<el-radio-group v-model="_ruleFormParam.is_new">
|
||||
<el-radio :value="1" :label="1">是</el-radio>
|
||||
<el-radio :value="0" :label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否推荐" style="width: 440px">
|
||||
<el-radio-group v-model="_ruleFormParam.is_hot">
|
||||
<el-radio :value="1" :label="1">是</el-radio>
|
||||
<el-radio :value="0" :label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="SEO标题">
|
||||
<el-input v-model="_ruleFormParam.seo_title" style="width: 440px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="SEO关键字">
|
||||
<el-input v-model="_ruleFormParam.seo_keywords" style="width: 440px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="SEO描述">
|
||||
<el-input v-model="_ruleFormParam.seo_desc" style="width: 440px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="basicInfo">
|
||||
import type { FormInstance } from "element-plus";
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
interface IProps {
|
||||
data: { [key: string]: any };
|
||||
options: any[];
|
||||
}
|
||||
|
||||
const props = defineProps<IProps>();
|
||||
|
||||
//重置
|
||||
const reset = () => {
|
||||
_ruleFormParam = {};
|
||||
};
|
||||
|
||||
let _ruleFormParam: any = computed(() => props.data);
|
||||
// 暴露给父组件的参数和方法(外部需要什么,都可以从这里暴露出去)
|
||||
defineExpose({
|
||||
ruleForm: _ruleFormParam,
|
||||
reset
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,2 @@
|
||||
export const FOLDER =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIUAAABoCAYAAADfADNgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAANmSURBVHhe7dpLb0xhHMfx/zlza4IQJIg0aoGIWwgSCWUiLNhga+Gy8gKwkmBF0peAqKUFKyxdupFY6MJCEIlYuHXhEmHaao/neeZ0dPxmVIgxnfP9LDrnnEm6mPn2uZzTKHEMmOSXUbz4nNiVZ9/C8d3XY+F1Kj0z4/Toz2xfFLvfEdmORbn0ClqtYRQ+gPKt4fSs9XwUh5fn7fT6QnoFrVQXxcTIcObhaHrl//Jx3NnbFV7ROnVRlG9V3Cgxnp61Bx/E5d4i00kL1RYA/W6EaLcgPD96HRkYsbOD7TF6ZUEYKfwHv/Tq1/RSe2Kd0TphpPjdncX/5MP1ax0/avhj/DshinttOG0046e58s1KmE6mQ8zTUZg+/NQxnf/62J38vp5Zkfu84nA/yC/eG312IYro0pf0FFnSbJ1GFAhxTL4f9Hf3pNERqtv+H3ewiQKBv0c1cS+IKFDT/7T68JMoUOOnEb/NJwrUufdmfOrdx4GenB1alrey29fOKnA/YDobqiR24+WYXXjyze6/a3zDcof7nn8ZxbWdpRAFOk/fo1E7+UAfMvptadPp4/iaAkF0sBPu+y03+XeEplH0beZpZKc7tjKfHtVrGMWGeaw/s2D/ksYjRcM1xa7FOevvLaZn6GSrr1Xs/ciPh6HdMyKLhseSpHSZZx+oKrrBg3kCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCDiossijtIzZN78UjpSzC1RBapWzI6rUWxZwCyCqq2uhVDDuY2FcAEZF0V2dEWhGsWqObFtW5gL15Fdp9blrGdmZFHi+AvPPo7b2usVq4yH95Ex87tiGzrYFY5ri4llboFxsbdkebYimTOnaDa4z/1I1UaKCc8/JXZ0YNgG3vrLdW+hA+3pztnN3W4fOolEMeHxh8T6Ho3a7Vdj9vpLYiNMKx0h7yaCNXNjW+5mhvObCmEN8bOmUSCrzL4DY7H3Znn6h1gAAAAASUVORK5CYII=";
|
||||
@@ -0,0 +1,45 @@
|
||||
import { ArrowLeft, FolderAdd, Refresh, UploadFilled, Upload, DeleteFilled } from "@element-plus/icons-vue";
|
||||
export const ICONS: any = [
|
||||
{
|
||||
icon: ArrowLeft,
|
||||
placement: "top",
|
||||
content: "上一级",
|
||||
type: "primary",
|
||||
is: true
|
||||
},
|
||||
{
|
||||
icon: Refresh,
|
||||
placement: "top",
|
||||
content: "刷新",
|
||||
type: "primary",
|
||||
is: true
|
||||
},
|
||||
{
|
||||
icon: UploadFilled,
|
||||
placement: "top",
|
||||
content: "上传文件",
|
||||
type: "primary",
|
||||
is: true
|
||||
},
|
||||
{
|
||||
icon: Upload,
|
||||
placement: "top",
|
||||
content: "直接上传",
|
||||
type: "primary",
|
||||
is: true
|
||||
},
|
||||
{
|
||||
icon: FolderAdd,
|
||||
placement: "top",
|
||||
content: "创建目录",
|
||||
type: "primary",
|
||||
is: true
|
||||
},
|
||||
{
|
||||
icon: DeleteFilled,
|
||||
placement: "top",
|
||||
content: "删除",
|
||||
type: "danger",
|
||||
is: true
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
import { IMG_INFO_COLUMNS, TABLE_ITEM, CAPACITY, COLOR } from "./table";
|
||||
import { ICONS } from "./icons";
|
||||
import { FOLDER } from "./folderBase64";
|
||||
export { IMG_INFO_COLUMNS, TABLE_ITEM, CAPACITY, COLOR, ICONS, FOLDER };
|
||||
@@ -0,0 +1,55 @@
|
||||
export const IMG_INFO_COLUMNS = [
|
||||
{
|
||||
label: "SKU",
|
||||
prop: "sku",
|
||||
disabled: false,
|
||||
formType: "input",
|
||||
maxLength: 50,
|
||||
width: "180"
|
||||
},
|
||||
{
|
||||
label: "主图",
|
||||
prop: "main_image",
|
||||
disabled: false,
|
||||
formType: "img",
|
||||
width: "130"
|
||||
},
|
||||
{
|
||||
label: "图片",
|
||||
prop: "photo_album_clone",
|
||||
disabled: false,
|
||||
formType: "imgs"
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
prop: "operation",
|
||||
disabled: false,
|
||||
isHeaderIcon: false,
|
||||
width: 160
|
||||
}
|
||||
];
|
||||
//颜色初始值
|
||||
export const COLOR = {
|
||||
label: "颜色",
|
||||
prop: "color",
|
||||
disabled: false,
|
||||
formType: "select",
|
||||
options: [],
|
||||
width: "240"
|
||||
};
|
||||
//容量初始值
|
||||
export const CAPACITY = {
|
||||
label: "容器",
|
||||
prop: "capacity",
|
||||
disabled: false,
|
||||
formType: "input",
|
||||
width: "240"
|
||||
};
|
||||
//添加行初始值
|
||||
export const TABLE_ITEM = {
|
||||
sku: "",
|
||||
color: "",
|
||||
capacity: "",
|
||||
img: "",
|
||||
imgs: []
|
||||
};
|
||||
222
src/views/productManagement/list/components/imgInfo.vue
Normal file
222
src/views/productManagement/list/components/imgInfo.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 封面图 -->
|
||||
<div>
|
||||
<h5 style="margin: 0; margin-bottom: 16px; font-size: 14px">封面图</h5>
|
||||
<UploadImg v-model:image-url="imgInfoDataStore.cover_image">
|
||||
<template #tip>
|
||||
<div style="width: 150px; text-align: center">(图片尺寸800x800)</div>
|
||||
</template>
|
||||
</UploadImg>
|
||||
</div>
|
||||
<el-divider />
|
||||
<!-- 属性 -->
|
||||
<div>
|
||||
<h5 style="margin-bottom: 16px; font-size: 14px">属性</h5>
|
||||
<div>
|
||||
<!-- 复选框组 -->
|
||||
<el-checkbox-group v-model="selectedAttrIds" @change="handleCheckboxChange">
|
||||
<el-checkbox v-for="attr in attrList" :key="attr.id" :label="attr.id">
|
||||
{{ attr.attr_name }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider />
|
||||
<!-- 列表图片 -->
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px">
|
||||
<h5 style="margin: 0; font-size: 14px">列表图信息</h5>
|
||||
<el-button type="primary" size="small" @click="addRow()">添加行</el-button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<el-table :data="imgInfoDataStore.skus" border>
|
||||
<el-table-column label="SKU" prop="sku" width="240px">
|
||||
<template #default="{ row }">
|
||||
<el-input style="width: 200px" placeholder="请输入" v-model="row.sku"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主图" prop="main_image" width="130px">
|
||||
<template #default="{ row }">
|
||||
<UploadImg height="104px" width="104px" v-model:image-url="row.main_image"> </UploadImg>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="attrId in selectedAttrIds" :key="attrId" :label="findAttrById(attrId)?.attr_name">
|
||||
<template #default="{ row }">
|
||||
<el-form :model="row">
|
||||
<el-form-item v-if="findAttrById(attrId)?.attr_type === 1" style="margin: 0">
|
||||
<el-select v-model="findAttrObjInRow(row, attrId).attr_value" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="prop in findAttrById(attrId)?.props"
|
||||
:key="prop.prop_value"
|
||||
:label="prop.prop_name"
|
||||
:value="prop.prop_value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="findAttrById(attrId)?.attr_type === 2" style="margin: 0">
|
||||
<!-- 生成输入框 -->
|
||||
<el-input v-model="findAttrObjInRow(row, attrId).attr_value" placeholder="请输入"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="图片">
|
||||
<template #default="{ row }">
|
||||
<UploadImgs height="80px" width="80px" v-model:fileList="row.photo_album_clone"> </UploadImgs>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 删除行操作列 -->
|
||||
<el-table-column label="操作" style="display: flex; align-items: center" width="120px">
|
||||
<template #default="{ $index }">
|
||||
<el-button type="danger" @click="deleteRow($index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-divider />
|
||||
<!-- 视频 -->
|
||||
<div style="margin-bottom: 40px">
|
||||
<!-- 视频图片 -->
|
||||
<div>
|
||||
<h5 style="margin: 0; margin-bottom: 16px; font-size: 14px">视频图</h5>
|
||||
<UploadImg v-model:image-url="imgInfoDataStore.video_img"> </UploadImg>
|
||||
</div>
|
||||
<!-- 视频 -->
|
||||
<div>
|
||||
<h5 style="margin: 16px 0; font-size: 14px">视频文件</h5>
|
||||
<UploadVideo v-model:video-url="imgInfoDataStore.video_url"> </UploadVideo>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="imgInfo">
|
||||
import { ref, reactive, shallowRef, onMounted } from "vue";
|
||||
import UploadImg from "@/components/Upload/UploadImg.vue";
|
||||
import UploadImgs from "@/components/Upload/UploadImgs.vue";
|
||||
import UploadVideo from "@/components/Upload/UploadVideo.vue";
|
||||
interface IProps {
|
||||
imgInfoData: { [key: string]: any };
|
||||
attrList: any[];
|
||||
}
|
||||
const props = defineProps<IProps>();
|
||||
const imgInfoDataRef = shallowRef(props.imgInfoData);
|
||||
let imgInfoDataStore = reactive({ ...imgInfoDataRef.value });
|
||||
|
||||
// 存储选中的属性 ID
|
||||
const selectedAttrIds = ref<any>([]);
|
||||
|
||||
// 根据 ID 查找属性
|
||||
const findAttrById = (id: any) => {
|
||||
return props.attrList.find(attr => attr.id === id);
|
||||
};
|
||||
|
||||
// 在 row 的 attrs 数组中查找对应 attrId 的对象
|
||||
const findAttrObjInRow = (row: any, attrId: any) => {
|
||||
console.log(row.attrs, "=======row===========");
|
||||
let obj = row.attrs.find((item: any) => item.attr_id === attrId.toString());
|
||||
if (!obj) {
|
||||
obj = { attr_id: attrId.toString(), attr_value: "" };
|
||||
row.attrs = [...row.attrs, obj]; // 避免直接修改原数组
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
// 处理复选框变化事件
|
||||
const handleCheckboxChange = () => {
|
||||
imgInfoDataStore.skus.forEach((row: any) => {
|
||||
const newAttrs: any = [];
|
||||
selectedAttrIds.value.forEach((attrId: any) => {
|
||||
const existingAttr = row.attrs.find((item: any) => item.attr_id === attrId.toString());
|
||||
if (existingAttr) {
|
||||
newAttrs.push({ ...existingAttr });
|
||||
} else {
|
||||
newAttrs.push({ attr_id: attrId.toString(), attr_value: "" });
|
||||
}
|
||||
});
|
||||
row.attrs = newAttrs;
|
||||
});
|
||||
};
|
||||
|
||||
// 添加新行的方法
|
||||
const addRow = () => {
|
||||
const newRow: any = {
|
||||
attrs: []
|
||||
};
|
||||
selectedAttrIds.value.forEach((attrId: any) => {
|
||||
newRow.attrs.push({ attr_id: attrId?.toString(), attr_value: "" });
|
||||
});
|
||||
|
||||
imgInfoDataStore.skus.push({
|
||||
sku: "", //SKU
|
||||
main_image: "", //主图
|
||||
photo_album: [], //副图 这个是传给后端的
|
||||
photo_album_clone: [], //附图 这个是本地用的
|
||||
attrs: []
|
||||
});
|
||||
};
|
||||
// 删除行的方法
|
||||
const deleteRow = (index: any) => {
|
||||
imgInfoDataStore.skus.splice(index, 1);
|
||||
};
|
||||
|
||||
const echoData = () => {
|
||||
const newSkus: any[] = [];
|
||||
imgInfoDataStore.skus.forEach((backendRow: any) => {
|
||||
const newRow = {
|
||||
sku: backendRow.sku,
|
||||
main_image: backendRow.main_image,
|
||||
photo_album: backendRow.photo_album,
|
||||
photo_album_clone: backendRow.photo_album.map((url: any) => {
|
||||
const name = url.split("/").pop();
|
||||
return { name, url };
|
||||
}),
|
||||
attrs: []
|
||||
};
|
||||
|
||||
backendRow.attrs.forEach((attr: any) => {
|
||||
const targetAttr = findAttrObjInRow(newRow, attr.attr_id);
|
||||
|
||||
targetAttr.attr_value = attr.attr_value;
|
||||
if (!selectedAttrIds.value.includes(attr.attr_id)) {
|
||||
selectedAttrIds.value.push(attr.attr_id);
|
||||
}
|
||||
});
|
||||
|
||||
newSkus.push(newRow);
|
||||
});
|
||||
|
||||
imgInfoDataStore.skus = newSkus;
|
||||
console.log(imgInfoDataStore, "=imgInfoDataStore=");
|
||||
handleCheckboxChange();
|
||||
};
|
||||
const callEchoDataIfHasValue = () => {
|
||||
if (Object.keys(imgInfoDataStore).length > 0) {
|
||||
echoData();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
callEchoDataIfHasValue();
|
||||
});
|
||||
watch(
|
||||
() => props.imgInfoData,
|
||||
newValue => {
|
||||
imgInfoDataRef.value = newValue;
|
||||
Object.keys(imgInfoDataStore).forEach(key => delete imgInfoDataStore[key]);
|
||||
Object.assign(imgInfoDataStore, newValue);
|
||||
callEchoDataIfHasValue();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
data: imgInfoDataStore
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 可以添加自定义样式 */
|
||||
</style>
|
||||
158
src/views/productManagement/list/constant/edit.ts
Normal file
158
src/views/productManagement/list/constant/edit.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
disabled?: boolean;
|
||||
fileList?: any;
|
||||
prompt?: any;
|
||||
}
|
||||
//basicInfoFormData
|
||||
export const BASIC_INFO_FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品名称: "
|
||||
},
|
||||
{
|
||||
prop: "short_name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "副标题名称: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "spu",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "型号: "
|
||||
},
|
||||
{
|
||||
prop: "category_id",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品分类: "
|
||||
},
|
||||
{
|
||||
prop: "params",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品参数: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "sort",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "产品排序: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "is_sale",
|
||||
placeholder: "",
|
||||
type: "radio",
|
||||
label: "是否上架: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
prop: "is_new",
|
||||
placeholder: "",
|
||||
type: "radio",
|
||||
label: "是否新品: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
prop: "is_hot",
|
||||
placeholder: "",
|
||||
type: "radio",
|
||||
label: "是否热门: ",
|
||||
options: [
|
||||
{
|
||||
label: "是",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "否",
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
prop: "seo_title",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "SEO标题: "
|
||||
},
|
||||
{
|
||||
prop: "seo_keyword",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "SEO关键字: "
|
||||
},
|
||||
{
|
||||
prop: "seo_desc",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
label: "SEO描述: "
|
||||
}
|
||||
];
|
||||
export const BASIC_INFO_RULE_FORM = {
|
||||
seo_desc: "",
|
||||
seo_keyword: "",
|
||||
seo_title: "",
|
||||
is_hot: "",
|
||||
is_new: "",
|
||||
is_sale: "",
|
||||
is_show: "",
|
||||
sort: 1,
|
||||
params: "",
|
||||
category_id: "",
|
||||
spu: "",
|
||||
short_name: "",
|
||||
name: "",
|
||||
detail: "",
|
||||
video_url: "",
|
||||
video_img: "",
|
||||
desc: "",
|
||||
cover_image: ""
|
||||
};
|
||||
export const BASIC_INFO_RULES = {
|
||||
name: [{ required: true, message: "产品名称不能为空 ! ", trigger: "blur" }],
|
||||
spu: [{ required: true, message: "型号不能为空 ! ", trigger: "blur" }],
|
||||
category_id: [{ required: true, message: "产品分类不能为空 ! ", trigger: "blur" }],
|
||||
sort: [{ required: true, message: "产品排序不能为空 ! ", trigger: "blur" }]
|
||||
};
|
||||
|
||||
// editRuleForm: {},
|
||||
//editFormData: [],
|
||||
5
src/views/productManagement/list/constant/index.ts
Normal file
5
src/views/productManagement/list/constant/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { FORM_DATA, RULE_FORM } from "./search";
|
||||
import { COLUMNS } from "./table";
|
||||
import { OPERATIONS } from "./operations";
|
||||
import { BASIC_INFO_FORM_DATA, BASIC_INFO_RULE_FORM, BASIC_INFO_RULES } from "./edit";
|
||||
export { FORM_DATA, RULE_FORM, COLUMNS, OPERATIONS, BASIC_INFO_RULE_FORM, BASIC_INFO_FORM_DATA, BASIC_INFO_RULES };
|
||||
26
src/views/productManagement/list/constant/operations.ts
Normal file
26
src/views/productManagement/list/constant/operations.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export const OPERATIONS = [
|
||||
{
|
||||
name: "下架",
|
||||
name1: "上架",
|
||||
id: 1,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "添加SKU",
|
||||
name1: "添加SKU",
|
||||
id: 2,
|
||||
type: "info"
|
||||
},
|
||||
{
|
||||
name: "编辑",
|
||||
name1: "编辑",
|
||||
id: 3,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "删除",
|
||||
name1: "删除",
|
||||
id: 4,
|
||||
type: "info"
|
||||
}
|
||||
];
|
||||
22
src/views/productManagement/list/constant/related.ts
Normal file
22
src/views/productManagement/list/constant/related.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export const RELATED_INFO_COLUMNS = [
|
||||
{
|
||||
label: "型号",
|
||||
prop: "spu",
|
||||
disabled: false,
|
||||
formType: "selectRemote",
|
||||
options: []
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
disabled: false,
|
||||
formType: "inputNumber"
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
prop: "operation",
|
||||
disabled: false,
|
||||
isHeaderIcon: false,
|
||||
width: 160
|
||||
}
|
||||
];
|
||||
90
src/views/productManagement/list/constant/search.ts
Normal file
90
src/views/productManagement/list/constant/search.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
}
|
||||
export const FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "产品名称: "
|
||||
},
|
||||
{
|
||||
prop: "spu",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "型号: "
|
||||
},
|
||||
{
|
||||
prop: "category_id",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelect",
|
||||
isArray: true,
|
||||
label: "产品分类: ",
|
||||
options: [
|
||||
{
|
||||
value: "1",
|
||||
label: "Level one 1",
|
||||
children: [
|
||||
{
|
||||
value: "1-1",
|
||||
label: "Level two 1-1",
|
||||
children: [
|
||||
{
|
||||
value: "1-1-1",
|
||||
label: "Level three 1-1-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
prop: "Time",
|
||||
type: "daterange",
|
||||
options: [],
|
||||
startPlaceholder: "开始日期",
|
||||
endPlaceholder: "结束日期",
|
||||
startDate: "created_at",
|
||||
// endDate: "createEndDate",
|
||||
label: "添加时间: "
|
||||
},
|
||||
|
||||
{
|
||||
prop: "is_show",
|
||||
placeholder: "请选择",
|
||||
type: "select",
|
||||
options: [
|
||||
{
|
||||
value: 0,
|
||||
label: "未上架"
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: "已上架"
|
||||
}
|
||||
],
|
||||
label: "上架状态: "
|
||||
}
|
||||
];
|
||||
|
||||
export const RULE_FORM = {
|
||||
page: 1,
|
||||
size: 50
|
||||
};
|
||||
102
src/views/productManagement/list/constant/table.ts
Normal file
102
src/views/productManagement/list/constant/table.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { RenderScope } from "@/components/ProTable/interface";
|
||||
|
||||
const YES_OR_NO: any = {
|
||||
0: "❌",
|
||||
1: "✔️"
|
||||
};
|
||||
|
||||
export const COLUMNS = [
|
||||
{
|
||||
align: "center",
|
||||
fixed: true,
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "图片",
|
||||
prop: "cover_image",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品名称",
|
||||
prop: "name",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "型号",
|
||||
prop: "spu",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品分类",
|
||||
prop: "category_name",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品排序",
|
||||
prop: "sort",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "新品",
|
||||
prop: "is_new",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_new];
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "热门",
|
||||
prop: "is_hot",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_hot];
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "添加时间",
|
||||
prop: "created_at",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "在售",
|
||||
prop: "is_sale",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_sale];
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "库存数量",
|
||||
prop: "stock_qty",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return scope.row.stock_qty === 0 ? "0" : scope.row.stock_qty;
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "上架状态",
|
||||
prop: "is_show",
|
||||
width: 160
|
||||
},
|
||||
|
||||
{ prop: "operation", label: "操作", fixed: "right", width: 300 }
|
||||
];
|
||||
174
src/views/productManagement/list/edit.vue
Normal file
174
src/views/productManagement/list/edit.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<!-- style="margin-bottom: 16px" -->
|
||||
|
||||
<div class="table-box">
|
||||
<div style="padding-bottom: 16px">
|
||||
<el-button @click="handleReset(dataStore)"> 重置 </el-button>
|
||||
<el-button type="primary" @click="handleSubmit(infoRef, imgInfoRef, dataStore)"> 提交 </el-button>
|
||||
</div>
|
||||
<div class="card table-main">
|
||||
<el-tabs v-model="activeName" class="demo-tabs">
|
||||
<el-tab-pane label="基本信息" name="basicInfo">
|
||||
<basicInfo ref="infoRef" :data="dataStore.basicInfoRuleForm" :options="dataStore.options" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="图片信息" name="imgInfo">
|
||||
<imgInfo :imgInfoData="dataStore.imgInfoData" ref="imgInfoRef" :attrList="dataStore.attrList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="详细内容" name="third">
|
||||
<div style="width: 1280px; margin: 0 auto">
|
||||
<WangEditor v-model:value="dataStore.detail" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="相关信息及下载" name="related">
|
||||
<!-- <related ref="relatedRef" :data="dataStore.related" /> -->
|
||||
<div style="margin-bottom: 16px">
|
||||
<el-button type="primary" size="small" @click="handleRelatedAdd()">添加行</el-button>
|
||||
</div>
|
||||
<FormTable
|
||||
:columns="dataStore.relatedColumns"
|
||||
:tableData="dataStore.relatedTableData"
|
||||
@handleRemote="handleRemote"
|
||||
@handleRemoteClick="handleRemoteClick"
|
||||
>
|
||||
<template #operation="scope">
|
||||
<el-button type="danger" size="small" @click="handleRelatedDelete(scope)">删除行</el-button>
|
||||
</template>
|
||||
</FormTable>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productEditIndex">
|
||||
import { ref, reactive } from "vue";
|
||||
//getProductAttrsApi
|
||||
import { getProductDetailsApi, getProductListApi, getProductAttrsListApi } from "@/api/modules/productList";
|
||||
import { getProductCategoryListApi } from "@/api/modules/productClass";
|
||||
import { RELATED_INFO_COLUMNS } from "./constant/related";
|
||||
import { cloneDeep, debounce } from "lodash-es";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { handleSubmit, handleReset, initDetailParams } from "./utils/edit/index";
|
||||
import { addLabelValue } from "./utils/common/addLabelValue";
|
||||
//组件引入
|
||||
import basicInfo from "./components/basicInfo.vue";
|
||||
import imgInfo from "./components/imgInfo.vue";
|
||||
import WangEditor from "@/components/WangEditor/index.vue";
|
||||
import FormTable from "@/components/FormTable/index.vue";
|
||||
|
||||
const $route = useRoute();
|
||||
//数据集合
|
||||
const dataStore = reactive<any>({
|
||||
relatedColumns: cloneDeep(RELATED_INFO_COLUMNS), //相关信息及下载表格配置
|
||||
relatedTableData: [{ related_product_id: null, sort: 1, spu: "" }], //相关信息下载参数
|
||||
imgInfoData: {
|
||||
cover_image: "",
|
||||
video_url: "",
|
||||
video_img: "",
|
||||
skus: []
|
||||
}, //图片信息
|
||||
detail: "", //详情
|
||||
basicInfoRuleForm: {}, //基本信息表单数据
|
||||
options: [], //产品分类
|
||||
attrList: [] //产品属性列表
|
||||
});
|
||||
|
||||
const infoRef = ref<any>(null);
|
||||
const imgInfoRef = ref<any>(null);
|
||||
const activeName = ref("basicInfo");
|
||||
//详情
|
||||
const getProductDetails = async () => {
|
||||
let id = $route.query.id;
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
const result = await getProductDetailsApi(id);
|
||||
if (result?.code === 0) {
|
||||
const { data } = result;
|
||||
//参数初始化(将参数按照不同的tab区分出来)
|
||||
initDetailParams(dataStore, data);
|
||||
}
|
||||
};
|
||||
getProductDetails();
|
||||
//产品属性列表
|
||||
const getProductAttrsList = async () => {
|
||||
const result = await getProductAttrsListApi();
|
||||
if (result?.code === 0) {
|
||||
dataStore.attrList = result?.data;
|
||||
}
|
||||
};
|
||||
getProductAttrsList();
|
||||
//型号接口(后端大佬说用产品列表接口)
|
||||
const getProductList = async (query: any) => {
|
||||
const result: any = await getProductListApi({
|
||||
spu: query,
|
||||
page: 1,
|
||||
size: 1000
|
||||
});
|
||||
if (result?.code === 0) {
|
||||
let data = cloneDeep(result?.data?.data);
|
||||
//参数本地化
|
||||
let dataClone = data.map((item: any) => {
|
||||
return {
|
||||
label: item.spu,
|
||||
value: item.spu,
|
||||
id: item.id
|
||||
};
|
||||
});
|
||||
dataStore.relatedColumns[0].options = dataClone;
|
||||
}
|
||||
};
|
||||
|
||||
//产品分类(后端大佬说直接掉列表接口)
|
||||
const getProductCategoryList = async () => {
|
||||
const result = await getProductCategoryListApi({ page: 1, size: 500 });
|
||||
if (result?.code === 0) {
|
||||
let dataClone: any = cloneDeep(result?.data);
|
||||
dataStore.options = addLabelValue(dataClone);
|
||||
}
|
||||
};
|
||||
getProductCategoryList();
|
||||
|
||||
//相关信息及行远程搜索下拉框点击
|
||||
const handleRemoteClick = (params: any) => {
|
||||
const { item, index } = params;
|
||||
console.log(item, index);
|
||||
dataStore.relatedTableData[index].related_product_id = item.id;
|
||||
};
|
||||
//相关信息及行删除
|
||||
const handleRelatedDelete = (scope: any) => {
|
||||
messageBox("确定要删除该行数据?", () => {
|
||||
if (dataStore.relatedTableData.length === 1) {
|
||||
useMsg("warning", "请至少保留一行数据 ! ");
|
||||
return;
|
||||
}
|
||||
dataStore.relatedTableData.splice(scope.$index, 1);
|
||||
});
|
||||
};
|
||||
//相关信息及下载添加行
|
||||
const handleRelatedAdd = () => {
|
||||
//添加行的初始化对象
|
||||
let obj = {
|
||||
related_product_id: null,
|
||||
sort: 1,
|
||||
spu: ""
|
||||
};
|
||||
dataStore.relatedTableData.push(obj);
|
||||
};
|
||||
//相关信息及下载远程搜索
|
||||
const handleRemote = debounce((params: any) => {
|
||||
getProductList(params.query);
|
||||
}, 800);
|
||||
//产品属性接口
|
||||
// const getProductAttrs = async () => {
|
||||
// const result = await getProductAttrsApi();
|
||||
// if (result?.code === 0) {
|
||||
// console.log(result.data);
|
||||
// }
|
||||
// };
|
||||
// getProductAttrs();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
155
src/views/productManagement/list/index.vue
Normal file
155
src/views/productManagement/list/index.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<!-- 产品列表 -->
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<div style="padding-bottom: 16px">
|
||||
<el-button type="primary" @click="handleExport"> 导出 </el-button>
|
||||
</div>
|
||||
<ProTable
|
||||
ref="proTableRef"
|
||||
:formData="dataStore.formData"
|
||||
:columns="dataStore.columns"
|
||||
:request-api="getProductListApi"
|
||||
:init-param="dataStore.initParam"
|
||||
>
|
||||
<template #cover_image="scope">
|
||||
<el-image :src="h + scope.row.cover_image" style="width: 60px; height: 60px" />
|
||||
</template>
|
||||
<template #status="scope">
|
||||
<el-tag effect="dark" :type="scope.row.status === 1 ? 'success' : 'danger'">{{
|
||||
scope.row.status === 1 ? "启用" : "禁用"
|
||||
}}</el-tag>
|
||||
</template>
|
||||
<template #is_show="scope">
|
||||
<el-tag :type="scope.row.is_show === 1 ? 'success' : 'danger'" effect="dark">{{
|
||||
scope.row.is_show === 1 ? "已上架" : "未上架"
|
||||
}}</el-tag>
|
||||
</template>
|
||||
<!-- sort -->
|
||||
<template #sort="scope">
|
||||
<el-input v-model="scope.row.sort" @blur="handleBlur(scope.row)" @input="handleInput(scope.row)"></el-input>
|
||||
</template>
|
||||
<template #operation="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
:type="scope.row.is_show === 1 ? 'danger' : 'primary'"
|
||||
@click="handleBtnClick('上下架', scope.row)"
|
||||
>{{ scope.row.is_show === 1 ? "下架" : "上架" }}</el-button
|
||||
>
|
||||
<el-button size="small" type="info" style="cursor: not-allowed" @click="handleBtnClick('添加SKU', scope.row)"
|
||||
>添加SKU</el-button
|
||||
>
|
||||
<el-button size="small" type="primary" @click="handleBtnClick('编辑', scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="info" style="cursor: not-allowed" @click="handleBtnClick('删除', scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productListIndex">
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import { integerRexg } from "@/utils/regexp/index";
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { useExport } from "@/hooks/useExport";
|
||||
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
|
||||
//列表接口
|
||||
//getProductDelApi
|
||||
import {
|
||||
getProductListApi,
|
||||
getProductUpOrShelvesApi,
|
||||
getProductListSortApi,
|
||||
getProductListExportApi
|
||||
} from "@/api/modules/productList";
|
||||
import { getProductCategoryListApi } from "@/api/modules/productClass";
|
||||
import { addLabelValue } from "./utils/common/addLabelValue";
|
||||
|
||||
//深拷贝方法
|
||||
import { cloneDeep } from "lodash-es";
|
||||
//表格和搜索條件
|
||||
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
|
||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||||
const proTableRef = ref<any>(null);
|
||||
const $router = useRouter();
|
||||
// 数据源
|
||||
const dataStore = reactive<any>({
|
||||
columns: COLUMNS, //列表配置项
|
||||
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
|
||||
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
|
||||
formData: FORM_DATA //搜索配置项
|
||||
});
|
||||
|
||||
//导出
|
||||
const handleExport = () => {
|
||||
getProductListExport();
|
||||
};
|
||||
//导出接口
|
||||
const getProductListExport = async () => {
|
||||
const result = await getProductListExportApi(dataStore.ruleForm);
|
||||
await useExport(result);
|
||||
};
|
||||
//上下架
|
||||
const getProductUpOrShelves = async (id: any) => {
|
||||
const result = await getProductUpOrShelvesApi(id);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
}
|
||||
};
|
||||
|
||||
//排序
|
||||
const getProductListSort = async (row: any) => {
|
||||
const result = await getProductListSortApi({ id: row.id, sort: row.sort });
|
||||
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
}
|
||||
};
|
||||
|
||||
//产品分类(后端大佬说直接掉列表接口)
|
||||
const getProductCategoryList = async () => {
|
||||
const result = await getProductCategoryListApi({ page: 1, size: 500 });
|
||||
if (result?.code === 0) {
|
||||
let dataClone: any = cloneDeep(result?.data);
|
||||
dataStore.formData[2].options = addLabelValue(dataClone);
|
||||
console.log(result?.data);
|
||||
}
|
||||
};
|
||||
getProductCategoryList();
|
||||
//排序input框失焦
|
||||
const handleBlur = (row: any) => {
|
||||
getProductListSort(row);
|
||||
};
|
||||
//
|
||||
const handleInput = (row: any) => {
|
||||
row.sort = integerRexg(row.sort);
|
||||
};
|
||||
|
||||
//按钮点击事件
|
||||
const handleBtnClick = (type: any, row: any) => {
|
||||
// if (type === "删除") {
|
||||
// // getProductDel(row.id);
|
||||
// }
|
||||
//添加SUK和删除暂时无法操作
|
||||
if (type == "添加SUK" || type === "删除") {
|
||||
return false;
|
||||
}
|
||||
if (type === "上下架") {
|
||||
getProductUpOrShelves(row.id);
|
||||
}
|
||||
|
||||
if (type === "编辑") {
|
||||
$router.push({
|
||||
path: "/admin/productManagement/list/edit",
|
||||
query: {
|
||||
id: row.id
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
./utils/common/addLabelValue
|
||||
@@ -0,0 +1,14 @@
|
||||
export const addLabelValue = (arr: any) => {
|
||||
return arr.map((item: any) => {
|
||||
// 为当前对象添加 label 和 value 属性
|
||||
const newItem = { ...item };
|
||||
newItem.label = newItem.name;
|
||||
newItem.value = newItem.id;
|
||||
|
||||
// 如果有子对象,递归调用 addLabelValue 处理子对象
|
||||
if (newItem.children && Array.isArray(newItem.children)) {
|
||||
newItem.children = addLabelValue(newItem.children);
|
||||
}
|
||||
return newItem;
|
||||
});
|
||||
};
|
||||
4
src/views/productManagement/list/utils/edit/index.ts
Normal file
4
src/views/productManagement/list/utils/edit/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { handleSubmit } from "./submit";
|
||||
import { handleReset } from "./reset";
|
||||
import { initDetailParams } from "./initDetailParams";
|
||||
export { handleSubmit, handleReset, initDetailParams };
|
||||
@@ -0,0 +1,35 @@
|
||||
import { cloneDeep } from "lodash-es";
|
||||
//将参数分离
|
||||
export const initDetailParams = (dataStore: any, data: any) => {
|
||||
//基本信息
|
||||
dataStore.basicInfoRuleForm = cloneDeep({
|
||||
name: data.name,
|
||||
short_name: data.short_name,
|
||||
spu: data.spu,
|
||||
category_id: data.category_id,
|
||||
params: data.category_id,
|
||||
sort: data.sort,
|
||||
is_show: data.is_show,
|
||||
is_new: data.is_new,
|
||||
is_hot: data.is_hot,
|
||||
is_sale: data.is_sale,
|
||||
status: data.status,
|
||||
seo_title: data.seo_title,
|
||||
seo_keywords: data.seo_keywords,
|
||||
seo_desc: data.seo_desc,
|
||||
stock_qty: data.stock_qty,
|
||||
id: data.id
|
||||
});
|
||||
//详情
|
||||
dataStore.detail = cloneDeep(data.detail);
|
||||
//图片
|
||||
dataStore.imgInfoData.cover_image = data.cover_image;
|
||||
dataStore.imgInfoData.video_url = data.video_url;
|
||||
dataStore.imgInfoData.skus = data.skus;
|
||||
dataStore.imgInfoData.video_img = data.video_img;
|
||||
|
||||
//相关信息及下载
|
||||
if (data.related) {
|
||||
dataStore.relatedTableData = cloneDeep(data.related);
|
||||
}
|
||||
};
|
||||
22
src/views/productManagement/list/utils/edit/reset.ts
Normal file
22
src/views/productManagement/list/utils/edit/reset.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { getProductDetailsApi } from "@/api/modules/productList";
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
// import { cloneDeep } from "lodash-es";
|
||||
import { initDetailParams } from "./initDetailParams";
|
||||
//详情(重置,重新获取一下详情)
|
||||
const getProductDetails = async (dataStore: any) => {
|
||||
const { id } = dataStore.basicInfoRuleForm;
|
||||
const result = await getProductDetailsApi(id);
|
||||
if (result?.code === 0) {
|
||||
const { data } = result;
|
||||
|
||||
initDetailParams(dataStore, data);
|
||||
useMsg("success", "重置成功 !");
|
||||
}
|
||||
};
|
||||
|
||||
export const handleReset = (dataStore: any) => {
|
||||
messageBox("该操作会将数据重置为初始状态", () => {
|
||||
getProductDetails(dataStore);
|
||||
});
|
||||
};
|
||||
78
src/views/productManagement/list/utils/edit/submit.ts
Normal file
78
src/views/productManagement/list/utils/edit/submit.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { getProductEditUpApi } from "@/api/modules/productList";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
const WARN: any = {
|
||||
name: "产品名称不能为空 !",
|
||||
spu: "型号不能为空 !",
|
||||
category_id: "产品分类不能为空 !",
|
||||
sort: "产品排序不能为空 !"
|
||||
};
|
||||
//警告
|
||||
const warnFunction = (data: any) => {
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["name"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.spu) {
|
||||
useMsg("warning", WARN["spu"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.category_id) {
|
||||
useMsg("warning", WARN["category_id"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["sort"]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
//更新
|
||||
const getProductEditUp = async (params: any) => {
|
||||
const result: any = await getProductEditUpApi(params);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
// montageImg(imgInfoRef);
|
||||
}
|
||||
};
|
||||
export const handleSubmit = async (infoRef: any, imgInfoRef: any, dataStore: any) => {
|
||||
let is = await warnFunction(infoRef.ruleForm);
|
||||
if (!is) {
|
||||
return false;
|
||||
}
|
||||
//相关信息及下载(过滤掉没有id的对象)
|
||||
let relatedData = dataStore.relatedTableData.filter((item: any) => {
|
||||
return item.related_product_id;
|
||||
});
|
||||
|
||||
const { video_img, video_url, cover_image, skus } = imgInfoRef.data;
|
||||
|
||||
//不要直接去修改skus的数据类型,这里的skus是和表格绑定的
|
||||
let skusClone = cloneDeep(skus);
|
||||
skusClone.forEach((item: any) => {
|
||||
let arr: any = [];
|
||||
item.photo_album_clone.forEach((it: any) => {
|
||||
arr.push(it.url);
|
||||
});
|
||||
item.photo_album = arr;
|
||||
item.attrs = item.attrs;
|
||||
// delete item.photo_albumClone;
|
||||
});
|
||||
console.log(skusClone, "=skusClone=");
|
||||
let skusCloneStr = JSON.stringify(skusClone);
|
||||
console.log(typeof skusCloneStr);
|
||||
|
||||
const params = {
|
||||
...infoRef.ruleForm,
|
||||
cover_image,
|
||||
video_url,
|
||||
video_img,
|
||||
skus: skusCloneStr,
|
||||
detail: dataStore.details,
|
||||
related: JSON.stringify(relatedData) || []
|
||||
};
|
||||
|
||||
console.log(params, "===========params=============");
|
||||
getProductEditUp(params);
|
||||
};
|
||||
4
src/views/productManagement/recycle/constant/index.ts
Normal file
4
src/views/productManagement/recycle/constant/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { FORM_DATA, RULE_FORM } from "./search";
|
||||
import { COLUMNS } from "./table";
|
||||
import { OPERATIONS } from "./operations";
|
||||
export { FORM_DATA, RULE_FORM, COLUMNS, OPERATIONS };
|
||||
26
src/views/productManagement/recycle/constant/operations.ts
Normal file
26
src/views/productManagement/recycle/constant/operations.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export const OPERATIONS = [
|
||||
{
|
||||
name: "下架",
|
||||
name1: "上架",
|
||||
id: 1,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "添加SKU",
|
||||
name1: "添加SKU",
|
||||
id: 2,
|
||||
type: "info"
|
||||
},
|
||||
{
|
||||
name: "编辑",
|
||||
name1: "编辑",
|
||||
id: 3,
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
name: "删除",
|
||||
name1: "删除",
|
||||
id: 4,
|
||||
type: "info"
|
||||
}
|
||||
];
|
||||
63
src/views/productManagement/recycle/constant/search.ts
Normal file
63
src/views/productManagement/recycle/constant/search.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
interface FormItem {
|
||||
prop: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type: string;
|
||||
isCopy?: boolean;
|
||||
optionProps?: any;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
options?: any;
|
||||
isArray?: boolean;
|
||||
startDate?: string; //开始时间(传入后台需要的参数)
|
||||
endDate?: string; //结束时间(传入后台需要的参数)
|
||||
startProp?: string;
|
||||
endProp?: string;
|
||||
isInteger?: boolean;
|
||||
}
|
||||
export const FORM_DATA: FormItem[] = [
|
||||
{
|
||||
prop: "name",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "产品名称: "
|
||||
},
|
||||
{
|
||||
prop: "spu",
|
||||
placeholder: "请输入",
|
||||
type: "input",
|
||||
isArray: true,
|
||||
label: "型号: "
|
||||
},
|
||||
{
|
||||
prop: "category_id",
|
||||
placeholder: "请选择",
|
||||
type: "treeSelect",
|
||||
isArray: true,
|
||||
label: "产品分类: ",
|
||||
options: [
|
||||
{
|
||||
value: "1",
|
||||
label: "Level one 1",
|
||||
children: [
|
||||
{
|
||||
value: "1-1",
|
||||
label: "Level two 1-1",
|
||||
children: [
|
||||
{
|
||||
value: "1-1-1",
|
||||
label: "Level three 1-1-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const RULE_FORM = {
|
||||
page: 1,
|
||||
size: 50
|
||||
};
|
||||
95
src/views/productManagement/recycle/constant/table.ts
Normal file
95
src/views/productManagement/recycle/constant/table.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { RenderScope } from "@/components/ProTable/interface";
|
||||
const YES_OR_NO: any = {
|
||||
0: "❌",
|
||||
1: "✔️"
|
||||
};
|
||||
export const COLUMNS = [
|
||||
{ type: "selection", fixed: "left", width: 40 },
|
||||
{
|
||||
align: "center",
|
||||
fixed: true,
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "图片",
|
||||
prop: "cover_image",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品名称",
|
||||
prop: "name",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "型号",
|
||||
prop: "spu",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品分类",
|
||||
prop: "category_name",
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
align: "left",
|
||||
label: "产品排序",
|
||||
prop: "sort",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "新品",
|
||||
prop: "is_new",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_new];
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
align: "center",
|
||||
label: "添加时间",
|
||||
prop: "created_at",
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "在售",
|
||||
prop: "is_sale",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_sale];
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "库存数量",
|
||||
prop: "stock_qty",
|
||||
width: 80,
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return scope.row.stock_qty === 0 ? "0" : scope.row.stock_qty;
|
||||
}
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
label: "上架状态",
|
||||
prop: "is_show",
|
||||
render: (scope: RenderScope<any>): VNode | string | any => {
|
||||
return YES_OR_NO[scope.row.is_show];
|
||||
}
|
||||
},
|
||||
|
||||
{ prop: "operation", label: "操作", fixed: "right", width: 300 }
|
||||
];
|
||||
105
src/views/productManagement/recycle/index.vue
Normal file
105
src/views/productManagement/recycle/index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<!-- 回收站 -->
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<ProTable
|
||||
ref="proTableRef"
|
||||
:formData="dataStore.formData"
|
||||
:columns="dataStore.columns"
|
||||
:request-api="getProductTrashListApi"
|
||||
:init-param="dataStore.initParam"
|
||||
>
|
||||
<template #image="scope">
|
||||
<el-image :src="h + scope.row.image" style="width: 60px; height: 60px" />
|
||||
</template>
|
||||
<template #status="scope">
|
||||
<el-tag type="danger" effect="dark"> {{ scope.row.status === 1 ? "删除" : "删除" }}</el-tag>
|
||||
</template>
|
||||
|
||||
<template #operation="scope">
|
||||
<el-button size="small" type="danger" @click="handleBtnClick('删除', scope.row)">删除</el-button>
|
||||
<el-button size="small" type="primary" @click="handleBtnClick('恢复', scope.row)">恢复</el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="productRecycleIndex">
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
|
||||
//列表接口
|
||||
import { getProductTrashListApi, getProductTrashDelApi, getProductTrashRestoreApi } from "@/api/modules/productRecycle";
|
||||
//深拷贝方法
|
||||
import { cloneDeep } from "lodash-es";
|
||||
//表格和搜索條件
|
||||
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
import { getProductCategoryListApi } from "@/api/modules/productClass";
|
||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||||
const proTableRef = ref<any>(null);
|
||||
|
||||
// 数据源
|
||||
const dataStore = reactive<any>({
|
||||
columns: COLUMNS, //列表配置项
|
||||
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
|
||||
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
|
||||
formData: FORM_DATA //搜索配置项
|
||||
});
|
||||
|
||||
//删除
|
||||
const getProductTrashDel = async (id: any) => {
|
||||
messageBox("你确定要删除?", async () => {
|
||||
const result = await getProductTrashDelApi(id);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
}
|
||||
});
|
||||
};
|
||||
//恢复
|
||||
const getProductTrashRestore = async (id: any) => {
|
||||
const result = await getProductTrashRestoreApi(id);
|
||||
if (result?.code === 0) {
|
||||
useMsg("success", result?.msg);
|
||||
proTableRef?.value?.getTableList();
|
||||
}
|
||||
};
|
||||
//按钮点击事件
|
||||
const handleBtnClick = (type: any, row: any) => {
|
||||
//删除
|
||||
if (type === "删除") {
|
||||
getProductTrashDel(row.id);
|
||||
}
|
||||
if (type === "恢复") {
|
||||
getProductTrashRestore(row.id);
|
||||
}
|
||||
};
|
||||
|
||||
const addLabelValue = (arr: any) => {
|
||||
return arr.map((item: any) => {
|
||||
// 为当前对象添加 label 和 value 属性
|
||||
const newItem = { ...item };
|
||||
newItem.label = newItem.name;
|
||||
newItem.value = newItem.id;
|
||||
|
||||
// 如果有子对象,递归调用 addLabelValue 处理子对象
|
||||
if (newItem.children && Array.isArray(newItem.children)) {
|
||||
newItem.children = addLabelValue(newItem.children);
|
||||
}
|
||||
return newItem;
|
||||
});
|
||||
};
|
||||
//产品分类(后端大佬说直接掉列表接口)
|
||||
const getProductCategoryList = async () => {
|
||||
const result = await getProductCategoryListApi({ page: 1, size: 500 });
|
||||
if (result?.code === 0) {
|
||||
// let data:any = []
|
||||
let dataClone: any = cloneDeep(result?.data);
|
||||
dataStore.formData[2].options = addLabelValue(dataClone);
|
||||
console.log(result?.data);
|
||||
}
|
||||
};
|
||||
getProductCategoryList();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
3
src/views/productManagement/recycle/utils/edit/index.ts
Normal file
3
src/views/productManagement/recycle/utils/edit/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { handleSubmit } from "./submit";
|
||||
import { handleReset } from "./reset";
|
||||
export { handleSubmit, handleReset };
|
||||
7
src/views/productManagement/recycle/utils/edit/reset.ts
Normal file
7
src/views/productManagement/recycle/utils/edit/reset.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { messageBox } from "@/utils/messageBox";
|
||||
export const handleReset = (dataStore: any) => {
|
||||
messageBox("该操作会将数据重置为初始状态", () => {
|
||||
dataStore.basicInfoRuleForm = cloneDeep(dataStore.resetBasicInfoRuleForm);
|
||||
});
|
||||
};
|
||||
34
src/views/productManagement/recycle/utils/edit/submit.ts
Normal file
34
src/views/productManagement/recycle/utils/edit/submit.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useMsg } from "@/hooks/useMsg";
|
||||
const WARN: any = {
|
||||
name: "产品名称不能为空 !",
|
||||
model: "型号不能为空 !",
|
||||
type: "产品分类不能为空 !",
|
||||
sort: "产品排序不能为空 !"
|
||||
};
|
||||
const warnFunction = (data: any) => {
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["name"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.model) {
|
||||
useMsg("warning", WARN["model"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.type) {
|
||||
useMsg("warning", WARN["type"]);
|
||||
return false;
|
||||
}
|
||||
if (!data.name) {
|
||||
useMsg("warning", WARN["sort"]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
export const handleSubmit = async (infoRef: any) => {
|
||||
console.log(infoRef.ruleForm, "============ruleForm===========");
|
||||
|
||||
let is = await warnFunction(infoRef.ruleForm);
|
||||
if (!is) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
16
src/views/productManagement/recycle/utils/messageBox.ts
Normal file
16
src/views/productManagement/recycle/utils/messageBox.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ElMessageBox } from "element-plus";
|
||||
|
||||
export const messageBox = (message: any, callback: any) => {
|
||||
ElMessageBox.confirm(message, "警告", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
console.log("132323");
|
||||
callback && callback();
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("取消323232");
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user