Skip to content
导航目录

前端代码

涉及文件

温馨提示

主要涉及api接口,views视图,其它文件无须修改;路由是后端接口返回,需要先在后台创建菜单路由

代码均可使用代码生成工具一键生成,分别存放cogen 目录下

1. 添加路由

  • 路由分为菜单和按钮两种
  • 菜单主要设置,权限标识,路由路径,组件路径;
  • 按钮主要设置权限标识
  • 权限标识采用api接口名称,用“:” 分割,用于操作权限校验,使用/@/utils/authFunctionauth方法
  • 路由路径 是在视图在views 下的目录路径,例如 /system/user
  • 组件路径 是在视图在views 下的文件路径,例如 /system/user/index;一级菜单默认/layout/routerView/parent

/images/menu.png

/images/btn.png

2. 添加接口

  • src\api 目录下添加接口文件,主要方法增删改查
sh
import request from '/@/utils/request';

//获取分页列表
export function getList(params: object) {
	return request({
		url: '/admin/admin/index',
		method: 'post',
		data: params,
	});
}

//获取全部菜单列表
export function getListAll(params: any) {
	return request({
		url: '/admin/admin/getlists',
		method: 'post',
		data: params,
	});
}

//获取详情
export function getinfo(id: String) {
	return request({
		url: '/admin/admin/getinfo',
		method: 'post',
		data: { id },
	});
}

//保存
export function save(params: object) {
	return request({
		url: '/admin/admin/save',
		method: 'post',
		data: params,
	});
}

//删除
export function del(id: String) {
	return request({
		url: '/admin/admin/del',
		method: 'post',
		data: { id },
	});
}

3. 创建视图列表

  • 根据组件路径,在src\views 下面创建文件
  • 主要结构包括查询,表格,操作,分页,表单
sh
<template>
	<div class="table-admin-container layout-padding">
		<div class="table-admin-padding layout-padding-view layout-padding-auto">
			<TableSearch :search="state.tableData.search" :isAdd="state.tableData.config.isAdd" @search="onSearch" @add="onTableAddRow"/>
			<Table
				ref="tableRef"
				v-bind="state.tableData"
				class="table-admin"
				@updateRow="onTableUpdateRow"
				@delRow="onTableDelRow"
				@pageChange="onTablePageChange"
				@sortHeader="onSortHeader"
			/>
		</div>
		<EditDialog  ref="editRef"  @refresh="getTableData()" />
	</div>
</template>
  • 主要操作方法包括列表,新增,修改,分页
sh
<script setup lang="ts" name="articleColumn">
import { defineAsyncComponent, reactive, ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { getListAll,del } from '/@/api/articlecolumn/index';
import { handleTree } from '/@/utils';

// 引入组件
const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'));
const TableSearch = defineAsyncComponent(() => import('/@/components/table/search.vue'));
const EditDialog = defineAsyncComponent(() => import('/@/views/article/column/form/edit.vue'));

// 定义变量内容
const tableRef = ref<RefType>();
const editRef = ref();
const state = reactive<TableDemoState>({
	tableData: {
		// 列表数据(必传)
		data: [],
		// 表头内容(必传,注意格式)
		header: [
			{ key: 'id', colWidth: '80', title: 'ID', type: 'text', isCheck: true },
			{ key: 'name', colWidth: '300', title: '名称', type: 'text', isCheck: true },
			{ key: 'imgs', colWidth: '80', title: '封面', type: 'image', isCheck: true },
			{ key: 'sorts', colWidth: '', title: '排序', type: 'text',  isCheck: true },
			{ key: 'types', colWidth: '', title: '类型', type: 'radio', dict:{'1':'列表','2':'单页','3':'链接'},isCheck: true },
			{ key: 'status', colWidth: '', title: '状态', type: 'radio',dict:{'1':'正常','0':'禁用'},isCheck: true },
		],
		// 配置项(必传)
		config: {
			total: 0, // 列表总数
			loading: true, // loading 加载
			isBorder: false, // 是否显示表格边框
			isSerialNo: false, // 是否显示表格序号
			isSelection: true, // 是否显示表格多选
			isOperate: true, // 是否显示表格操作栏
			isAdd: 'admin:articlecolumn:save', //新增标识
			isUpdate: 'admin:articlecolumn:save', //修改标识
			isDelete: 'admin:articlecolumn:del', //删除标识
		},
		// 搜索表单,动态生成(传空数组时,将不显示搜索,注意格式)
		search: [
			{ label: '名称', prop: 'name', placeholder: '请输入名称', required: false, type: 'input' },
			{
				label: '状态',
				prop: 'status',
				placeholder: '请选择',
				required: false,
				type: 'select',
				options: [
					{ label: '正常', value: 1 },
					{ label: '禁用', value: 0 },
				],
			},
		],
		// 搜索参数(不用传,用于分页、搜索时传给后台的值,`getTableData` 中使用)
		param: {
			page: 1,
			psize: 10,
		},
		// 打印标题
		printName: '数据打印',
		//列字典
		dictData:{
		},
	},
	
});

// 初始化列表数据
const getTableData =  () => {
	state.tableData.config.loading = true;
	state.tableData.data = [];
	getListAll(state.tableData.param).then((response: any) => {
		state.tableData.data = handleTree(response.data.data, 'id', 'pid', 'children');
		state.tableData.config.total = response.data.total;
		state.tableData.config.loading = false;
	});
};

// 搜索点击时表单回调
const onSearch = (data: EmptyObjectType) => {
	state.tableData.param = Object.assign({}, state.tableData.param, { ...data });
	tableRef.value.pageReset();
};
// 删除当前项回调
const onTableDelRow = (row: EmptyObjectType) => {
	return del(row.id).then(() => {
		getTableData();
		ElMessage.success(`删除${row.id}成功!`);
	});
};
// 分页改变时回调
const onTablePageChange = (page: TableDemoPageType) => {
	state.tableData.param.page = page.page;
	state.tableData.param.psize = page.psize;
	getTableData();
};
// 拖动显示列排序回调
const onSortHeader = (data: TableHeaderType[]) => {
	state.tableData.header = data;
};

/** 新增按钮操作 */
const onTableAddRow = () => {
	editRef.value.openDialog('add');
};
/** 修改按钮操作 */
const onTableUpdateRow = (row: any) => {
	editRef.value.openDialog('edit',row);
};


// 页面加载时
onMounted(() => {
	getTableData();
});
</script>

<style scoped lang="scss">

</style>

4. 创建视图表单

  • 根据路由路径,在src\views\路由路径\form 下面创建文件
  • 主要结构包括表单字段和保存按钮
sh
<template>
	<div class="system-menu-dialog-container">
		<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
			<el-form ref="dialogFormRef" :model="state.ruleForm" :rules="state.ruleRules" size="default" label-width="80px">
				<el-row :gutter="35">
					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
						<el-form-item label="上级栏目" prop="pid">
							<el-cascader
								:options="state.menuData"
								:props="{ checkStrictly: true, value: 'id', label: 'name' }"
								placeholder="请选择上级栏目"
								clearable
								class="w100"
								v-model="state.ruleForm.pid"
							>
								<template #default="{ node, data }">
									<span>{{ data.name }}</span>
									<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
								</template>
							</el-cascader>
						</el-form-item>
					</el-col>
					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" class="mb20">
						<el-form-item label="栏目类型" prop="types">
							<el-radio-group v-model="state.ruleForm.types">
								<el-radio :label="1">列表</el-radio>
								<el-radio :label="2">单页</el-radio>
								<el-radio :label="3">链接</el-radio>
							</el-radio-group>
						</el-form-item>
					</el-col>
					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
						<el-form-item label="栏目状态" prop="status">
							<el-radio-group v-model="state.ruleForm.status">
								<el-radio :label="1">正常</el-radio>
								<el-radio :label="0">禁用</el-radio>
							</el-radio-group>
						</el-form-item>
					</el-col>
					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
						<el-form-item label="栏目名称" prop="name">
							<el-input v-model="state.ruleForm.name" placeholder="请输入栏目名称" clearable></el-input>
						</el-form-item>
					</el-col>

					 
					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
						<el-form-item label="SEO描述" prop="seo_dec">
							<el-input v-model="state.ruleForm.seo_dec" type="textarea" placeholder="请输入SEO描述" clearable></el-input>
						</el-form-item>
					</el-col>

						
					
				</el-row>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="onCancel" size="default">取 消</el-button>
					<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
				</span>
			</template>
		</el-dialog>
	</div>
</template>
  • 主要操作方法包括详情,保存
sh
<script setup lang="ts" name="articleColumnForm">
import { defineAsyncComponent, reactive, onMounted, ref ,unref,nextTick} from 'vue';
import { getListAll,getinfo,save } from '/@/api/articlecolumn/index';
import { ElMessageBox, ElMessage } from 'element-plus';
import { handleTree } from '/@/utils';

// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);

// 引入组件
const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
const Uploadimg = defineAsyncComponent(() => import('/@/components/Upload/singleImage.vue'));

// 定义变量内容
const dialogFormRef = ref();
const state = reactive({
	ruleForm: {
		id:0,
		pid: 0, // 上级栏目
		types: 1, // 栏目类型 
		
	},
	menuData: [] , // 上级栏目数据
	dialog: {
		isShowDialog: false,
		type: '',
		title: '',
		submitTxt: '',
	},
	// 表单校验
	ruleRules: {
		name: [{ required: true, message: '栏目名称不能为空', trigger: 'blur' }],
	},
	loading: false,
	msg:'最佳尺寸',
});

const onUpload = (data) => {
	state.ruleForm.imgs = data;
};


// 打开弹窗
const openDialog = (type: string, row?: any) => {
	if (type === 'edit') {
		// 实际请走接口
		getinfo(row.id).then((response: any) => {
			state.ruleForm.id = response.data.id;
			state.ruleForm.seo_dec = response.data.seo_dec; 
		});
		
		state.dialog.title = '修改栏目';
		state.dialog.submitTxt = '修 改';
	} else {
		state.dialog.title = '新增栏目';
		state.dialog.submitTxt = '新 增';
		// 清空表单,此项需加表单验证才能使用
		nextTick(() => {
			dialogFormRef.value.resetFields();
			initForm();
		});
	}
	state.dialog.type = type;
	state.dialog.isShowDialog = true;
	// 查询栏目下拉树结构
	getListAll().then((response: any) => {
		response.data.data.unshift({ id: 0, name: '顶级栏目' });
		state.menuData = handleTree(response.data.data, 'id', 'pid', 'children');
	});
};
// 关闭弹窗
const closeDialog = () => {
	initForm();
	state.dialog.isShowDialog = false;
};

// 取消
const onCancel = () => {
	closeDialog();
};
// 提交
const onSubmit = () => {

	const formWrap = unref(dialogFormRef) as any;
	if (!formWrap) return;
	formWrap.validate((valid: boolean) => {
		if (valid) {
			state.loading = true;
			if(state.ruleForm.pid != 0 &&  typeof(state.ruleForm.pid) == 'object'){
				state.ruleForm.pid = state.ruleForm.pid.pop();
			}
			save(state.ruleForm)
				.then(() => {
					ElMessage.success('保存成功');
					state.loading = false;
					closeDialog(); // 关闭弹窗
					emit('refresh');
				})
				.finally(() => {
					state.loading = false;
				});
		}
	})
};
// 页面加载时
onMounted(() => {
	
});


// 表单初始化,方法:`resetFields()` 无法使用
const initForm = () => {
	state.ruleForm.id = 0;
	state.ruleForm.seo_dec = ''; 
};

// 暴露变量
defineExpose({
	openDialog,
});
</script>

5. 刷新页面

  • 刷新页面,查看结果

欢迎使用HardAdmin