5 Commits

Author SHA1 Message Date
b73f4d519f feat: 🚀 远程搜索下拉框 2026-07-09 16:36:34 +08:00
472dd212f0 feat: 🚀 完整 2026-07-09 11:39:00 +08:00
fc627b7666 feat: 🚀 配件类型接口 2026-07-08 17:45:48 +08:00
d5512ad8d3 feat: 🚀 配件兼容型 2026-07-07 14:37:27 +08:00
109a8264fc feat: 🚀 测试登出地址修改 2026-05-08 17:50:18 +08:00
25 changed files with 1168 additions and 33 deletions

View File

@@ -0,0 +1,28 @@
import http from "@/api";
const URL = `product/compat/parts/`;
// 配件类型列表
export const getProductAccessoryTypeListApi = (params: any) => {
return http.get<any>(`${URL}/index`, params);
};
// 配件类型详情
export const getProductAccessoryTypeDetailsApi = (params: any) => {
return http.get<any>(`${URL}/read/${params}`);
};
// 配件类型删除
export const getProductAccessoryTypeDelApi = (params: any) => {
return http.delete<any>(`${URL}/delete/${params}`);
};
// 配件类型更新
export const getProductAccessoryTypeUpApi = (params: any) => {
const { id } = params;
return http.put<any>(`${URL}/update/${id}`, params);
};
//配件类型新增
export const getProductAccessoryTypeAddApi = (params: any) => {
return http.post<any>(`${URL}/save`, params, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
};

View File

@@ -0,0 +1,33 @@
import http from "@/api";
const PRODUCT_Compatibility = `/product/compat`;
// 列表
export const getProductCompatibilityListApi = (params: any) => {
return http.get<any>(`${PRODUCT_Compatibility}/index`, params);
};
// 详情
export const getProductCompatibilityDetailsApi = (params: any) => {
return http.get<any>(`${PRODUCT_Compatibility}/read/${params}`);
};
// 删除
export const getProductCompatibilityDelApi = (params: any) => {
return http.delete<any>(`${PRODUCT_Compatibility}/delete/${params}`);
};
// 更新
export const getProductCompatibilityUpApi = (params: any) => {
const { id } = params;
return http.put<any>(`${PRODUCT_Compatibility}/update/${id}`, params);
};
//新增
export const getProductCompatibilityAddApi = (params: any) => {
return http.post<any>(`${PRODUCT_Compatibility}/save`, params, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
};
//导入
export const getProductCompatibilityListImportApi = (params: any) => {
return http.post<any>(`${PRODUCT_Compatibility}/import`, params);
};
//getProductCompatibilityListApi,getProductCompatibilityDetailsApi,getProductCompatibilityDelApi,getProductCompatibilityUpApi,getProductCompatibilityUpApi,getProductCompatibilityAddApi,getProductCompatibilityAddApi

1
src/components.d.ts vendored
View File

@@ -46,7 +46,6 @@ declare module "vue" {
ElTabs: typeof import("element-plus/es")["ElTabs"]; ElTabs: typeof import("element-plus/es")["ElTabs"];
ElTag: typeof import("element-plus/es")["ElTag"]; ElTag: typeof import("element-plus/es")["ElTag"];
ElTooltip: typeof import("element-plus/es")["ElTooltip"]; ElTooltip: typeof import("element-plus/es")["ElTooltip"];
ElTree: typeof import("element-plus/es")["ElTree"];
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"]; ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
ElUpload: typeof import("element-plus/es")["ElUpload"]; ElUpload: typeof import("element-plus/es")["ElUpload"];
IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"]; IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"];

View File

@@ -108,17 +108,6 @@
> >
</el-radio-group> </el-radio-group>
</template> </template>
<!-- <template v-if="item.type === 'radio1'">
<el-radio-group v-model="_ruleForm[`${item.prop}`]">
<el-radio
:value="option.value"
:label="option.value"
v-for="(option, optionIndex) in item.options"
:key="optionIndex"
>{{ option.label }}</el-radio
>
</el-radio-group>
</template> -->
<template v-if="item.type === 'upImg'"> <template v-if="item.type === 'upImg'">
<UploadImg v-model:image-url="_ruleForm[`${item.prop}`]"> <UploadImg v-model:image-url="_ruleForm[`${item.prop}`]">
<template #tip> <template #tip>
@@ -149,6 +138,57 @@
/> />
</el-select> </el-select>
</template> </template>
<template v-if="item.type === 'selectRemote'">
<el-select
v-model="_ruleForm[`${item.prop}`]"
:placeholder="item.placeholder"
clearable
remote
filterable
multiple
:debounce="400"
@clear="handleClear(item)"
class="m-2 select"
remote-show-suffix
:remote-method="
(query:any) => {
remoteMethod(
query,
item
);
}
"
:disabled="item.disabled"
style="width: 444px"
>
<el-option
:label="option.name"
:value="option.value"
v-for="option in item.options"
:key="option.value"
/>
</el-select>
<!--item.prop -->
</template>
<template v-if="item.type === 'selectMultiple'">
<el-select
style="width: 240px"
v-model="_ruleForm[`${item.prop}`]"
:placeholder="item.placeholder"
clearable
multiple
@change="handleSelectChange(_ruleForm[`${item.prop}`], item.prop)"
>
<el-option
:label="option.label"
:value="option.value"
v-for="option in item.options"
:key="option.value"
/>
</el-select>
</template>
<template v-if="item.type === 'treeSelect'"> <template v-if="item.type === 'treeSelect'">
<el-tree-select <el-tree-select
clearable clearable
@@ -156,6 +196,7 @@
:data="item.options" :data="item.options"
:placeholder="item.placeholder" :placeholder="item.placeholder"
:render-after-expand="false" :render-after-expand="false"
multiple
show-checkbox show-checkbox
check-strictly check-strictly
@change="handleSelectChange(_ruleForm[`${item.prop}`], item.prop)" @change="handleSelectChange(_ruleForm[`${item.prop}`], item.prop)"
@@ -201,6 +242,7 @@ interface IProps {
handleSelectChangeEmits?: () => void; handleSelectChangeEmits?: () => void;
handleRadioGroupEmits?: () => void; handleRadioGroupEmits?: () => void;
handleTreesSelectChangeEmits?: () => void; handleTreesSelectChangeEmits?: () => void;
handleSelectRometeEmits?: () => void;
} }
const emits = defineEmits<{ const emits = defineEmits<{
(e: "handleInputButton", result?: Record<string, any>): void; (e: "handleInputButton", result?: Record<string, any>): void;
@@ -208,6 +250,7 @@ const emits = defineEmits<{
(e: "handleSelectChangeEmits", result?: Record<string, any>): void; (e: "handleSelectChangeEmits", result?: Record<string, any>): void;
(e: "handleRadioGroupEmits", result?: any): void; (e: "handleRadioGroupEmits", result?: any): void;
(e: "handleTreesSelectChangeEmits", result?: any): void; (e: "handleTreesSelectChangeEmits", result?: any): void;
(e: "handleSelectRometeEmits", result?: any): void;
}>(); }>();
const editorRef = ref<any>(null); const editorRef = ref<any>(null);
const ruleFormRef = ref<FormInstance>(); const ruleFormRef = ref<FormInstance>();
@@ -232,6 +275,14 @@ const handleSelectChange = (params: any, prop: any) => {
const handleRadioGroup = (value: any) => { const handleRadioGroup = (value: any) => {
emits("handleRadioGroupEmits", value); emits("handleRadioGroupEmits", value);
}; };
const handleClear = (item: any) => {
item.options = [];
};
//远程搜索(供应商)
const remoteMethod = async (query: any, item: any) => {
emits("handleSelectRometeEmits", { query, item });
console.log(query, item);
};
// 暴露给父组件的参数和方法(外部需要什么,都可以从这里暴露出去) // 暴露给父组件的参数和方法(外部需要什么,都可以从这里暴露出去)
defineExpose({ defineExpose({
ruleForm: _ruleForm, ruleForm: _ruleForm,

View File

@@ -4,11 +4,11 @@ import { useUserStore } from "@/stores/modules/user";
//不同环境的login地址 //不同环境的login地址
const LOGIN_OBJ: any = { const LOGIN_OBJ: any = {
development: "http://localhost:8080/admin/login", //开发环境 development: "http://localhost:8080/admin/login", //开发环境
test: "https://dev.orico.com.cn/admin/login", //测试环境 test: "https://dev.ow.f2b211.com/admin/login", //测试环境
production: "https://orico.com.cn/admin/login" //生产环境 production: "https://orico.com.cn/admin/login" //生产环境
}; };
/** /**
/** /**https://dev.ow.f2b211.com/admin/login
* @description 登出 * @description 登出
*/ */
export const outLogin = () => { export const outLogin = () => {

View File

@@ -0,0 +1,55 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "name",
placeholder: "请输入",
type: "input",
label: "配件类型: "
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "排序: "
},
{
prop: "disabled",
placeholder: "请输入",
type: "radio",
label: "是否启用: ",
options: [
{
label: "是",
value: 0
},
{
label: "否",
value: 1
}
]
}
];
export const EDIT_RULE_FORM = {
sort: 1
};
// editRuleForm: {},
//editFormData: [],

View File

@@ -0,0 +1,5 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
import { RULES } from "./rules";
import { EDIT_FORM_DATA, EDIT_RULE_FORM } from "./edit";
export { FORM_DATA, RULE_FORM, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES };

View File

@@ -0,0 +1,4 @@
export const RULES = {
name: [{ required: true, message: "配件类型不能为空 ! ", trigger: "blur" }],
sort: [{ required: true, message: "排序不能为空 ! ", trigger: "blur" }]
};

View File

@@ -0,0 +1,31 @@
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: "配件类型名称: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,39 @@
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "left",
label: "配件类型",
prop: "name"
},
{
align: "left",
label: "使用状态",
prop: "disabled"
},
{
align: "left",
label: "创建时间",
prop: "created_at"
},
{
align: "left",
label: "更新时间",
prop: "updated_at"
},
// {
// align: "center",
// label: "状态",
// prop: "status",
// width: 80
// },
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,224 @@
<!-- 视频列表 -->
<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="getProductAccessoryTypeListApi"
:init-param="dataStore.initParam"
>
<template #disabled="scope">
<el-tag :type="scope.row.stdisabledatus == 1 ? 'danger' : 'success'" effect="dark">{{
scope.row.disabled == 1 ? "禁用" : "启用"
}}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="handleBtnClick('编辑', scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleBtnClick('删除', scope.row)">删除</el-button>
</template>
</ProTable>
<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"
>
</rulesForm>
</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="accessoryType">
import ProTable from "@/components/ProTable/index.vue";
import rulesForm from "@/components/rulesForm/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
//列表接口
import {
getProductAccessoryTypeUpApi,
getProductAccessoryTypeAddApi,
getProductAccessoryTypeDelApi,
getProductAccessoryTypeDetailsApi,
getProductAccessoryTypeListApi
} from "@/api/modules/productAccessoryType";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
const formRef: any = ref(null);
// 数据源
const dataStore = reactive<any>({
title: "添加配件类型",
columns: COLUMNS, //列表配置项
rules: cloneDeep(RULES), //抽屉表单验证
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA), //抽屉表单配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA, //搜索配置项
visible: false,
selectRow: {} //当前选择的row
});
//抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
dataStore.title === "添加配件类型" ? getProductAccessoryTypeSave() : getProductAccessoryTypeUpdate();
} else {
console.log("error submit!");
return false;
}
});
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
//抽屉重置
const handleResetClick = () => {
if (dataStore.title === "添加配件类型") {
resetFields();
} else {
getProductAccessoryTypeRead(dataStore.selectRow.id);
}
};
// //视频分类接口
// const getProductAccessoryTypeClassList = async () => {
// const result = await getProductAccessoryTypeClassListApi();
// if (result?.code === 0) {
// let arr: any[] = [];
// if (result?.data?.length) {
// result?.data?.forEach((item: any) => {
// let obj = {
// value: item.id,
// label: item.name
// };
// arr.push(obj);
// });
// dataStore.formData[1].options = arr;
// }
// }
// };
// getProductAccessoryTypeClassList();
// const getProductAccessoryTypeClassEditList = async () => {
// const result = await getProductAccessoryTypeClassListApi({ is_show: 1 });
// if (result?.code === 0) {
// let arr: any[] = [];
// if (result?.data?.length) {
// result?.data?.forEach((item: any) => {
// let obj = {
// value: item.id,
// label: item.name
// };
// arr.push(obj);
// });
// dataStore.editFormData[1].options = arr;
// }
// }
// };
// getProductAccessoryTypeClassEditList();
//添加
const handleAdd = () => {
dataStore.visible = true;
dataStore.title = "添加配件类型";
};
//抽屉关闭前的钩子
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
//详情
const getProductAccessoryTypeRead = async (id: any) => {
const result = await getProductAccessoryTypeDetailsApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
}
};
//保存
const getProductAccessoryTypeSave = async () => {
const result = await getProductAccessoryTypeAddApi(dataStore.editRuleForm);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//更新
const getProductAccessoryTypeUpdate = async () => {
const result = await getProductAccessoryTypeUpApi(dataStore.editRuleForm);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//删除
const getProductAccessoryTypeListDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getProductAccessoryTypeDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
dataStore.selectRow = row;
//编辑
if (type === "编辑") {
dataStore.visible = true;
dataStore.title = "编辑配件类型";
getProductAccessoryTypeRead(row.id);
return;
}
//删除
if (type === "删除") {
getProductAccessoryTypeListDel(row.id);
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,109 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "label_name",
placeholder: "请输入",
type: "input",
label: "标签名称: "
},
{
prop: "part_id",
placeholder: "请输入",
type: "select",
label: "配件类型: ",
options: []
},
{
prop: "brand_name",
placeholder: "请输入",
type: "input",
label: "品牌: "
},
{
prop: "level_name",
placeholder: "请输入",
type: "input",
label: "级别: "
},
{
prop: "class_name",
placeholder: "请输入",
type: "input",
label: "类别: "
},
{
prop: "series_name",
placeholder: "请输入",
type: "input",
label: "系列: "
},
{
prop: "model",
placeholder: "请输入",
type: "input",
label: "市场型号: "
},
{
prop: "capacity",
placeholder: "请输入",
type: "input",
label: "容量: "
},
{
prop: "interface_type",
placeholder: "请输入",
type: "input",
label: "接口类型: "
},
{
prop: "compat_status",
placeholder: "请输入",
type: "input",
label: "兼容状态: "
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "排序: "
},
{
prop: "disabled",
placeholder: "请输入",
type: "radio",
label: "是否启用: ",
options: [
{
label: "是",
value: 0
},
{
label: "否",
value: 1
}
]
}
];
export const EDIT_RULE_FORM = {
sort: 1
};
// editRuleForm: {},
//editFormData: [],

View File

@@ -0,0 +1,5 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
import { RULES } from "./rules";
import { EDIT_FORM_DATA, EDIT_RULE_FORM } from "./edit";
export { FORM_DATA, RULE_FORM, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES };

View File

@@ -0,0 +1,5 @@
export const RULES = {
label_name: [{ required: true, message: "标签名称不能为空 ! ", trigger: "blur" }],
brand_name: [{ required: true, message: "标签名称不能为空 ! ", trigger: "blur" }],
sort: [{ required: true, message: "视频排序不能为空 ! ", trigger: "blur" }]
};

View File

@@ -0,0 +1,36 @@
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: "label_name",
placeholder: "请输入",
type: "input",
label: "标签名称: "
},
{
prop: "model",
placeholder: "请输入",
type: "input",
label: "型号: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,94 @@
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "left",
label: "标签名称",
prop: "label_name",
width: 200,
fixed: true
},
{
align: "left",
label: "配件类型",
prop: "part_name",
width: 200,
fixed: true
},
{
align: "left",
label: "品牌",
prop: "brand_name",
width: 200,
fixed: true
},
{
align: "left",
label: "级别",
prop: "level_name",
width: 160
},
{
align: "left",
label: "系列",
prop: "series_name",
width: 200
},
{
align: "left",
label: "型号",
prop: "model",
width: 200
},
{
align: "left",
label: "容量",
prop: "capacity",
width: 160
},
{
align: "left",
label: "接口型号",
prop: "interface_type",
width: 200
},
{
align: "left",
label: "兼容性状态",
prop: "compat_status",
width: 160
},
{
align: "left",
label: "排序",
prop: "sort",
width: 160
},
{
align: "left",
label: "使用状态",
prop: "disabled",
width: 160
},
{
align: "left",
label: "创建时间",
prop: "created_at",
width: 160
},
{
align: "left",
label: "更新时间",
prop: "updated_at",
width: 160
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,230 @@
<!-- 视频列表 -->
<template>
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button type="primary" @click="handleAdd"> 添加 </el-button>
<el-button type="primary" @click="handleImport"> 导入 </el-button>
</div>
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getProductCompatibilityListApi"
:init-param="dataStore.initParam"
>
<template #disabled="scope">
<el-tag :type="scope.row.stdisabledatus == 1 ? 'danger' : 'success'" effect="dark">{{
scope.row.disabled == 1 ? "禁用" : "启用"
}}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="handleBtnClick('编辑', scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleBtnClick('删除', scope.row)">删除</el-button>
</template>
</ProTable>
<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"
@handleSelectChangeEmits="handleSelectChangeEmits"
>
</rulesForm>
</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>
<ImportExcel ref="importRef" />
</div>
</template>
<script setup lang="ts" name="productCompatibilityList">
import ProTable from "@/components/ProTable/index.vue";
import rulesForm from "@/components/rulesForm/index.vue";
import ImportExcel from "@/components/ImportExcel/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
//列表接口
import {
getProductCompatibilityListApi,
getProductCompatibilityDetailsApi,
getProductCompatibilityDelApi,
getProductCompatibilityUpApi,
getProductCompatibilityAddApi,
getProductCompatibilityListImportApi
} from "@/api/modules/productCompatibility";
//列表接口
import { getProductAccessoryTypeListApi } from "@/api/modules/productAccessoryType";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
const formRef: any = ref(null);
const importRef = ref(null);
// 数据源
const dataStore = reactive<any>({
title: "添加",
columns: COLUMNS, //列表配置项
rules: cloneDeep(RULES), //抽屉表单验证
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA), //抽屉表单配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA, //搜索配置项
visible: false,
selectRow: {} //当前选择的row
});
//抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
dataStore.title === "添加" ? getSave() : getUpdate();
} else {
console.log("error submit!");
return false;
}
});
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
//抽屉重置
const handleResetClick = () => {
if (dataStore.title === "添加") {
resetFields();
} else {
getRead(dataStore.selectRow.id);
}
};
const getProductAccessoryTypeList = async () => {
const result = await getProductAccessoryTypeListApi({ is_show: 1 });
console.log(result?.data.data, "==================>");
if (result?.code === 0) {
let arr: any[] = [];
if (result?.data?.data?.length) {
result?.data?.data?.forEach((item: any) => {
let obj = {
value: item.id,
label: item.name
};
arr.push(obj);
});
console.log(arr, "=================");
dataStore.editFormData[1].options = arr;
}
}
};
getProductAccessoryTypeList();
//添加
const handleAdd = () => {
dataStore.visible = true;
dataStore.title = "添加";
};
//抽屉关闭前的钩子
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
//详情
const getRead = async (id: any) => {
const result = await getProductCompatibilityDetailsApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
}
};
const handleSelectChangeEmits = (value: any) => {
console.log(value, "========value=33========");
};
//保存
const getSave = async () => {
const result = await getProductCompatibilityAddApi(dataStore.editRuleForm);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//更新
const getUpdate = async () => {
const result = await getProductCompatibilityUpApi(dataStore.editRuleForm);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//删除
const getListDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getProductCompatibilityDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
dataStore.selectRow = row;
//编辑
if (type === "编辑") {
dataStore.visible = true;
dataStore.title = "编辑";
getRead(row.id);
return;
}
//删除
if (type === "删除") {
getListDel(row.id);
}
};
const handleImport = () => {
//getProductBuypassListImportApi,
let params = {
title: "数据",
tempApi: "",
importApi: getProductCompatibilityListImportApi,
proTableRef: proTableRef
};
importRef.value.acceptParams(params);
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,75 @@
//兼容性信息(否)
export const FORM_DATA_LV1: any[] = [
{
prop: "compat_id",
placeholder: "请输入",
type: "selectRemote",
label: "关联标签: ",
options: []
},
{
prop: "show_series_name",
placeholder: "请输入",
type: "radio",
label: "是否显示系列名: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
{
prop: "remark",
placeholder: "请输入",
type: "textarea",
label: "兼容性说明"
}
];
//兼容性信息(是)
export const FORM_DATA_LV2: any[] = [
{
prop: "compat_id",
placeholder: "请输入",
type: "selectRemote",
label: "关联标签: ",
options: []
},
{
prop: "show_series_name",
placeholder: "请输入",
type: "radio",
label: "是否显示系列名: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
//
{
prop: "series_name",
placeholder: "请输入",
type: "input",
label: "产品系列名: "
},
{
prop: "remark",
placeholder: "请输入",
type: "textarea",
label: "兼容性说明"
}
];

View File

@@ -2,4 +2,18 @@ import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table"; import { COLUMNS } from "./table";
import { OPERATIONS } from "./operations"; import { OPERATIONS } from "./operations";
import { BASIC_INFO_FORM_DATA, BASIC_INFO_RULE_FORM, BASIC_INFO_RULES } from "./edit"; 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 }; import { FORM_DATA_LV2, FORM_DATA_LV1 } from "./form";
import { RULES_LV1, RULES_LV2 } from "./rules";
export {
FORM_DATA,
RULE_FORM,
COLUMNS,
OPERATIONS,
BASIC_INFO_RULE_FORM,
BASIC_INFO_FORM_DATA,
BASIC_INFO_RULES,
FORM_DATA_LV2,
FORM_DATA_LV1,
RULES_LV1,
RULES_LV2
};

View File

@@ -0,0 +1,2 @@
export const RULE_FORM_LV1: any = {};
export const RULE_FORM_LV2: any = {};

View File

@@ -0,0 +1,7 @@
export const RULES_LV1 = {
compat_id: [{ required: true, message: "所属系列名称不能为空 ! ", trigger: "change" }]
};
export const RULES_LV2 = {
compat_id: [{ required: true, message: "所属系列名称不能为空 ! ", trigger: "change" }],
series_name: [{ required: true, message: "产品系列名不能为空 ! ", trigger: "blur" }]
};

View File

@@ -4,10 +4,10 @@
<div class="table-box"> <div class="table-box">
<div style="padding-bottom: 16px"> <div style="padding-bottom: 16px">
<el-button @click="handleReset(dataStore, editorRef)"> 重置 </el-button> <el-button @click="handleReset(dataStore, editorRef)"> 重置 </el-button>
<el-button type="primary" @click="handleSubmit(infoRef, imgInfoRef, dataStore)"> 提交 </el-button> <el-button type="primary" @click="handleSubmit(infoRef, imgInfoRef, formRef, dataStore)"> 提交 </el-button>
</div> </div>
<div class="card table-main"> <div class="card table-main">
<el-tabs v-model="activeName" class="demo-tabs"> <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleTabClick">
<el-tab-pane label="基本信息" name="basicInfo"> <el-tab-pane label="基本信息" name="basicInfo">
<basicInfo ref="infoRef" :data="dataStore.basicInfoRuleForm" :options="dataStore.options" /> <basicInfo ref="infoRef" :data="dataStore.basicInfoRuleForm" :options="dataStore.options" />
</el-tab-pane> </el-tab-pane>
@@ -35,6 +35,16 @@
</template> </template>
</FormTable> </FormTable>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="兼容性信息" name="compatible">
<rulesForm
:ruleForm="dataStore.ruleForm"
:formData="dataStore.formData"
:rules="dataStore.rules"
ref="formRef"
@handleSelectRometeEmits="handleSelectRometeEmits"
@handleRadioGroupEmits="handleRadioGroupEmits"
/>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</div> </div>
@@ -43,12 +53,16 @@
<script setup lang="ts" name="productEditIndex"> <script setup lang="ts" name="productEditIndex">
import { ref, reactive } from "vue"; import { ref, reactive } from "vue";
import Editor from "@/components/Editor/index.vue"; import Editor from "@/components/Editor/index.vue";
import rulesForm from "@/components/rulesForm/index.vue";
import { FORM_DATA_LV2, FORM_DATA_LV1, RULES_LV1, RULES_LV2 } from "./constant/index";
import { import {
getProductDetailsApi, getProductDetailsApi,
getProductListApi, getProductListApi,
getProductAttrsListApi, getProductAttrsListApi,
getProductCategoryListApi getProductCategoryListApi
} from "@/api/modules/productList"; } from "@/api/modules/productList";
import { getProductCompatibilityListApi } from "@/api/modules/productCompatibility";
// import { getProductCategoryListApi } from "@/api/modules/productClass"; // import { getProductCategoryListApi } from "@/api/modules/productClass";
import { RELATED_INFO_COLUMNS } from "./constant/related"; import { RELATED_INFO_COLUMNS } from "./constant/related";
import { cloneDeep, debounce } from "lodash-es"; import { cloneDeep, debounce } from "lodash-es";
@@ -67,6 +81,7 @@ import FormTable from "@/components/FormTable/index.vue";
const $route = useRoute(); const $route = useRoute();
const editorRef = ref<any>(null); const editorRef = ref<any>(null);
const formRef = ref<any>(null);
//数据集合 //数据集合
const dataStore = reactive<any>({ const dataStore = reactive<any>({
@@ -81,7 +96,10 @@ const dataStore = reactive<any>({
detail: "", //详情 detail: "", //详情
basicInfoRuleForm: {}, //基本信息表单数据 basicInfoRuleForm: {}, //基本信息表单数据
options: [], //产品分类 options: [], //产品分类
attrList: [] //产品属性列表 attrList: [], //产品属性列表
ruleForm: {},
formData: cloneDeep(FORM_DATA_LV1),
rules: cloneDeep(RULES_LV1)
}); });
const infoRef = ref<any>(null); const infoRef = ref<any>(null);
@@ -141,6 +159,28 @@ const getProductCategoryList = async () => {
}; };
getProductCategoryList(); getProductCategoryList();
//兼容性信息(后端大佬说直接掉列表接口)
const getProductCompatibilityList = async (label_name: any) => {
if (!label_name) {
return;
}
const result = await getProductCompatibilityListApi({ is_show: 1, page: 1, size: 50, label_name });
if (result?.code === 0) {
let arr: any[] = [];
if (result?.data?.data?.length) {
result?.data?.data?.forEach((item: any) => {
let obj = {
value: item.id,
name: item.label_name
};
arr.push(obj);
});
dataStore.formData[0].options = arr;
}
}
};
//相关信息及行远程搜索下拉框点击 //相关信息及行远程搜索下拉框点击
const handleRemoteClick = (params: any) => { const handleRemoteClick = (params: any) => {
const { item, index } = params; const { item, index } = params;
@@ -169,17 +209,25 @@ const handleRelatedAdd = () => {
}; };
//相关信息及下载远程搜索 //相关信息及下载远程搜索
const handleRemote = debounce((params: any) => { const handleRemote = debounce((params: any) => {
console.log(params, "============>>>>");
getProductList(params.query); getProductList(params.query);
}, 800); }, 800);
//产品属性接口 const handleTabClick = () => {
// const getProductAttrs = async () => { formRef.value.ruleFormRef.clearValidate("compat_id");
// const result = await getProductAttrsApi(); };
// if (result?.code === 0) { const handleRadioGroupEmits = (params: any) => {
// console.log(result.data); if (params === 1) {
// } dataStore.formData = cloneDeep(FORM_DATA_LV2);
// }; dataStore.rules = cloneDeep(RULES_LV2);
// getProductAttrs(); } else {
dataStore.ruleForm.series_name = "";
dataStore.formData = cloneDeep(FORM_DATA_LV1);
dataStore.rules = cloneDeep(RULES_LV1);
}
};
const handleSelectRometeEmits = (params: any) => {
console.log(params.query, "=============params=========");
getProductCompatibilityList(params.query);
};
</script> </script>
<style scoped></style> <style scoped></style>

View File

@@ -62,6 +62,7 @@ import {
getProductListExportApi, getProductListExportApi,
getProductCategoryListApi getProductCategoryListApi
} from "@/api/modules/productList"; } from "@/api/modules/productList";
// import { getProductCategoryListApi } from "@/api/modules/productClass"; // import { getProductCategoryListApi } from "@/api/modules/productClass";
import { addLabelValue } from "@/utils/addLabelValue"; import { addLabelValue } from "@/utils/addLabelValue";

View File

@@ -1,4 +1,5 @@
import { cloneDeep } from "lodash-es"; import { cloneDeep } from "lodash-es";
import { FORM_DATA_LV2, FORM_DATA_LV1, RULES_LV1, RULES_LV2 } from "../../constant/index";
// import { convertSpanToDiv } from "@/utils/convertSpanToDiv"; // import { convertSpanToDiv } from "@/utils/convertSpanToDiv";
const hasIdRecursive = (data: any, targetId: any) => { const hasIdRecursive = (data: any, targetId: any) => {
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
@@ -88,4 +89,29 @@ export const initDetailParams = (dataStore: any, data: any, editorRef: any) => {
if (data.related) { if (data.related) {
dataStore.relatedTableData = cloneDeep(data.related); dataStore.relatedTableData = cloneDeep(data.related);
} }
if (data.compat.length) {
dataStore.ruleForm = data.compat[0];
let ids: any[] = [];
let options: any[] = [];
dataStore.ruleForm?.compat.forEach((item: any) => {
ids.push(item.compat_id);
options.push({
value: item.compat_id,
name: item.label_name
});
});
dataStore.ruleForm.compat_id = ids;
//
console.log(options, "===options===");
if (dataStore.ruleForm.show_series_name === 1) {
dataStore.formData = cloneDeep(FORM_DATA_LV2);
dataStore.rules = cloneDeep(RULES_LV2);
dataStore.formData[0].options = options;
} else {
dataStore.ruleForm.series_name = "";
dataStore.formData = cloneDeep(FORM_DATA_LV1);
dataStore.rules = cloneDeep(RULES_LV1);
dataStore.formData[0].options = options;
}
}
}; };

View File

@@ -5,10 +5,12 @@ const WARN: any = {
name: "产品名称不能为空 !", name: "产品名称不能为空 !",
spu: "型号不能为空 !", spu: "型号不能为空 !",
category_id: "产品分类不能为空 !", category_id: "产品分类不能为空 !",
sort: "产品排序不能为空 !" sort: "产品排序不能为空 !",
tag: "关联标签不能为空 !",
seriesName: "产品系列名不能为空 !"
}; };
//警告 //警告
const warnFunction = (data: any) => { const warnFunction = (data: any, data1: any) => {
if (!data.name) { if (!data.name) {
useMsg("warning", WARN["name"]); useMsg("warning", WARN["name"]);
return false; return false;
@@ -25,6 +27,14 @@ const warnFunction = (data: any) => {
useMsg("warning", WARN["sort"]); useMsg("warning", WARN["sort"]);
return false; return false;
} }
// if (!data1.tag) {
// useMsg("warning", WARN["tag"]);
// return false;
// }
if (data1.is_show && !data1.series_name) {
useMsg("warning", WARN["seriesName"]);
return false;
}
return true; return true;
}; };
@@ -36,8 +46,8 @@ const getProductEditUp = async (params: any) => {
// montageImg(imgInfoRef); // montageImg(imgInfoRef);
} }
}; };
export const handleSubmit = async (infoRef: any, imgInfoRef: any, dataStore: any) => { export const handleSubmit = async (infoRef: any, imgInfoRef: any, formRef: any, dataStore: any) => {
let is = await warnFunction(infoRef.ruleForm); let is = await warnFunction(infoRef.ruleForm, formRef.ruleForm);
if (!is) { if (!is) {
return false; return false;
} }
@@ -61,8 +71,11 @@ export const handleSubmit = async (infoRef: any, imgInfoRef: any, dataStore: any
}); });
console.log(skusClone, "=skusClone="); console.log(skusClone, "=skusClone=");
let skusCloneStr = JSON.stringify(skusClone); let skusCloneStr = JSON.stringify(skusClone);
// cloneDeep
let ruleForm: any = cloneDeep(dataStore.ruleForm);
ruleForm.compat_id = ruleForm.compat_id.join(",");
console.log(typeof skusCloneStr); console.log(typeof skusCloneStr);
console.log(dataStore.ruleForm, "=ruleForm=");
const params = { const params = {
...infoRef.ruleForm, ...infoRef.ruleForm,
cover_image, cover_image,
@@ -70,7 +83,8 @@ export const handleSubmit = async (infoRef: any, imgInfoRef: any, dataStore: any
video_img, video_img,
skus: skusCloneStr, skus: skusCloneStr,
detail: dataStore.detail, detail: dataStore.detail,
related: JSON.stringify(relatedData) || [] related: JSON.stringify(relatedData) || [],
compat: JSON.stringify(ruleForm) || {}
}; };
console.log(params, "===========params============="); console.log(params, "===========params=============");