2025-03-26

This commit is contained in:
2025-03-26 11:00:21 +08:00
parent 927d7381b8
commit b45f4950d3
468 changed files with 54473 additions and 124 deletions

View File

@@ -0,0 +1,60 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "question",
placeholder: "请输入",
type: "input",
label: "标题: "
},
{
prop: "image",
type: "upImg",
placeholder: "请输入",
label: "图片: "
},
{
prop: "recommend",
placeholder: "",
type: "radio",
label: "首页推荐: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "问答排序: "
}
];
export const EDIT_RULE_FORM = {
sort: 1
};

View File

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

View File

@@ -0,0 +1,5 @@
export const RULES = {
question: [{ required: true, message: "标题不能为空 ! ", trigger: "blur" }],
sort: [{ required: true, message: "问答排序不能为空 ! ", trigger: "change" }],
image: [{ required: true, message: "图片不能为空 ! ", trigger: "change" }]
};

View File

@@ -0,0 +1,42 @@
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: "question",
placeholder: "请输入",
type: "input",
isArray: true,
label: "标题: "
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "添加时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,48 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{ type: "selection", fixed: "left", width: 40 },
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "标题",
prop: "question"
},
{
align: "left",
label: "首页显示",
prop: "recommend",
render: (scope: RenderScope<any>): VNode | string | any => {
return YES_OR_NO[scope.row.recommend];
}
},
{
align: "left",
label: "问答排序",
prop: "sort"
},
{
align: "center",
label: "添加时间",
prop: "created_at"
},
{ prop: "operation", label: "操作", fixed: "right", width: 300 }
];

View File

@@ -0,0 +1,107 @@
<template>
<!-- style="margin-bottom: 16px" -->
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button @click="handleReset"> 重置 </el-button>
<el-button type="primary" @click="handleSubmit"> 提交 </el-button>
</div>
<div class="card table-main">
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="基本信息" name="basicInfo">
<rulesForm
:ruleForm="dataStore.editRuleForm"
:formData="dataStore.editFormData"
:rules="dataStore.rules"
ref="formRef"
>
</rulesForm>
</el-tab-pane>
<el-tab-pane label="问答详细" name="third">
<div style="width: 1280px; margin: 0 auto">
<WangEditor v-model:value="dataStore.value" />
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup lang="ts" name="QAManagementListEdit">
import rulesForm from "@/components/rulesForm/index.vue";
import { getQAListDetailsApi, getQAListEditUpApi, getQAListSaveApi } from "@/api/modules/QAList";
import { ref, reactive } from "vue";
import WangEditor from "@/components/WangEditor/index.vue";
import { useMsg } from "@/hooks/useMsg";
import { EDIT_FORM_DATA, EDIT_RULE_FORM, RULES } from "./constant/index";
import { cloneDeep } from "lodash-es";
const $route = useRoute();
const activeName = ref("basicInfo");
//数据集合
const dataStore = reactive<any>({
value: "",
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA),
rules: RULES
});
const formRef: any = ref(null);
//详情
const getQAListDetails = async () => {
let id = $route.query.id;
console.log(id, "=========id========");
if (!id) {
return;
}
const result = await getQAListDetailsApi(id);
if (result?.code === 0) {
const { data } = result;
//这里是传给基本信息组件的表单数据
dataStore.editRuleForm = cloneDeep(data);
}
};
getQAListDetails();
//更新
const getQAListEditUp = async () => {
const result: any = await getQAListEditUpApi(dataStore.editRuleForm);
if (result?.code === 0) {
useMsg("success", result?.msg);
// dataStore.editRuleForm = result?.data;
}
};
//新增 getQAListSaveApi
const getQAListSave = async () => {
const result: any = await getQAListSaveApi(dataStore.editRuleForm);
if (result?.code === 0) {
useMsg("success", result?.msg);
}
};
const handleReset = () => {
if ($route.query.id) {
getQAListDetails();
} else {
resetFields();
}
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
const handleSubmit = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
$route.query.id ? getQAListEditUp() : getQAListSave();
console.log("submit!");
} else {
console.log("error submit!");
return false;
}
});
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,99 @@
<!-- QA列表 -->
<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="getQAListApi"
:init-param="dataStore.initParam"
>
<template #sort="scope">
<el-input v-model="scope.row.sort" @blur="handleBlur(scope.row)" @input="handleInput(scope.row)"></el-input>
</template>
<template #image="scope">
<el-image :src="h + scope.row.image" style="width: 60px; height: 60px" />
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="handleToDetails(scope.row.id)">编辑</el-button>
<el-button size="small" type="danger" @click="getQADel(scope.row.id)">删除</el-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts" name="QAListIndex">
import ProTable from "@/components/ProTable/index.vue";
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
import { useMsg } from "@/hooks/useMsg";
import { integerRexg } from "@/utils/regexp/index";
import { messageBox } from "@/utils/messageBox";
//列表接口
import { getQAListApi, getQASortApi, getQAListDelApi } from "@/api/modules/QAList";
//深拷贝方法
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 handleToDetails = async (id: any) => {
$router.push({
path: "/admin/QAManagement/list/edit",
query: {
id,
title: "编辑问答"
}
});
};
//添加
const handleAdd = async () => {
$router.push({
path: "/admin/QAManagement/list/edit",
query: {
title: "添加问答"
}
});
};
//排序
const getQASort = async (row: any) => {
const result = await getQASortApi({ id: row.id, sort: row.sort });
if (result?.code === 0) {
useMsg("success", result?.msg);
proTableRef?.value?.getTableList();
}
};
//删除
const getQADel = async (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getQAListDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//排序input框失焦
const handleBlur = (row: any) => {
getQASort(row);
};
//排序input输入
const handleInput = (row: any) => {
row.sort = integerRexg(row.sort);
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,5 @@
export const BTNS = [
{ name: "编辑", type: "edit", btnType: "primary" },
{ name: "添加文章", type: "add", btnType: "primary" },
{ name: "删除", type: "del", btnType: "danger" }
];

View File

@@ -0,0 +1,79 @@
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: "is_show",
placeholder: "请输入",
type: "radio",
label: "是否显示: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
}
// {
// prop: "seo_title",
// placeholder: "请输入",
// type: "input",
// label: "SEO标题: "
// },
// {
// prop: "seo_keywords",
// placeholder: "请输入",
// type: "input",
// label: "SEO关键词: "
// },
// {
// prop: "seo_desc",
// placeholder: "请输入",
// type: "input",
// label: "SEO描述: "
// }
];
export const EDIT_RULE_FORM = {
is_show: 1,
seo_desc: "",
seo_keywords: "",
seo_title: "",
sort: 1,
name: ""
};
// editRuleForm: {},
//editFormData: [],

View File

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

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,38 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "left",
label: "文章分类名称",
prop: "name"
},
{
align: "left",
label: "文章分类排序",
prop: "sort"
},
{
align: "left",
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 }
];

View File

@@ -0,0 +1,194 @@
<!-- 文章分类 -->
<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="getArticleClassListApi"
:init-param="dataStore.initParam"
>
<template #operation="scope">
<el-button
size="small"
v-for="(item, index) in dataStore.btns"
:key="index"
:type="item.btnType"
@click="handleBtnClick(item.type, scope.row)"
>{{ item.name }}</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"
/>
</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="articleClassListIndex">
import rulesForm from "@/components/rulesForm/index.vue";
import ProTable from "@/components/ProTable/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
//列表接口
import {
getArticleClassListApi,
getArticleClassAddSaveApi,
getArticleClassDelApi,
getArticleClassEditUpApi,
getArticleClassDetailsApi
} from "@/api/modules/articleClass";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES, BTNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
const formRef: any = ref(null);
const $router = useRouter();
// 数据源
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,
btns: BTNS,
selectRow: {} //当前选择的row
});
//新增文章接口
const getArticleClassAddSave = async () => {
const result = await getArticleClassAddSaveApi(dataStore.editRuleForm);
const { msg, code } = result;
if (code === 0) {
useMsg("success", msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//文章编辑
const getArticleClassUpEdit = async () => {
const result = await getArticleClassEditUpApi(dataStore.editRuleForm);
const { msg, code } = result;
if (code === 0) {
useMsg("success", msg);
dataStore.visible = false;
proTableRef?.value?.getTableList();
}
};
//删除文章
const getArticleClassDel = (row: any) => {
messageBox("你确定要删除?", async () => {
const result = await getArticleClassDelApi(row.id);
const { msg, code } = result;
if (code === 0) {
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
dataStore.title === "添加文章分类" ? getArticleClassAddSave() : getArticleClassUpEdit();
} else {
console.log("error submit!");
return false;
}
});
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
};
//抽屉重置
const handleResetClick = () => {
resetFields();
getArticleClassDetails(dataStore.selectRow);
};
//添加
const handleAdd = () => {
dataStore.visible = true;
};
//弹窗关闭钩子
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
//文章分类详情
const getArticleClassDetails = async (row: any) => {
const result = await getArticleClassDetailsApi(row.id);
const { code, data } = result;
if (code === 0) {
dataStore.editRuleForm = cloneDeep(data);
}
};
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
dataStore.selectRow = row;
//添加
if (type === "add") {
$router.push({
path: "/admin/articleManagement/list/edit",
query: {
type,
title: "添加文章",
category_id: row.id
}
});
}
//编辑
if (type === "edit") {
dataStore.visible = true;
dataStore.title = "编辑文章分类";
getArticleClassDetails(row);
return;
}
//删除
if (type === "del") {
getArticleClassDel(row);
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,112 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "title",
placeholder: "请输入",
type: "input",
label: "文章名称: "
},
{
prop: "category_id",
placeholder: "请选择",
type: "treeSelect",
label: "文章分类: ",
options: []
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "文章排序: "
},
{
prop: "recommend",
placeholder: "请选择",
type: "radio",
label: "首页推荐: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
{
prop: "link",
placeholder: "请输入",
type: "input",
label: "跳转链接: "
},
{
prop: "desc",
placeholder: "请输入",
type: "textarea",
label: "文章描述: "
},
{
prop: "release_time",
placeholder: "请选择",
type: "datetime",
label: "发布时间: "
},
{
prop: "image",
type: "upImg",
label: "封面图: ",
prompt: "图片尺寸320x320"
},
{
prop: "seo_title",
placeholder: "请输入",
type: "input",
label: "SEO标题: "
},
{
prop: "seo_keywords",
placeholder: "请输入",
type: "input",
label: "SEO关键词: "
},
{
prop: "seo_desc",
placeholder: "请输入",
type: "input",
label: "SEO描述: "
}
];
export const EDIT_RULE_FORM = {
category_id: "",
title: "",
image: "",
link: "",
sort: 1,
desc: "",
content: "",
recommend: 1,
release_time: ""
};

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 = {
title: [{ required: true, message: "文章名称不能为空 ! ", trigger: "blur" }],
category_id: [{ required: true, message: "文章分类不能为空 ! ", trigger: "change" }],
sort: [{ required: true, message: "文章排序不能为空 ! ", trigger: "blur" }]
};

View File

@@ -0,0 +1,50 @@
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: "title",
placeholder: "请输入",
type: "input",
isArray: true,
label: "文章名称: "
},
{
prop: "category_id",
placeholder: "请选择",
type: "treeSelect",
isArray: true,
label: "文章分类: ",
options: []
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "发布时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,53 @@
//import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "文章名称",
prop: "title"
},
{
align: "left",
label: "文章分类",
prop: "category_name"
},
{
align: "left",
label: "文章排序",
prop: "sort",
width: 160
},
{
align: "left",
label: "首页推荐",
prop: "recommend"
},
{
align: "left",
label: "发布时间",
prop: "release_time",
width: 160
},
{
align: "center",
label: "状态",
prop: "enabled",
width: 80
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,126 @@
<template>
<!-- style="margin-bottom: 16px" -->
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button @click="handleReset"> 重置 </el-button>
<el-button type="primary" @click="handleConfirmClick"> 提交 </el-button>
</div>
<div class="card table-main">
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="基本信息" name="basicInfo">
<rulesForm
:ruleForm="dataStore.editRuleForm"
:formData="dataStore.editFormData"
:rules="dataStore.rules"
ref="formRef"
/>
</el-tab-pane>
<el-tab-pane label="详细内容" name="third">
<div style="width: 1280px; margin: 0 auto">
<WangEditor v-model:value="dataStore.editRuleForm.content" />
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup lang="ts" name="articleEditIndex">
import rulesForm from "@/components/rulesForm/index.vue";
import {
getArticleClassDataApi,
getArticleListAddSaveApi,
getArticleListDetailsApi,
getArticleListUpApi
} from "@/api/modules/articleList";
// /handleSubmit,
import { EDIT_FORM_DATA, EDIT_RULE_FORM, RULES } from "./constant/index";
import { useSearchInfoArray } from "@/hooks/useSearch";
import { ref, reactive } from "vue";
import WangEditor from "@/components/WangEditor/index.vue";
// import rulesForm from "@/components/rulesForm/index.vue";
import { cloneDeep } from "lodash-es";
import { useMsg } from "@/hooks/useMsg";
const formRef = ref<any>(null);
const activeName = ref("basicInfo");
const $route = useRoute();
//数据集合
const dataStore = reactive<any>({
rules: cloneDeep(RULES), //抽屉表单验证
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA) //抽屉表单配置项
});
//新增
const getArticleListAddSave = async () => {
const result = await getArticleListAddSaveApi(dataStore.editRuleForm);
if (result.code === 0) {
const { msg } = result;
useMsg("success", msg);
}
};
//文章分类
const getArticleClassData = async () => {
const result = await getArticleClassDataApi();
if (result?.code === 0) {
const { data } = result;
dataStore.editFormData[1].options = useSearchInfoArray(data);
//如果有category_id就代表是从文章分类跳转过来的
if ($route.query.category_id) {
dataStore.editRuleForm.category_id = Number($route.query.category_id);
}
}
};
getArticleClassData();
//文章详情
const getArticleListDetails = async () => {
let id = $route.query.id;
if (!id) {
return;
}
const result = await getArticleListDetailsApi(id);
if (result?.code === 0) {
const { data } = result;
dataStore.editRuleForm = data;
console.log(data);
}
};
//更新
const getArticleListUp = async () => {
const result = await getArticleListUpApi({ id: $route.query.id, ...dataStore.editRuleForm });
if (result?.code === 0) {
useMsg("success", result?.msg);
}
};
getArticleListDetails();
//提交
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
console.log("submit!");
$route.query.type === "add" ? getArticleListAddSave() : getArticleListUp();
} else {
console.log("error submit!");
return false;
}
});
};
//重置
const handleReset = () => {
if ($route.query.type === "add") {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
} else {
getArticleListDetails();
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,122 @@
<!-- 视频列表 -->
<template>
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button type="primary" @click="handleAdd('add')"> 添加 </el-button>
<el-button type="primary" @click="handleExport"> 导出 </el-button>
</div>
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getArticleListApi"
:init-param="dataStore.initParam"
>
<template #image="scope">
<el-image :src="h + scope.row.image" style="width: 60px; height: 60px" />
</template>
<template #enabled="scope">
<el-tag type="success" effect="dark">{{ scope.row.enabled === 1 ? "启用" : "禁用" }}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="handleBtnClick('edit', scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleBtnClick('del', scope.row)">删除</el-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts" name="articleListIndex">
import { useExport } from "@/hooks/useExport";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
import ProTable from "@/components/ProTable/index.vue";
//列表接口
import {
getArticleListApi,
getArticleClassDataApi,
getArticleListExportApi,
getArticleListDelApi
} from "@/api/modules/articleList";
import { useSearchInfoArray } from "@/hooks/useSearch";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
//图片地址
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
// 获取 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, //搜索配置项
selectRow: {} //当前选择的row
});
//文章分类(搜索条件)
const getArticleClassData = async () => {
const result = await getArticleClassDataApi();
if (result?.code === 0) {
const { data } = result;
dataStore.formData[1].options = useSearchInfoArray(data);
}
};
getArticleClassData();
//添加
const handleAdd = (type: any) => {
$router.push({
path: "/admin/articleManagement/list/edit",
query: {
type,
title: "添加文章"
}
});
};
//导出接口
const getArticleListExport = async () => {
const result = await getArticleListExportApi(dataStore.ruleForm);
await useExport(result);
};
//导出
const handleExport = () => {
getArticleListExport();
};
//删除
const getArticleListDel = async (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getArticleListDelApi(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 === "edit") {
$router.push({
path: "/admin/articleManagement/list/edit",
query: {
id: row.id,
type
}
});
return;
}
//删除
if (type === "del") {
getArticleListDel(row.id);
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,3 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,40 @@
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: "title",
placeholder: "请输入",
type: "input",
isArray: true,
label: "文章名称: "
},
{
prop: "category_id",
placeholder: "请选择",
type: "select",
isArray: true,
label: "文章分类: ",
options: []
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,61 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{ type: "selection", fixed: "left", width: 40 },
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "文章名称",
prop: "title"
},
{
align: "left",
label: "文章分类",
prop: "category_name"
},
{
align: "left",
label: "文章排序",
prop: "sort",
width: 160
},
{
align: "left",
label: "首页推荐",
prop: "recommend",
render: (scope: RenderScope<any>): VNode | string | any => {
return YES_OR_NO[scope.row.recommend];
}
},
{
align: "left",
label: "发布时间",
prop: "release_time",
width: 160
},
{
align: "center",
label: "状态",
prop: "status",
width: 80
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,81 @@
<!-- 文章回收 -->
<template>
<div class="table-box">
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getArticleTrashListApi"
: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 ? "删除" : "删除" }}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="danger" @click="getArticleTrashDel(scope.row.id)">删除</el-button>
<el-button size="small" type="primary" @click="getArticleTrashRestore(scope.row.id)">恢复</el-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts" name="articleRecycleListIndex">
import ProTable from "@/components/ProTable/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
import { useSearchInfoArray } from "@/hooks/useSearch";
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
//列表接口
import { getArticleTrashListApi, getArticleTrashDelApi, getArticleTrashRestoreApi } from "@/api/modules/articleRecycle";
import { getArticleClassDataApi } from "@/api/modules/articleList";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
});
//恢复
const getArticleTrashRestore = async (id: any) => {
const result = await getArticleTrashRestoreApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
};
//删除
const getArticleTrashDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getArticleTrashDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//文章分类(搜索条件)
const getArticleClassData = async () => {
const result = await getArticleClassDataApi();
if (result?.code === 0) {
const { data } = result;
dataStore.formData[1].options = useSearchInfoArray(data);
}
};
getArticleClassData();
</script>
<style scoped></style>
@/api/modules/articleRecycle

View File

@@ -0,0 +1,136 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "videoName",
placeholder: "请输入",
type: "input",
label: "下载名称: "
},
{
prop: "videoType",
placeholder: "请选择",
type: "treeSelect",
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: "videoSort",
placeholder: "请输入",
type: "input",
label: "下载排序: "
},
{
prop: "recommend",
placeholder: "请输入",
type: "radio",
label: "首页推荐: ",
options: [
{
label: "是",
value: "是"
},
{
label: "否",
value: "否"
}
]
},
{
prop: "imgUrl",
type: "upImg",
label: "下载图片: ",
prompt: "图片尺寸320x320"
},
{
prop: "table",
type: "table",
label: "下载文件: "
},
{
prop: "videoDescribe",
placeholder: "请输入",
type: "input",
label: "适合型号: "
},
{
prop: "videoDescribe",
placeholder: "请输入",
type: "input",
label: "支持系统: "
},
{
prop: "videoDescribe",
placeholder: "请输入",
type: "input",
label: "文件格式: "
},
{
prop: "SEOTitle",
placeholder: "请输入",
type: "input",
label: "SEO标题: "
},
{
prop: "SEOKeywords",
placeholder: "请输入",
type: "input",
label: "SEO关键词: "
},
{
prop: "SEODescribe",
placeholder: "请输入",
type: "input",
label: "SEO描述: "
}
];
export const EDIT_RULE_FORM = {
videoName: "",
videoType: "",
videoSort: 1,
recommend: "",
videoDescribe: "",
link: "",
SEOTitle: "",
SEOKeywords: "",
SEODescribe: ""
};
// 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 = {
videoName: [{ required: true, message: "下载名称不能为空 ! ", trigger: "blur" }],
videoType: [{ required: true, message: "下载分类不能为空 ! ", trigger: "blur" }],
videoSort: [{ required: true, message: "下载排序不能为空 ! ", trigger: "blur" }]
};

View File

@@ -0,0 +1,57 @@
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: "title",
placeholder: "请输入",
type: "input",
isArray: true,
label: "文章标题: "
},
{
prop: "is_audited",
placeholder: "请选择",
type: "select",
options: [
{
value: 0,
label: "待审核"
},
{
value: 1,
label: "已审核"
}
],
label: "状态: "
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "提交时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,41 @@
//import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "留言人",
prop: "name",
width: 80
},
{
align: "center",
label: "联系邮箱",
prop: "email",
width: 160
},
{
align: "left",
label: "留言内容",
prop: "content"
},
{
align: "left",
label: "文章标题",
prop: "article_title"
},
{
align: "left",
label: "提交时间",
prop: "created_at",
width: 160
},
{
align: "center",
label: "状态",
prop: "is_audited",
width: 160
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,90 @@
<!-- 文章评论 -->
<template>
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button type="primary" @click="getArticleRemarkExport"> 导出 </el-button>
</div>
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getArticleRemarkListApi"
:init-param="dataStore.initParam"
>
<template #image="scope">
<el-image :src="h + scope.row.image" style="width: 60px; height: 60px" />
</template>
<template #is_audited="scope">
<el-tag :type="scope.row.is_audited ? 'success' : 'danger'" effect="dark">{{
scope.row.is_audited ? "已审核" : "待审核"
}}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="getArticleRemarkExamine(scope.row.id)">{{
scope.row.is_audited ? "取消审核" : "审核通过"
}}</el-button>
<el-button size="small" type="danger" @click="getArticleRemarkDel(scope.row.id)">删除</el-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts" name="articleRemarkListIndex">
import ProTable from "@/components/ProTable/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
import { useExport } from "@/hooks/useExport";
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
//列表接口
import {
getArticleRemarkListApi,
getArticleRemarkDelApi,
getArticleRemarkExamineApi,
getArticleRemarkExportApi
} from "@/api/modules/articleRemark";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS, RULES } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
rules: cloneDeep(RULES), //抽屉表单验证
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA, //搜索配置项
selectRow: {} //当前选择的row
});
//导出
const getArticleRemarkExport = async () => {
const result = await getArticleRemarkExportApi(dataStore.ruleForm);
await useExport(result);
};
//删除
const getArticleRemarkDel = async (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getArticleRemarkDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//审核
const getArticleRemarkExamine = async (id: any) => {
const result = await getArticleRemarkExamineApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,79 @@
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: " Banner分类名称: "
},
{
prop: "recommend",
placeholder: "请输入",
type: "radio",
label: "首页推荐: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
{
prop: "at_platform",
placeholder: "请输入",
type: "radio",
label: "显示端口: ",
options: [
{
label: "PC端",
value: "pc"
},
{
label: "移动端",
value: "mobile"
}
]
},
{
prop: "desc",
placeholder: "请输入",
type: "textarea",
label: "描述: "
}
];
export const EDIT_RULE_FORM = {
videoName: "",
videoType: "",
videoSort: 1,
recommend: "",
videoDescribe: "",
link: "",
SEOTitle: "",
SEOKeywords: "",
SEODescribe: ""
};
// 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,3 @@
export const RULES = {
at_platform: [{ required: true, message: "首页推荐不能为空 ! ", trigger: "change" }]
};

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: "Banner名称: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,52 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "left",
label: "Banner分类名称",
prop: "name"
},
{
align: "left",
label: "首页推荐",
prop: "recommend",
render: (scope: RenderScope<any>): VNode | string | any => {
return YES_OR_NO[scope.row.recommend];
}
},
{
align: "left",
label: "显示端口",
prop: "at_platform",
render: (scope: RenderScope<any>): VNode | string | any => {
const OBJ: any = {
pc: "PC端",
mobile: "移动端"
};
return OBJ[scope.row.at_platform];
}
},
{
align: "left",
label: "描述",
prop: "desc"
},
{
align: "left",
label: "添加时间",
prop: "created_at"
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,167 @@
<!-- 视频列表 -->
<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="getBannerClassListApi"
: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="success" effect="dark">{{ scope.row.status }}</el-tag>
</template>
<template #operation="scope">
<el-button size="small" type="primary" @click="getBannerClassListRead(scope.row.id)">编辑</el-button>
<el-button size="small" type="danger" @click="getBannerClassListDel(scope.row.id)">删除</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"
/>
</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="bannerClassListIndex">
import ProTable from "@/components/ProTable/index.vue";
import rulesForm from "@/components/rulesForm/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
//列表接口
import {
getBannerClassListApi,
getBannerClassListDelApi,
getBannerClassListReadApi,
getBannerClassListUpApi,
getBannerClassListSaveApi
} from "@/api/modules/bannerClass";
//深拷贝方法
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: "添加Banner分类",
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
});
//抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
dataStore.title === "添加Banner分类" ? getBannerClassListSave() : getBannerClassListUp();
console.log("submit!");
} else {
console.log("error submit!");
return false;
}
});
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
//抽屉重置
const handleResetClick = () => {
if (dataStore.title === "添加Banner分类") {
resetFields();
} else {
getBannerClassListRead(dataStore.editRuleForm.id);
}
};
//添加
const handleAdd = () => {
dataStore.visible = true;
dataStore.title = "添加Banner分类";
};
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
//更新
const getBannerClassListUp = async () => {
const result = await getBannerClassListUpApi(dataStore.editRuleForm);
if (result?.code === 0) {
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
formRef!.value!.ruleFormRef.resetFields();
proTableRef?.value?.getTableList();
}
};
//新增 getBannerListSave
const getBannerClassListSave = async () => {
const result = await getBannerClassListSaveApi(dataStore.editRuleForm);
if (result?.code === 0) {
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
formRef!.value!.ruleFormRef.resetFields();
proTableRef?.value?.getTableList();
}
};
//删除
const getBannerClassListDel = async (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getBannerClassListDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//详情
const getBannerClassListRead = async (id: any) => {
dataStore.title = "编辑Banner";
dataStore.visible = true;
const result = await getBannerClassListReadApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,187 @@
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;
placeholder1?: any;
prop1?: any;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "title",
placeholder: "请输入",
type: "input",
label: "Banner名称: "
},
{
prop: "title_txt_color",
placeholder: "填写RGB值",
type: "input",
label: "文字颜色: "
},
{
prop: "type",
placeholder: "请输入",
type: "radio",
label: "前台显示: ",
options: [
{
label: "显示图片",
value: "image"
},
{
label: "显示视频",
value: "video"
}
]
},
{
prop: "image",
type: "upImg",
label: "Banner图片: "
},
{
prop: "banner_id",
placeholder: "请选择",
type: "select",
label: "Banner分类: ",
options: [
{
value: "1",
label: "Level one 1"
}
]
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "Banner排序: "
},
{
prop: "link",
placeholder: "请输入",
type: "treeSelectInput",
label: "链接地址: ",
placeholder1: "请选择",
prop1: "link_to",
options: []
},
{
prop: "desc",
placeholder: "请输入",
type: "textarea",
label: "Banner描述: "
},
{
prop: "desc_txt_color",
placeholder: "填写RGB值",
type: "input",
label: "描述颜色: "
}
];
export const EDIT_FORM_DATA1: FormItem[] = [
{
prop: "title",
placeholder: "请输入",
type: "input",
label: "Banner名称: "
},
{
prop: "title_txt_color",
placeholder: "填写RGB值",
type: "input",
label: "文字颜色: "
},
{
prop: "type",
placeholder: "请输入",
type: "radio",
label: "前台显示: ",
options: [
{
label: "显示图片",
value: "image"
},
{
label: "显示视频",
value: "video"
}
]
},
{
prop: "image",
type: "upImg",
label: "Banner图片: "
},
{
prop: "banner_id",
placeholder: "请选择",
type: "select",
label: "Banner分类: ",
options: [
{
value: "1",
label: "Level one 1"
}
]
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "Banner排序: "
},
{
prop: "link",
placeholder: "请输入",
type: "inputSelect",
label: "链接地址: ",
placeholder1: "请选择",
prop1: "link_type",
options: []
},
{
prop: "video",
type: "video",
label: "视频文件: ",
fileList: []
},
{
prop: "desc",
placeholder: "请输入",
type: "textarea",
label: "Banner描述: "
},
{
prop: "desc_txt_color",
placeholder: "填写RGB值",
type: "input",
label: "描述颜色: "
}
];
export const EDIT_RULE_FORM = {
type: "image",
sort: 1
};
// editRuleForm: {},
//editFormData: [],

View File

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

View File

@@ -0,0 +1,15 @@
export const RULES = {
title: [{ required: true, message: "Banner名称不能为空 ! ", trigger: "blur" }],
type: [{ required: true, message: "前台显示不能为空 ! ", trigger: "change" }],
image: [{ required: true, message: "Banner图片不能为空 ! ", trigger: "change" }],
banner_id: [{ required: true, message: "Banner分类不能为空 ! ", trigger: "change" }],
sort: [{ required: true, message: "排序不能为空 ! ", trigger: "change" }]
};
export const RULES1 = {
title: [{ required: true, message: "Banner名称不能为空 ! ", trigger: "blur" }],
type: [{ required: true, message: "前台显示不能为空 ! ", trigger: "change" }],
image: [{ required: true, message: "Banner图片不能为空 ! ", trigger: "change" }],
banner_id: [{ required: true, message: "Banner分类不能为空 ! ", trigger: "change" }],
sort: [{ required: true, message: "排序不能为空 ! ", trigger: "change" }],
video: [{ required: true, message: "视频不能为空 ! ", trigger: "change" }]
};

View File

@@ -0,0 +1,50 @@
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: "title",
placeholder: "请输入",
type: "input",
isArray: true,
label: "Banner名称: "
},
{
prop: "banner_id",
placeholder: "请选择",
type: "select",
isArray: true,
label: "Banner分类: ",
options: []
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "添加时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,38 @@
//import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id"
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "Banner名称",
prop: "title"
},
{
align: "left",
label: "Banner分类",
prop: "banner_name"
},
{
align: "left",
label: "Banner排序",
prop: "sort"
},
{
align: "left",
label: "添加时间",
prop: "created_at"
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,339 @@
<template>
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button type="primary" @click="handleAdd"> 添加 </el-button>
<el-button type="primary" @click="handleExport"> 导出 </el-button>
</div>
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getBannerListApi"
:init-param="dataStore.initParam"
>
<template #image="scope">
<el-image :src="h + scope.row.image" style="width: 60px; height: 60px" />
</template>
<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="primary" @click="getBannerRead(scope.row.id)">编辑</el-button>
<el-button size="small" type="danger" @click="getBannerDel(scope.row.id)">删除</el-button>
</template>
</ProTable>
<el-drawer
v-model="dataStore.visible"
:show-close="true"
:size="640"
: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"
@handleRadioGroupEmits="handleRadioGroupEmits"
>
<el-input v-model.trim="dataStore.editRuleForm.link" clearable style="width: 440px">
<template #append>
<el-tree-select
lazy
:props="treeProps"
:load="getSystemUrls"
show-checkbox
v-model="selectedNodes"
ref="treeRef"
check-strictly
accordion
:cache-data="dataStore.data"
@check="handleCheck"
placeholder="请选择"
style="padding: 0"
@visible-change="visibleChange"
/>
</template>
</el-input>
</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="bannerListIndex">
import rulesForm from "@/components/rulesForm/index.vue";
import ProTable from "@/components/ProTable/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
import { useExport } from "@/hooks/useExport";
import { integerRexg } from "@/utils/regexp/index";
// 图片地址
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
// 列表接口
import {
getBannerListApi,
getBannerDelApi,
getBannerReadApi,
getBannerListSortApi,
getBannerUpApi,
getBannerListSaveApi,
getBannerListExportApi
} from "@/api/modules/banner";
import { getBannerClassListApi } from "@/api/modules/bannerClass";
import { getSystemUrlsApi } from "@/api/modules/home";
// 深拷贝方法
import { cloneDeep } from "lodash-es";
// 表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS, EDIT_FORM_DATA, EDIT_FORM_DATA1, EDIT_RULE_FORM, RULES, RULES1 } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
const formRef: any = ref(null);
// 数据源
const dataStore = reactive<any>({
title: "添加Banner",
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, // 搜索配置项 dataStore.formData
visible: false,
data: [],
is: false
});
const selectedNodes = ref(null);
const treeRef = ref(null);
// 配置 tree-select 的属性
const treeProps = {
children: "children",
label: "label",
value: "value"
};
const visibleChange = (is: any) => {
dataStore.is = is;
if (dataStore.is) {
}
};
const buildTree = (data: any, outerLinkTo: any = "") => {
return data.map((item: any) => {
const { name, id, url, data: childData = [], children: nestedChildren = [] } = item;
const currentLinkTo = item.link_to || outerLinkTo;
const value = id ? `${currentLinkTo}/${id}/${name}` : currentLinkTo || name;
const combinedChildren = [...childData, ...nestedChildren];
const childNodes = buildTree(combinedChildren, currentLinkTo);
return {
label: name,
value,
url,
link_to: currentLinkTo,
children: childNodes
};
});
};
let isFirstRequest = true;
const getSystemUrls = async (node: any, resolve: any) => {
//第一次请求
if (isFirstRequest) {
const result = await getSystemUrlsApi();
if (result?.code === 0) {
const children = buildTree(result?.data);
resolve(children);
isFirstRequest = false;
}
} else {
//第二次请求
if (node.data.children) {
resolve(node.data.children);
}
if (!node.data.children.length && !node.data.url && node.level > 1) {
const [link_to, id] = node?.data?.value?.split("/");
const result = await getSystemUrlsApi({ link_to, id });
if (result?.code === 0) {
const children = buildTree(result?.data, link_to);
resolve(children);
} else {
resolve([]);
}
}
}
};
// 详情
const getBannerRead = async (id: any) => {
dataStore.title = "编辑Banner";
dataStore.visible = true;
const result = await getBannerReadApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
if (dataStore.editRuleForm.link && dataStore.editRuleForm.link_to) {
let { id, name, link } = dataStore.editRuleForm.link_echo_data;
let obj: any = {
label: name, // 确保这里的name是你想要显示的文本
value: `${dataStore.editRuleForm.link_to}` + "/" + `${id}` + "/" + `${name}`,
url: link,
link_to: dataStore.editRuleForm.link_to,
children: []
};
let data: any = [];
data.push(obj);
selectedNodes.value = obj.value;
dataStore.data = data;
}
}
};
const handleCheck = (checkedNodes: any, values: any) => {
const { checkedKeys } = values;
if (checkedKeys.length) {
dataStore.editRuleForm.link = checkedNodes.url;
dataStore.editRuleForm.link_to = checkedNodes.link_to;
} else {
dataStore.editRuleForm.link = "";
dataStore.editRuleForm.link_to = "";
}
};
// 更新
const getBannerUp = async () => {
const result = await getBannerUpApi(dataStore.editRuleForm);
if (result?.code === 0) {
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
formRef!.value!.ruleFormRef.resetFields();
proTableRef?.value?.getTableList();
}
};
// 分类
const getBannerClassList = async () => {
const result = await getBannerClassListApi({ page: 1, size: 500 });
if (result?.code === 0) {
let arr: any = [];
result?.data?.data?.forEach((item: any) => {
arr.push({ value: item.id, label: item.name });
});
dataStore.formData[1].options = arr;
dataStore.editFormData[4].options = arr;
}
};
getBannerClassList();
// 新增 getBannerListSave
const getBannerListSave = async () => {
const result = await getBannerListSaveApi(dataStore.editRuleForm);
if (result?.code === 0) {
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
useMsg("success", result?.msg);
formRef!.value!.ruleFormRef.resetFields();
proTableRef?.value?.getTableList();
}
};
// 导出接口
const getArticleListExport = async () => {
const result = await getBannerListExportApi(dataStore.ruleForm);
await useExport(result);
};
// 导出
const handleExport = () => {
getArticleListExport();
};
// 抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
dataStore.title === "编辑Banner" ? getBannerUp() : getBannerListSave();
console.log("submit!");
} else {
console.log("error submit!");
return false;
}
});
};
// 重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
// 抽屉重置
const handleResetClick = () => {
if (dataStore.title === "添加Banner") {
resetFields();
} else {
getBannerRead(dataStore.editRuleForm.id);
}
};
// 添加
const handleAdd = () => {
dataStore.title = "添加Banner";
dataStore.visible = true;
};
// 抽屉关闭前的钩子
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
const handleRadioGroupEmits = (value: any) => {
if (value === "image") {
dataStore.editFormData = EDIT_FORM_DATA;
dataStore.rules = RULES;
} else {
dataStore.editFormData = EDIT_FORM_DATA1;
dataStore.rules = RULES1;
}
};
// 删除
const getBannerDel = async (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getBannerDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
// 排序
const getBannerListSort = async (row: any) => {
const result = await getBannerListSortApi({ id: row.id, sort: row.sort });
if (result?.code === 0) {
useMsg("success", result?.msg);
proTableRef?.value?.getTableList();
}
};
// 排序 input 框失焦
const handleBlur = (row: any) => {
getBannerListSort(row);
};
// 排序 input 输入
const handleInput = (row: any) => {
row.sort = integerRexg(row.sort);
};
</script>
<style scoped lang="scss">
::v-deep(.el-input-group__append) {
padding: 0;
}
</style>

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: "is_show",
placeholder: "请输入",
type: "radio",
label: "是否显示: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
}
];
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,36 @@
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: "left",
label: "下载分类名称",
prop: "name"
},
{
align: "left",
label: "下载分类排序",
prop: "sort"
},
{
align: "left",
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: 260 }
];

View File

@@ -0,0 +1,208 @@
<!-- 视频列表 -->
<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="getCategoryListApi"
: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="success" effect="dark">{{ scope.row.status }}</el-tag>
</template>
<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="primary" @click="handleBtnClick('编辑', scope.row)">编辑</el-button>
<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"
/>
</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="downloadClassListIndex">
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 { integerRexg } from "@/utils/regexp/index";
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
//列表接口
import {
getCategoryListApi,
getCategoryDelApi,
getCategorySortApi,
getCategorySaveApi,
getCategoryReadApi,
getCategoryUpdateApi
} from "@/api/modules/downloadClass";
//深拷贝方法
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 $router = useRouter();
// 数据源
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) {
console.log("submit!");
dataStore.title === "添加下载分类" ? getCategorySave() : getCategoryUpdate();
} else {
console.log("error submit!");
return false;
}
});
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
//抽屉重置
const handleResetClick = () => {
dataStore.title === "添加下载分类" ? resetFields() : getCategoryRead(dataStore.editRuleForm.id);
};
//添加
const handleAdd = () => {
dataStore.visible = true;
};
const handleBeforeClone = () => {
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
resetFields();
dataStore.visible = false;
};
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
dataStore.selectRow = row;
//编辑
if (type === "编辑") {
dataStore.visible = true;
dataStore.title = "编辑下载分类";
getCategoryRead(row.id);
return;
}
if (type === "添加") {
$router.push({
path: "/admin/downloadManagement/list/edit",
query: {
title: "添加下载"
}
});
}
//删除
if (type === "删除") {
getCategoryDel(row.id);
}
};
//更新
const getCategoryUpdate = async () => {
const result = await getCategoryUpdateApi(dataStore.editRuleForm);
if (result?.code === 0) {
useMsg("success", result?.msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//详情
const getCategoryRead = async (id: any) => {
const result = await getCategoryReadApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
}
};
//添加
const getCategorySave = async () => {
const result = await getCategorySaveApi(dataStore.editRuleForm);
if (result?.code === 0) {
useMsg("success", result?.msg);
dataStore.visible = false;
dataStore.editRuleForm = cloneDeep(EDIT_RULE_FORM);
proTableRef?.value?.getTableList();
}
};
//删除
const getCategoryDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getCategoryDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//排序input框失焦
const handleBlur = (row: any) => {
getCategorySort(row);
};
//排序input输入
const handleInput = (row: any) => {
row.sort = integerRexg(row.sort);
};
//排序
const getCategorySort = async (row: any) => {
const result = await getCategorySortApi({ id: row.id, sort: row.sort });
useMsg("success", result?.msg);
if (result?.code === 0) {
proTableRef?.value?.getTableList();
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,111 @@
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;
}
export const EDIT_FORM_DATA: FormItem[] = [
{
prop: "name",
placeholder: "请输入",
type: "input",
label: "下载名称: "
},
{
prop: "category_id",
placeholder: "请选择",
type: "select",
label: "下载分类: ",
options: []
},
{
prop: "sort",
placeholder: "请输入",
type: "inputNumber",
label: "下载排序: "
},
{
prop: "recommend",
placeholder: "请输入",
type: "radio",
label: "首页推荐: ",
options: [
{
label: "是",
value: 1
},
{
label: "否",
value: 0
}
]
},
{
prop: "image",
type: "upImg",
label: "下载图片: ",
prompt: "图片尺寸320x320"
},
{
prop: "table",
type: "table",
label: "下载文件: "
},
{
prop: "applicable_to",
placeholder: "请输入",
type: "input",
label: "适合型号: "
},
{
prop: "support_platform",
placeholder: "请输入",
type: "input",
label: "支持系统: "
},
{
prop: "seo_title",
placeholder: "请输入",
type: "input",
label: "SEO标题: "
},
{
prop: "seo_keywords",
placeholder: "请输入",
type: "input",
label: "SEO关键词: "
},
{
prop: "seo_desc",
placeholder: "请输入",
type: "input",
label: "SEO描述: "
}
];
export const EDIT_TABLE_DATA = [
{
file_path: "", //文件路径
btn_name: "", //按钮名字
file_ext: "" //文件格式
}
];
export const EDIT_RULE_FORM = {};
// 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, EDIT_TABLE_DATA } from "./edit";
export { FORM_DATA, RULE_FORM, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES, EDIT_TABLE_DATA };

View File

@@ -0,0 +1,5 @@
export const RULES = {
name: [{ required: true, message: "下载名称不能为空 ! ", trigger: "blur" }],
category_id: [{ required: true, message: "下载分类不能为空 ! ", trigger: "blur" }],
sort: [{ required: true, message: "下载排序不能为空 ! ", trigger: "blur" }]
};

View File

@@ -0,0 +1,50 @@
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: "category_id",
placeholder: "请选择",
type: "select",
isArray: true,
label: "下载分类: ",
options: []
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "添加时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,59 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "下载名称",
prop: "name"
},
{
align: "left",
label: "下载分类",
prop: "category_name"
},
{
align: "left",
label: "下载排序",
prop: "sort",
width: 160
},
{
align: "left",
label: "首页推荐",
prop: "recommend",
render: (scope: RenderScope<any>): VNode | string | any => {
return YES_OR_NO[scope.row.recommend];
}
},
{
align: "left",
label: "添加时间",
prop: "created_at"
},
{
align: "center",
label: "状态",
prop: "status",
width: 80
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,268 @@
<template>
<div class="table-box">
<div style="padding-bottom: 16px">
<el-button @click="handleResetClick()"> 重置 </el-button>
<el-button type="primary" @click="handleConfirmClick()"> 提交 </el-button>
</div>
<div class="card table-main">
<div style="width: 900px">
<rulesForm
:ruleForm="dataStore.editRuleForm"
:formData="dataStore.editFormData"
:rules="dataStore.rules"
ref="formRef"
>
<el-button type="primary" size="small" style="margin-bottom: 10px" @click="handleEditAdd">添加行</el-button>
<FormTable :columns="dataStore.editColumns" :tableData="dataStore.editTableData" :height="200">
<template #up="scope">
<el-upload
action="#"
class="upload"
:limit="1"
:multiple="true"
:show-file-list="false"
:http-request="param => uploadExcel(param)"
:before-upload="file => beforeExcelUpload(file)"
:on-exceed="handleExceed"
:on-success="(response, file, fileList) => excelUploadSuccess(response, scope.row)"
:on-error="excelUploadError"
:accept="filesType!.join(',')"
ref="uploadRef"
>
<el-button type="primary" size="small">文件上传</el-button>
</el-upload>
<!-- 显示文件名 -->
<div v-if="scope.row.file_path" style="display: flex; align-items: center; justify-content: center">
<span style="padding: 0 10px; margin-right: 20px; border: 1px solid #eeeeee">
{{ scope.row.file_path }}</span
>
<el-icon style="cursor: pointer" @click="handleDelete(scope.row)"><Delete /></el-icon>
</div>
</template>
<template #operation="scope">
<el-button type="danger" size="small" @click="handleEditDelete(scope)">删除行</el-button>
</template>
</FormTable>
</rulesForm>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import rulesForm from "@/components/rulesForm/index.vue";
import FormTable from "@/components/FormTable/index.vue";
import { EDIT_TABLE_DATA, RULES, EDIT_RULE_FORM, EDIT_FORM_DATA } from "./constant/index";
import { useMsg } from "@/hooks/useMsg";
import { Delete } from "@element-plus/icons-vue";
const $route = useRoute();
import { getCategorysApi } from "@/api/modules/downloadClass";
//深拷贝方法
import { cloneDeep } from "lodash-es";
import {
getAttachmentUpFileApi,
getAttachmentSaveApi,
getAttachmentUpdateApi,
getAttachmentReadApi
} from "@/api/modules/downloadList";
//上传文件格式
const filesType = ref([".inf", ".sys", ".dll", ".exe", ".cat", ".ko", ".rpm", ".kext", ".zip", ".bin", ".rar", ".tar", ".gz"]);
const dataStore = reactive<any>({
rules: cloneDeep(RULES), //抽屉表单验证
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA), //抽屉表单配置项
editTableData: cloneDeep(EDIT_TABLE_DATA), //添加|编辑里的表格数据
editColumns: [
{
label: "文件",
prop: "file_path",
disabled: false,
formType: "up",
width: "350",
align: "left"
},
{
label: "文件格式",
prop: "file_ext",
disabled: false,
formType: "input",
maxLength: 50,
width: "150"
},
//operation
{
label: "按钮名称",
prop: "btn_name",
disabled: false,
formType: "input",
maxLength: 50,
width: "150"
},
{
label: "操作",
prop: "operation",
width: "112"
}
] //添加|编辑里的表格配置项
});
const formRef: any = ref(null);
const uploadRef = ref<any>(null);
// 文件上传
const uploadExcel = async (param: any) => {
let excelFormData = new FormData();
excelFormData.append("attachment", param.file);
const result = await getAttachmentUpFileApi(excelFormData);
return result;
};
/**
* @description 文件上传之前判断
* @param file 上传的文件
* @param row 当前行数据
* */
const beforeExcelUpload = (file: any) => {
const maxSize = 50 * 1024 * 1024;
if (file.size > maxSize) {
setTimeout(() => {
ElNotification({
title: "温馨提示",
message: `上传文件大小不能超过 ${50}MB`,
type: "warning"
});
}, 0);
}
// return isExcel && fileSize;
};
// 上传错误提示
const excelUploadError = () => {
ElNotification({
title: "温馨提示",
message: `文件上传失败,请您重新上传!`,
type: "error"
});
};
// 上传成功提示
const excelUploadSuccess = (response: any, row: any) => {
console.log(response, "=response=");
// 假设后端返回的数据中有文件路径和文件格式
if (response?.code === 0) {
row.file_path = response.data.path; // 假设后端返回的文件路径在 data.path 中
}
console.log(row, "====row========");
ElNotification({
title: "温馨提示",
message: `文件上传成功!`,
type: "success"
});
};
// 文件数超出提示
const handleExceed = () => {
ElNotification({
title: "温馨提示",
message: "最多只能上传一个文件",
type: "warning"
});
};
//添加
const getAttachmentSave = async () => {
const result = await getAttachmentSaveApi({ ...dataStore.editRuleForm, attach: JSON.stringify(dataStore.editTableData) });
if (result?.code === 0) {
useMsg("success", result?.msg);
}
};
// //更新
const getAttachmentUpdate = async () => {
const result = await getAttachmentUpdateApi({ ...dataStore.editRuleForm, attach: JSON.stringify(dataStore.editTableData) });
if (result?.code === 0) {
useMsg("success", result?.msg);
}
};
//抽屉确认
const handleConfirmClick = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef!.validate((valid: any) => {
if (valid) {
console.log("submit!");
$route.query.title === "添加下载" ? getAttachmentSave() : getAttachmentUpdate();
} else {
console.log("error submit!");
return false;
}
});
};
//抽屉重置
const handleResetClick = () => {
if ($route.query.title === "添加下载") {
resetFields();
} else {
getAttachmentRead();
}
};
//重置验证状态
const resetFields = () => {
if (!formRef.value!.ruleFormRef) return;
formRef!.value!.ruleFormRef.resetFields();
};
const handleEditDelete = (scope: any) => {
dataStore.editTableData.splice(scope.$index, 1);
};
const handleEditAdd = () => {
dataStore.editTableData.push({
file_path: "", //文件路径
btn_name: "", //按钮名字
file_ext: "" //文件格式
});
};
//详情
const getAttachmentRead = async () => {
let id = $route.query.id;
if (!id) {
return;
}
const result = await getAttachmentReadApi(id);
if (result?.code === 0) {
dataStore.editRuleForm = result?.data;
dataStore.editTableData = result?.data.attach;
}
};
getAttachmentRead();
//分类
const getCategorys = async () => {
const result = await getCategorysApi();
if (result?.code === 0) {
let arr: any[] = [];
result?.data?.forEach((item: any) => {
let obj = {
value: item.id,
label: item.name
};
arr.push(obj);
});
dataStore.editFormData[1].options = arr;
}
};
getCategorys();
const handleDelete = async (row: any) => {
row.file_path = "";
// 清空上传组件的文件列表
if (uploadRef.value) {
uploadRef.value.clearFiles();
}
ElNotification({
title: "温馨提示",
message: `文件已删除!`,
type: "success"
});
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,172 @@
<!-- 视频列表 -->
<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="getAttachmentListApi"
: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="scope.row.status === 1 ? 'success' : 'danger'" effect="dark">{{
scope.row.status === 1 ? "启用" : "禁用"
}}</el-tag>
</template>
<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="primary" @click="handleBtnClick('编辑', scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleBtnClick('删除', scope.row)">删除</el-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts" name="downloadListIndex">
import ProTable from "@/components/ProTable/index.vue";
//列表接口
import { getAttachmentListApi, getAttachmentListDelApi, getAttachmentSortApi } from "@/api/modules/downloadList";
import { getCategorysApi } from "@/api/modules/downloadClass";
import { integerRexg } from "@/utils/regexp/index";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件 FORM_DATA
import { RULE_FORM, COLUMNS, EDIT_FORM_DATA, EDIT_RULE_FORM, RULES, EDIT_TABLE_DATA, FORM_DATA } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
const $router = useRouter();
//图片地址
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
// 数据源
const dataStore = reactive<any>({
editTableData: cloneDeep(EDIT_TABLE_DATA), //添加|编辑里的表格数据
editColumns: [
{
label: "文件",
prop: "file_path",
disabled: false,
formType: "up",
width: "250",
align: "left"
},
{
label: "文件格式",
prop: "file_ext",
disabled: false,
formType: "input",
maxLength: 50,
width: "100"
},
//operation
{
label: "按钮名称",
prop: "btn_name",
disabled: false,
formType: "input",
maxLength: 50,
width: "150"
},
{
label: "操作",
prop: "operation",
width: "112"
}
], //添加|编辑里的表格配置项
formData: cloneDeep(FORM_DATA),
columns: COLUMNS, //列表配置项
rules: cloneDeep(RULES), //抽屉表单验证
editRuleForm: cloneDeep(EDIT_RULE_FORM),
editFormData: cloneDeep(EDIT_FORM_DATA), //抽屉表单配置项
initParam: cloneDeep(RULE_FORM) // 初始化搜索条件|重置搜索条件
});
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
//编辑
if (type === "编辑") {
$router.push({
path: "/admin/downloadManagement/list/edit",
query: {
id: row.id,
title: "编辑下载"
}
});
return;
}
//删除
if (type === "删除") {
getAttachmentListDel(row.id);
}
};
const handleAdd = () => {
$router.push({
path: "/admin/downloadManagement/list/edit",
query: {
title: "添加下载"
}
});
};
//删除
const getAttachmentListDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getAttachmentListDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//排序
const getAttachmentSort = async (row: any) => {
const result = await getAttachmentSortApi({ id: row.id, sort: row.sort });
useMsg("success", result?.msg);
if (result?.code === 0) {
proTableRef?.value?.getTableList();
}
};
//排序input框失焦
const handleBlur = (row: any) => {
getAttachmentSort(row);
};
//排序input输入
const handleInput = (row: any) => {
row.sort = integerRexg(row.sort);
};
const getCategorys = async () => {
const result = await getCategorysApi();
if (result?.code === 0) {
let arr: any[] = [];
result?.data?.forEach((item: any) => {
let obj = {
value: item.id,
label: item.name
};
arr.push(obj);
});
dataStore.formData[1].options = arr;
}
};
getCategorys();
</script>
<style scoped></style>

View File

@@ -0,0 +1,3 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,40 @@
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: "category_id",
placeholder: "请选择",
type: "select",
isArray: true,
label: "下载分类: ",
options: []
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,60 @@
import { RenderScope } from "@/components/ProTable/interface";
const YES_OR_NO: any = {
1: "✔️",
0: "❌"
};
export const COLUMNS = [
{ type: "selection", fixed: "left", width: 40 },
{
align: "center",
fixed: true,
label: "ID",
prop: "id",
width: 80
},
{
align: "center",
label: "图片",
prop: "image",
width: 160
},
{
align: "left",
label: "下载名称",
prop: "name"
},
{
align: "left",
label: "下载分类",
prop: "category_name"
},
{
align: "left",
label: "下载排序",
prop: "sort",
width: 160
},
{
align: "left",
label: "首页推荐",
prop: "recommend",
render: (scope: RenderScope<any>): VNode | string | any => {
return YES_OR_NO[scope.row.recommend];
}
},
{
align: "left",
label: "添加时间",
prop: "created_at"
},
{
align: "center",
label: "状态",
prop: "status",
width: 80
},
{ prop: "operation", label: "操作", fixed: "right", width: 200 }
];

View File

@@ -0,0 +1,96 @@
<!-- 视频列表 -->
<template>
<div class="table-box">
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getAttachmentTrashListApi"
: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 ? "删除" : "删除" }}</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="downloadRecycleListIndex">
import ProTable from "@/components/ProTable/index.vue";
import { messageBox } from "@/utils/messageBox";
import { useMsg } from "@/hooks/useMsg";
//列表接口
import { getAttachmentTrashListApi, getAttachmentTrashRestoreApi, getAttachmentTrashDelApi } from "@/api/modules/downloadRecycle";
import { getCategorysApi } from "@/api/modules/downloadClass";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
//图片地址
const h = import.meta.env.VITE_APP_API_BASE_UPLOAD_URL;
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
});
//分类列表
const getCategorys = async () => {
const result = await getCategorysApi();
if (result?.code === 0) {
let arr: any[] = [];
result?.data?.forEach((item: any) => {
let obj = {
value: item.id,
label: item.name
};
arr.push(obj);
});
dataStore.formData[1].options = arr;
}
};
getCategorys();
//删除
const getAttachmentTrashDel = (id: any) => {
messageBox("你确定要删除?", async () => {
const result = await getAttachmentTrashDelApi(id);
if (result?.code === 0) {
const { msg } = result;
useMsg("success", msg);
proTableRef?.value?.getTableList();
}
});
};
//恢复
const getAttachmentTrashRestore = async (id: any) => {
const result = await getAttachmentTrashRestoreApi(id);
if (result?.code === 0) {
useMsg("success", result?.msg);
proTableRef?.value?.getTableList();
}
};
//按钮点击事件
const handleBtnClick = (type: any, row: any) => {
if (type === "恢复") {
getAttachmentTrashRestore(row.id);
}
//删除
if (type === "删除") {
getAttachmentTrashDel(row.id);
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,4 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,57 @@
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: "corp_name",
placeholder: "请输入",
type: "input",
isArray: true,
label: "公司名称: "
},
{
prop: "size_type",
placeholder: "请选择",
type: "select",
options: [
{
value: 1,
label: "待审核"
},
{
value: 2,
label: "已审核"
}
],
label: "企业规模: "
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
//endDate: "createEndDate",
label: "提交时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,49 @@
//import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "提交时间",
prop: "created_at"
},
{
align: "center",
label: "IP定位",
prop: "ip"
},
{
align: "left",
label: "公司名称",
prop: "corp_name"
},
{
align: "left",
label: "邮箱",
prop: "email"
},
{
align: "left",
label: "手机号码",
prop: "phone"
},
{
align: "left",
label: "业务类型",
prop: "business_type_name"
},
{
align: "left",
label: "企业规模",
prop: "enterprise_size_name"
},
{
align: "left",
label: "公司地址",
prop: "address"
},
{
align: "left",
label: "留言内容",
prop: "message"
}
];

View File

@@ -0,0 +1,63 @@
<!-- 联系我们列表 -->
<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="getAgentListApi"
:init-param="dataStore.initParam"
>
</ProTable>
</div>
</template>
<script setup lang="ts" name="feedbackContactIndex">
import ProTable from "@/components/ProTable/index.vue";
import { useExport } from "@/hooks/useExport";
//列表接口
import { getAgentListApi, getAgentListExportApi, getAgentTypesListApi } from "@/api/modules/agent";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
});
const handleExport = () => {
getMenusLisExport();
};
//导出
const getMenusLisExport = async () => {
const result = await getAgentListExportApi(dataStore.ruleForm);
await useExport(result);
};
const getAgentTypesList = async () => {
const result = await getAgentTypesListApi();
if (result?.code === 0) {
let arr: any = [];
result?.data.forEach((item: any) => {
arr.push({
value: item.value,
label: item.name
});
});
dataStore.formData[1].options = arr;
console.log(result?.data);
}
};
getAgentTypesList();
</script>
<style scoped></style>

View File

@@ -0,0 +1,4 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,34 @@
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: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "提交时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50
};

View File

@@ -0,0 +1,29 @@
//import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "提交时间",
prop: "created_at"
},
{
align: "center",
label: "IP定位",
prop: "ip"
},
{
align: "left",
label: "姓名",
prop: "name"
},
{
align: "left",
label: "邮箱",
prop: "email"
},
{
align: "left",
label: "留言内容",
prop: "content"
}
];

View File

@@ -0,0 +1,48 @@
<!-- 联系我们列表 -->
<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="getLeaveMsgListApi"
:init-param="dataStore.initParam"
>
</ProTable>
</div>
</template>
<script setup lang="ts" name="feedbackContactIndex">
import ProTable from "@/components/ProTable/index.vue";
import { useExport } from "@/hooks/useExport";
//列表接口
import { getLeaveMsgListExportApi, getLeaveMsgListApi } from "@/api/modules/contact";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
});
const handleExport = () => {
getMenusLisExport();
};
//导出
const getMenusLisExport = async () => {
const result = await getLeaveMsgListExportApi(dataStore.ruleForm);
await useExport(result);
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,4 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,49 @@
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: "corp_name",
placeholder: "请输入",
type: "input",
isArray: true,
label: "公司名称: "
},
{
prop: "country_name",
placeholder: "请选择",
type: "selectRemote",
options: [],
label: "所在国家: "
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "提交时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50,
orgCode: 0
};

View File

@@ -0,0 +1,47 @@
import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "姓名",
prop: "first_name",
render: (scope: RenderScope<any>): VNode | string | any => {
return scope.row.first_name + scope.row.last_name;
}
},
{
align: "center",
label: "公司名称",
prop: "corp_name"
},
{
align: "left",
label: "邮箱",
prop: "email"
},
{
align: "left",
label: "手机号码",
prop: "phone"
},
{
align: "left",
label: "所在国家",
prop: "country_name"
},
{
align: "left",
label: "行业",
prop: "industry"
},
{
align: "left",
label: "留言内容",
prop: "message"
},
{
align: "left",
label: "提交时间",
prop: "created_at"
}
];

View File

@@ -0,0 +1,68 @@
<!-- 批量采购询盘列表 -->
<template>
<div class="table-box">
<ProTable
ref="proTableRef"
:formData="dataStore.formData"
:columns="dataStore.columns"
:request-api="getProductListApi"
:init-param="dataStore.initParam"
>
</ProTable>
</div>
</template>
<script setup lang="ts" name="feedbackProductIndex">
import ProTable from "@/components/ProTable/index.vue";
//列表接口
import { getProductListApi } from "@/api/modules/product";
// import { getCountryListApi } from "@/api/modules/global";
// import { useUserStore } from "@/stores/modules/user";
// const userStore: any = useUserStore();
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
// ZH: [],
// EN: []
});
// const getCountryList = async () => {
// const result = await getCountryListApi();
// if (result?.code === 0) {
// dataStore.ZH = [];
// dataStore.EN = [];
// result?.data.forEach((item: any) => {
// dataStore.ZH.push({
// label: item.name,
// value: item.id
// });
// dataStore.EN.push({
// label: item.name,
// value: item.id
// });
// });
// dataStore.formData[1].options = userStore.languageType === 1 ? dataStore.ZH : dataStore.EN;
// }
// };
// getCountryList();
// watch(
// () => userStore.languageType,
// (newVal: any) => {
// dataStore.formData[1].options = newVal === 1 ? dataStore.ZH : dataStore.EN;
// },
// { deep: true, immediate: true }
// );
</script>
<style scoped></style>

View File

@@ -0,0 +1,4 @@
import { FORM_DATA, RULE_FORM } from "./search";
import { COLUMNS } from "./table";
export { FORM_DATA, RULE_FORM, COLUMNS };

View File

@@ -0,0 +1,49 @@
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: "corp_name",
placeholder: "请输入",
type: "input",
isArray: true,
label: "公司名称: "
},
{
prop: "interested",
placeholder: "请选择",
type: "select",
options: [],
label: "想采购的产品: "
},
{
prop: "Time",
type: "daterange",
options: [],
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
startDate: "created_at",
// endDate: "createEndDate",
label: "提交时间: "
}
];
export const RULE_FORM = {
page: 1,
size: 50,
orgCode: 0
};

View File

@@ -0,0 +1,47 @@
import { RenderScope } from "@/components/ProTable/interface";
export const COLUMNS = [
{
align: "center",
fixed: true,
label: "提交时间",
prop: "created_at"
},
{
align: "center",
label: "IP定位",
prop: "ip"
},
{
align: "left",
label: "公司名称",
prop: "corp_name"
},
{
align: "left",
label: "姓名",
prop: "first_name",
render: (scope: RenderScope<any>): VNode | string | any => {
return scope.row.first_name + scope.row.last_name;
}
},
{
align: "left",
label: "邮箱",
prop: "email"
},
{
align: "left",
label: "手机号码",
prop: "phone"
},
{
align: "left",
label: "想采购的产品",
prop: "interested"
},
{
align: "left",
label: "询问内容",
prop: "message"
}
];

View File

@@ -0,0 +1,64 @@
<!-- 联系我们列表 -->
<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="getBPListApi"
:init-param="dataStore.initParam"
>
</ProTable>
</div>
</template>
<script setup lang="ts" name="feedbackContactIndex">
import ProTable from "@/components/ProTable/index.vue";
import { useExport } from "@/hooks/useExport";
//列表接口
import { getBPListExportApi, getBPListApi, getBPInterestedListApi } from "@/api/modules/purchase";
//深拷贝方法
import { cloneDeep } from "lodash-es";
//表格和搜索條件
import { RULE_FORM, FORM_DATA, COLUMNS } from "./constant/index";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTableRef = ref<any>(null);
// 数据源
const dataStore = reactive<any>({
columns: COLUMNS, //列表配置项
initParam: cloneDeep(RULE_FORM), // 初始化搜索条件|重置搜索条件
ruleForm: cloneDeep(RULE_FORM), // 搜索參數
formData: FORM_DATA //搜索配置项
});
const handleExport = () => {
getBPListExport();
};
//导出
const getBPListExport = async () => {
const result = await getBPListExportApi(dataStore.ruleForm);
await useExport(result);
};
//
const getBPInterestedList = async () => {
const result = await getBPInterestedListApi();
if (result?.code === 0) {
let arr: any = [];
result?.data.forEach((item: any) => {
arr.push({
label: item,
value: item
});
});
dataStore.formData[1].options = arr;
console.log(result?.data, "=======data========");
}
};
getBPInterestedList();
</script>
<style scoped></style>

29
src/views/home/index.scss Normal file
View File

@@ -0,0 +1,29 @@
.box {
display: flex;
align-items: center;
justify-content: center;
// justify-content: space-between;
width: 100%;
height: 100%;
.box-bg {
width: 70%;
max-width: 1200px;
margin-bottom: 20px;
}
}
.tableItem {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
border-bottom: 1px solid #eeeeee;
}
.tableItem1 {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}

108
src/views/home/index.vue Normal file
View File

@@ -0,0 +1,108 @@
<template>
<div>
<div class="card">
<h4 style="display: flex; align-items: center; margin: 0">
<el-icon :size="20" style="margin-right: 2px"><BellFilled /></el-icon>信息
</h4>
<el-divider style="margin: 10px 0" />
<div style="padding: 20px; color: #ffffff; background: #027415; border-radius: 4px">
<div style="display: flex; align-items: center">
<el-icon :size="18"><Select /></el-icon>
<div style="margin-left: 10px; font-size: 20px; font-weight: 900">欢迎 !</div>
</div>
<div style="margin-top: 10px">欢迎来到首页 !</div>
</div>
</div>
<div class="card" style="margin-top: 20px">
<h4 style="display: flex; align-items: center; margin: 0">
<el-icon :size="20" style="margin-right: 2px"><DArrowLeft /></el-icon>快速进入
</h4>
<el-divider style="margin: 10px 0" />
<!-- 按钮组 -->
<div style="padding-top: 12px">
<el-button
style="margin-bottom: 12px; margin-left: 12px"
type="primary"
v-for="(item, index) in menuList"
:key="index"
@click="handleClickMenu(item)"
>{{ item.meta.title }}</el-button
>
</div>
</div>
<div class="card" style="padding-bottom: 4%; margin-top: 20px">
<h4 style="display: flex; align-items: center; margin: 0">
<el-icon :size="20" style="margin-right: 2px"><Tools /></el-icon>系统信息
</h4>
<el-divider style="margin: 10px 0" />
<div style="min-width: 1340px; border: 1px solid #eeeeee; border-bottom: none">
<div style="display: flex; height: 34px" v-for="(item, index) in tableData" :key="index">
<div class="tableItem1" style="font-weight: 900">
{{ item.name }}
</div>
<div class="tableItem1">
{{ item.text }}
</div>
<div class="tableItem1" style="font-weight: 900">
{{ item.name1 }}
</div>
<div class="tableItem">
{{ item.text1 }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="home">
import { Select, Tools, BellFilled, DArrowLeft } from "@element-plus/icons-vue";
import { useAuthStore } from "@/stores/modules/auth";
import { getSystemInfoApi } from "@/api/modules/home";
const $router = useRouter();
const tableData = ref<any>([]);
const authStore = useAuthStore();
const menuList = computed(() =>
authStore.flatMenuListGet.filter(item => {
const ON_PATH = [
"产品管理",
"视频管理",
"下载管理",
"文章管理",
"Banner管理",
"用户角色管理",
"问答管理",
"反馈管理",
"网站管理"
];
return item.hidden && !ON_PATH.includes(item.meta.title);
})
);
const handleClickMenu = (item: any) => {
$router.push({ path: item.path });
};
const getSystemInfo = async () => {
const result = await getSystemInfoApi();
if (result?.code === 0) {
const newArray = [];
const batchSize = 2; // 每个对象包含的属性对数这里设置为2
for (let i = 0; i < result?.data.length; i += batchSize) {
const obj: any = {};
for (let j = 0; j < batchSize && i + j < result?.data.length; j++) {
const keyPrefix = j === 0 ? "" : j.toString();
obj[`name${keyPrefix}`] = result?.data[i + j].name;
obj[`text${keyPrefix}`] = result?.data[i + j].value;
}
newArray.push(obj);
}
tableData.value = newArray;
}
};
getSystemInfo();
</script>
<style scoped lang="scss">
@import "./index.scss";
</style>

View File

@@ -0,0 +1,3 @@
import { RULES, RULE_FORM } from "./ruleForm";
import { RESET_RULES, RESET_RULE_FORM } from "./resetRuleForm";
export { RULES, RULE_FORM, RESET_RULES, RESET_RULE_FORM };

View File

@@ -0,0 +1,41 @@
export const RESET_RULE_FORM = {
iphone: "", //手机号码
code: "", //验证码
newPassword: "", //新密码
confirmPassword: "" //确认新密码
};
export const RESET_RULES = {
iphone: [
{
required: true,
message: "请填写手机号码",
trigger: "blur"
},
{
pattern: /^1[3-9]\d{9}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
],
code: [
{
required: true,
message: "请填写验证码",
trigger: "blur"
}
],
newPassword: [
{
required: true,
message: "请填写新密码",
trigger: "blur"
}
],
confirmPassword: [
{
required: true,
message: "请填写确认密码",
trigger: "blur"
}
]
};

View File

@@ -0,0 +1,29 @@
export const RULE_FORM = {
username: "",
password: "",
captcha: "",
token: "" //此token是从图片验证码接口获取
}; //登录表单数据
export const RULES = {
username: [
{
required: true,
message: "请填写账号",
trigger: "blur"
}
],
password: [
{
required: true,
message: "请填写密码",
trigger: "blur"
}
],
captcha: [
{
required: true,
message: "请填写验证码",
trigger: "blur"
}
]
};

View File

@@ -0,0 +1,95 @@
.main {
width: 100%;
min-width: 830px;
height: 100%;
overflow: hidden;
}
.main::before {
position: absolute;
display: block;
width: 33%;
height: 100%;
content: "";
background-color: #4178d5;
}
.container {
position: absolute;
top: 50%;
left: 50%;
box-sizing: border-box;
display: flex;
width: 800px;
height: 500px;
font-size: 0;
background-color: #ffffff;
box-shadow: 0 1px 40px 1px rgb(52 69 94 / 19%);
transform: translate(-50%, -50%);
.left {
position: relative;
width: 300px;
height: 500px;
background-image: url("@/assets/images/electronic_component.png");
background-repeat: no-repeat;
background-size: cover;
.left-logo-box {
position: absolute;
top: 50%;
left: 50%;
width: 250px;
height: 150px;
background-image: url("@/assets/images/login_logo.png");
background-repeat: no-repeat;
background-size: cover;
transform: translate(-50%, -50%);
}
}
.left::before {
display: block;
width: 100%;
height: 100%;
content: "";
background-color: rgb(65 120 213 / 60%);
}
.right {
position: relative;
display: flex;
flex-direction: column;
// align-items: center;
justify-content: center;
width: 500px;
height: 460px;
padding: 20px 0;
.right-logo-box {
// position: absolute;
// top: 0;
// left: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
width: 75px;
height: 75px;
margin-left: 100px;
background-image: url("@/assets/images/right-logo.png");
background-repeat: no-repeat;
background-size: cover;
// transform: translate(-50%, -50%);
.right-logo-font {
font-family: "Microsoft YaHei", Georgia, "Times New Roman", Times, serif;
font-size: 19px;
font-weight: 900;
color: #122b5a;
}
.sign-in {
font-family: "Microsoft YaHei", Georgia, "Times New Roman", Times, serif;
font-size: 12px;
color: #b5bdce;
}
}
}
}
.el-input-group__append {
padding: 0 8px;
}

291
src/views/login/index.vue Normal file
View File

@@ -0,0 +1,291 @@
<template>
<div class="main">
<div class="container">
<div class="left">
<div class="left-logo-box"></div>
</div>
<!-- 登录 -->
<div class="right" v-if="dataStore.type === 1">
<div class="right-logo-box">
<div>
<div class="right-logo-font">登录</div>
<div class="sign-in">Sign in</div>
</div>
</div>
<div style="margin-left: 100px">
<el-form
ref="ruleFormRef"
style="width: 300px"
:model="dataStore.ruleForm"
:rules="dataStore.rules"
label-width="auto"
label-position="top"
class="demo-ruleForm"
hide-required-asterisk
>
<el-form-item label="账号" prop="username">
<el-input v-model="dataStore.ruleForm.username" :prefix-icon="Iphone" autocomplete="off" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="dataStore.ruleForm.password"
type="password"
show-password
:prefix-icon="Lock"
autocomplete="off"
/>
<!-- <div
style="
width: 350px;
font-size: 12px;
line-height: 1;
color: #4178d5;
text-align: right;
cursor: pointer;
"
@click="handleTabClick(2)"
>
忘记密码?
</div> -->
</el-form-item>
<!-- <el-form-item prop="captcha">
<span style="margin-right: 10px; color: #606266">验证码</span>
<el-input v-model="dataStore.ruleForm.captcha" style="width: 80px" autocomplete="off" />
<img :src="dataStore.base64" style="width: 150px; height: 60px; margin: 0 6px" />
<el-button type="primary" v-debounce="getLoginCodeImg">刷新</el-button>
</el-form-item> -->
<el-form-item>
<el-button
size="large"
type="primary"
style="width: 100px; height: 36px; border-radius: 2px; box-shadow: 2px 5px 16px #4178d5"
v-debounce="submitForm"
>登录</el-button
>
</el-form-item>
</el-form>
</div>
</div>
<!--忘记密码 -->
<div class="right" v-if="dataStore.type === 2">
<div style="margin-left: 100px">
<el-button
type="primary"
:icon="ArrowLeftBold"
circle
style="margin: 60px 0 20px"
@click="handleTabClick(1)"
/>
<el-form
ref="resetRuleFormRef"
:model="dataStore.resetRuleForm"
:rules="dataStore.resetRules"
label-width="auto"
label-position="top"
class="demo-ruleForm"
hide-required-asterisk
>
<el-form-item label="手机号" prop="iphone">
<el-input v-model="dataStore.resetRuleForm.iphone" :prefix-icon="Iphone" autocomplete="off" />
</el-form-item>
<el-form-item prop="code" label="验证码">
<el-input v-model="dataStore.resetRuleForm.code" autocomplete="off">
<template #append>
<div style="font-size: 14px; color: #4178d5; cursor: pointer" v-debounce="handleGetCode">
{{ dataStore.codeFont }}
</div>
<div v-if="dataStore.isShowTime" style="margin: 0 5px; font-size: 14px; color: #4178d5">
{{ dataStore.timeCount }}s
</div>
</template>
</el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input
v-model="dataStore.resetRuleForm.newPassword"
type="password"
show-password
:prefix-icon="Lock"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="dataStore.resetRuleForm.confirmPassword"
type="password"
show-password
:prefix-icon="Lock"
autocomplete="off"
/>
</el-form-item>
<el-form-item>
<el-button
size="large"
type="primary"
style="width: 100px; height: 36px; border-radius: 2px; box-shadow: 2px 5px 16px #4178d5"
v-debounce="resetConfirmForm"
>提交</el-button
>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import CryptoJS from "crypto-js";
//loginCodeImgApi
import { loginApi } from "@/api/modules/login";
import { Iphone, Lock, ArrowLeftBold } from "@element-plus/icons-vue";
import { RULES, RULE_FORM, RESET_RULES, RESET_RULE_FORM } from "./constant/index";
import { cloneDeep } from "lodash-es";
//用户信息存储
import { useUserStore } from "@/stores/modules/user";
const userStore = useUserStore();
const $router = useRouter();
//登录表单Ref
const ruleFormRef: any = ref(null);
//修改密码表单Ref
const resetRuleFormRef: any = ref(null);
//数据源
const dataStore = reactive<any>({
timeCount: 120, //修改密码里验证码倒计时
isShowTime: false,
base64: "", //验证码图片
type: 1, //1:登录,2:修改密码
codeFont: "获取验证码", //修改密码里的验证码按钮文字
ruleForm: cloneDeep(RULE_FORM), //登录表单数据
rules: cloneDeep(RULES), //登录表单验证
resetRuleForm: cloneDeep(RESET_RULE_FORM), //修改密码表单数据
resetRules: cloneDeep(RESET_RULES) //修改密码表单验证
});
//计时器
let intervalId: any = null;
//登录
const submitForm = () => {
console.log(ruleFormRef);
if (!ruleFormRef) return;
ruleFormRef?.value?.validate((valid: any) => {
if (valid) {
login();
} else {
console.log("error submit!");
}
});
};
//忘记密码提交事件
const resetConfirmForm = () => {
if (!resetRuleFormRef) return;
resetRuleFormRef?.value?.validate((valid: any) => {
if (valid) {
let password = CryptoJS.MD5(dataStore.ruleForm.password)?.toString();
console.log(password, "==== dataStore.ruleForm.password====");
console.log("submit!");
} else {
console.log("error submit!");
}
});
};
//登录接口
const login = async () => {
const result: any = await loginApi({
...dataStore.ruleForm,
password: CryptoJS?.MD5(dataStore.ruleForm.password)?.toString()
});
if (result?.code === 0) {
const { data } = result;
setUserData(data);
}
// else {
// getLoginCodeImg();
// }
};
//获取验证码图片接口
// const getLoginCodeImg = async () => {
// const result: any = await loginCodeImgApi();
// if (result?.code === 0) {
// const { data } = result;
// const { captcha, token } = data;
// dataStore.base64 = captcha;
// dataStore.ruleForm.token = token;
// }
// };
// getLoginCodeImg();
//登录和密码重置切换
const handleTabClick = (type: any) => {
dataStore.type = type;
for (let key in dataStore.ruleForm) {
dataStore.ruleForm[key] = "";
}
for (let key in dataStore.resetRuleForm) {
dataStore.resetRuleForm[key] = "";
}
if (intervalId) {
handleClearInterval();
dataStore.timeCount = 120;
dataStore.isShowTime = false;
}
};
//120秒验证时间
const updateCountdown = () => {
intervalId = setInterval(() => {
if (dataStore.timeCount > 0) {
dataStore.isShowTime = true;
dataStore.timeCount--;
} else {
handleClearInterval();
dataStore.timeCount = 120;
dataStore.isShowTime = false;
}
}, 1000);
};
//获取验证码
const handleGetCode = () => {
//如果计时器已经启动了,就不要再去触发了
if (intervalId) {
return;
}
resetRuleFormRef.value.validateField("iphone", (valid: any) => {
if (valid) {
updateCountdown();
} else {
}
});
};
//清理定时器
const handleClearInterval = () => {
clearInterval(intervalId);
intervalId = null;
};
// 设置用户数据
const setUserData = (data: any) => {
const { username, uid, token, avatar } = data;
console.log();
// 设置token
userStore.setToken(token);
userStore.setUid(uid);
userStore.setNickname(username);
userStore.setAvatar(avatar);
// await userStore.getAuthMenuList();
//跳转到首页
setTimeout(() => {
$router.push("/admin/index");
}, 500);
};
onUnmounted(() => {
//页面卸载的时候清空定时器
if (intervalId) {
handleClearInterval();
}
});
</script>
<style lang="scss">
@import "./index.scss";
</style>

View 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: "" //新增
};

View File

@@ -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 };

View File

@@ -0,0 +1,4 @@
export const RULES = {
attr_name: [{ required: true, message: "产品属性不能为空 ! ", trigger: "blur" }]
// attributeValue: [{ required: true, message: "产品属性值不能为空 ! ", trigger: "blur" }]
};

View 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
};

View 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 }
];

View 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>

View File

@@ -0,0 +1,3 @@
import { handleSubmit } from "./submit";
import { handleReset } from "./reset";
export { handleSubmit, handleReset };

View 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);
});
};

View 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;
}
};

View 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");
});
};

View 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
}
]
}
];

View 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 };

View File

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

View 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" }]
};

View File

@@ -0,0 +1,9 @@
export const SEARCH = [
{
prop: "keywords",
placeholder: "请输入",
type: "input",
isArray: true,
label: "分类名称"
}
];

View 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>

View 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 };

Some files were not shown because too many files have changed in this diff Show More