Vben Admin 自学记录 —— 使用 mock 模拟数据以及模拟api联调接口(持续更新中...)
Vben Admin —— 使用 mock 模拟数据以及模拟api联调接口
数据 mock&联调相关概念及使用
练习 —— 在之前table基础上,使用mock模拟数据,替换原来的死数据,添加新增、查看、修改和删除api并添加逻辑,实现一个简单的、完整的增删改查页面
/mock文件夹下添加table文件夹,其中添加tableMock.ts

/mock/table/tableMock.ts
import { time } from 'console';
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess, resultError, requestParams, getRequestToken } from '../_util';const tableListData = {pager: {list: [{contno: '610964224475996443',name: '张三',sex: '0',dt: '20200701',age: '22',tel: '13789890909',address: '北京市北京小区',},{contno: '610964224475996442',name: '李四',sex: '1',dt: '20230507',age: '27',tel: '15477778888',address: '大连市大连小区',},{contno: '610964224475996445',name: '王五',sex: '0',dt: '20221001',age: '26',tel: '15477778888',address: '大连市大连小区',},{contno: '610964224475996446',name: '小明',sex: '0',dt: '20220701',age: '25',tel: '15477778888',address: '大连市大连小区',},{contno: '610964224475996447',name: '小红',sex: '1',dt: '20180808',age: '28',tel: '15477778888',address: '大连市大连小区',},],},
};export default [{url: '/basic-api/table/getListData',timeout: 200,method: 'get',response: () => {return resultSuccess(tableListData);},},{url: '/basic-api/table/addListData',timeout: 1000,method: 'post',response: (request: requestParams) => {tableListData.pager.list.push(request.body);return resultSuccess({});},},{url: '/basic-api/table/editListData',timeout: 1000,method: 'post',response: (request: requestParams) => {let list: any[] = [];for (let item of tableListData.pager.list) {console.log('item', item);if (request.body.contno === item.contno) {list.push(request.body);} else {list.push(item);}}tableListData.pager.list = list;return resultSuccess({});},},{url: '/basic-api/table/delListData',timeout: 1000,method: 'post',response: (request: requestParams) => {let list: any[] = [];for (let item of tableListData.pager.list) {console.log('item', item);if (request.body.contno === item.contno) {} else {list.push(item);}}tableListData.pager.list = list;return resultSuccess({});},},
] as MockMethod[];
/src/api/table下添加相关api

/src/api/table/tableApi.ts
import { defHttp } from '/@/utils/http/axios';enum Api {LIST_DATA = '/table/getListData',ADD_DATA = '/table/addListData',EDIT_DATA = '/table/editListData',DEL_DATA = '/table/delListData',
}/*** @description: Get sample list value*/// export const printSignIssue = (params) =>
// defHttp.post({
// url: Api.PRINT_AMT,
// params,
// });
// table列表
export const getListDataApi = (params) =>defHttp.get({url: Api.LIST_DATA,params,});// 新增
export const addListDataApi = (params) =>defHttp.post({url: Api.ADD_DATA,params,});// 编辑
export const editListDataApi = (params) =>defHttp.post({url: Api.EDIT_DATA,params,});// 删除
export const delListDataApi = (params) =>defHttp.post({url: Api.DEL_DATA,params,});
!注意:
在使用页面使用mock和api前,要先在 /src/settings/componentSetting.ts中修改响应后处理的配置,我自己之前没有设置这里,所以table组件useTable调接口一直不通

componentSetting.ts
export default {// basic-table settingtable: {// Form interface request general configuration// support xxx.xxx.xxxfetchSetting: {// The field name of the current page passed to the backgroundpageField: 'page',// The number field name of each page displayed in the backgroundsizeField: 'pageSize',// Field name of the form data returned by the interface// listField: 'items',// 这里要和 mock 和 api 返回的数据字段匹配listField: 'pager.list',// Total number of tables returned by the interface field nametotalField: 'total',},// Number of pages that can be selectedpageSizeOptions: ['10', '50', '80', '100'],// Default display quantity on one pagedefaultPageSize: 10,// Default SizedefaultSize: 'middle',// Custom general sort functiondefaultSortFn: (sortInfo: SorterResult) => {const { field, order } = sortInfo;if (field && order) {return {// The sort field passed to the backend youfield,// Sorting method passed to the background asc/descorder,};} else {return {};}},// Custom general filter functiondefaultFilterFn: (data: Partial<Recordable<string[]>>) => {return data;},},// scrollbar settingscrollbar: {// Whether to use native scroll bar// After opening, the menu, modal, drawer will change the pop-up scroll bar to nativenative: false,},
};
在之前的table练习中添加并使用api,注:我的新增、编辑和查看都改成了使用Drawer组件弹出,添加了AEVDrawerPage.vue,和之前Drawer练习的页面代码差不太多

之前相关记录:
- Table组件的基本使用及练习
- Drawer组件的基本使用及练习
data.ts
import { FormProps, FormSchema } from '/@/components/Form';
import { BasicColumn } from '/@/components/Table';
import { formatToDate } from '/@/utils/dateUtil';
import { Switch } from 'ant-design-vue';
import { ref, h, computed } from 'vue';type sexOptionType = [{ label: string; value: string }, { label: string; value: string }];const sexOption: sexOptionType = [{ value: '0', label: '男' },{ value: '1', label: '女' },
];// 配置表格SearchForm字段
export const formConfig: Partial<FormProps> = {labelWidth: 120,actionColOptions: {span: 25,},//自动展开行autoAdvancedLine: 1,showAdvancedButton: true,baseColProps: {span: 8,},schemas: [{field: 'contno',label: '承兑协议号',component: 'Input',defaultValue: '',componentProps: ({ formModel }) => {return {style: { width: '100%', textAlign: 'left' },onInput: (e) => {formModel.contno = formModel.contno.replace(/[^\w-\/]/gi, '');},};},},{field: 'name',label: '姓名',component: 'Input',},{field: 'sex',label: '性别',component: 'Select',componentProps: {options: sexOption,},},{field: 'dt',label: '出生日期',component: 'DatePicker',componentProps: {style: {width: '100%',},valueFormat: 'YYYYMMDD',},},{field: 'age',label: '年龄',component: 'InputNumber',componentProps: {style: {width: '100%',},},},],
};// 配置表格表头字段
export const columns: BasicColumn[] = [{title: '承兑协议号',dataIndex: 'contno',// ifShow:falsewidth: 200,},{title: '姓名',width: 200,dataIndex: 'name',// helpMessage:'aaa',// edit:true},{title: '性别',width: 200,dataIndex: 'sex',customRender: function (text) {console.log('text', text);return text.text === '0' ? '男' : '女';},// customRender:({record}) => {// console.log(record)// return h(Switch,{checked:record.sex == '0'},)// }},{title: '出生日期',width: 200,dataIndex: 'dt',customRender: function (text) {return formatToDate(text.text);},},{title: '年龄',width: 200,dataIndex: 'age',},{title: '电话',width: 200,dataIndex: 'tel',},{title: '住址',width: 200,dataIndex: 'address',},
];export const schemasView: FormSchema[] = [{field: 'divider-bill',component: 'Divider',label: '信息',colProps: {span: 24,},},{field: 'contno',component: 'Input',label: '承兑协议号',required: true,defaultValue: '',componentProps: ({ formModel }) => {return {style: { width: '100%', textAlign: 'left' },oninput: (e) => {// formModel.contno = formModel.contno.replace(/[^\w\/]/ig, '');},};},dynamicRules: () => {return [{required: true,validator: (_, value) => {if (!value) {return Promise.reject('请输入承兑协议号');}},},];},},{field: 'name',component: 'Input',label: '姓名',required: true,},{field: 'sex',component: 'Select',label: '性别',required: true,componentProps: {options: sexOption,},},{field: 'dt',component: 'DatePicker',label: '出生日期',required: true,componentProps: {style: { width: '100%' },valueFormat: 'YYYYMMDD',},},{field: 'age',component: 'InputNumber',label: '年龄',required: true,componentProps: {style: { width: '100%' },step: 1,min: 0,max: 150,},},{label: '电话',field: 'tel',component: 'Input',required: true,dynamicRules: ({ values }) => {if (values.tel !== undefined) {if (values.tel.indexOf('-') > 0) {return [{required: true,trigger: 'change',message: '请输入正确的号码',pattern: /(^\d{4}-\d{7}$)|(^\d{3}-\d{8}$)/,},];} else {return [{required: true,trigger: 'change',message: '请输入正确的号码',pattern: /^1[3|4|5|7|8][0-9]{9}$/,},];}} else {return [{ required: true, message: '请输入电话' }];}},},{field: 'address',component: 'InputTextArea',label: '住址',required: true,},
];// 姓名
// 性别
// 出生日期
// 年龄
// 电话 tel
// 住址 address// 表单数据
export function initData() {return [{name: '张三',sex: '男',dt: '20200701',age: '22',tel: '13789890909',address: '北京市北京小区',},{name: '李四',sex: '女',dt: '20230507',age: '27',tel: '15477778888',address: '大连市大连小区',},{name: '王五',sex: '男',dt: '20221001',age: '26',tel: '15477778888',address: '大连市大连小区',},{name: '小明',sex: '男',dt: '20220701',age: '25',tel: '15477778888',address: '大连市大连小区',},{name: '小红',sex: '女',dt: '20180808',age: '28',tel: '15477778888',address: '大连市大连小区',},];
}
basicTable.vue
<template><div:style="{overflow: 'hidden',position: 'relative',height: '100%',}"><BasicTable @register="registerTable"><template #action="{ record }"><TableAction:actions="[{tooltip: '查看',icon: 'clarity:info-standard-line',onClick: handleOpen.bind(null, { type: 'view', data: record }),},{tooltip: '编辑',icon: 'clarity:note-edit-line',onClick: handleOpen.bind(null, { type: 'edit', data: record }),},{tooltip: '删除',color: 'error',icon: 'ant-design:delete-outlined',popConfirm: {title: '是否确定删除?',confirm: handleDel.bind(null, record),},},]"/>template><template #toolbar><a-button type="primary" @click="handleOpen({ type: 'add', data: {} })">{{'新增'}}a-button><a-button color="warning" @click="exitExcel()">{{ '导出 Excel' }}a-button>template>BasicTable><AEVDrawerPage @reload="handleReload" @register="registerDrawer" />div>
template><script lang="ts">import { defineComponent } from 'vue';// import { router } from '/@/router';import { formConfig, columns, initData } from './data';import { BasicTable, useTable, TableAction } from '/@/components/Table';import { useDrawer } from '/@/components/Drawer';// import { useModal } from '/@/components/Modal';import { useMessage } from '/@/hooks/web/useMessage';// import { aoaToSheetXlsx } from '/@/components/Excel';import { getListDataApi, delListDataApi } from '../../../api/table/tableApi';// import ViewDrawer from './ViewDrawer.vue';// import EditModal from './EditModal.vue';import AEVDrawerPage from './AEVDrawerPage.vue';export default defineComponent({name: 'tableTest',components: {BasicTable,TableAction,AEVDrawerPage,// ViewDrawer,// EditModal},setup() {// const data = initData();const { createMessage } = useMessage();// 设置tableconst [registerTable, { reload, clearSelectedRowKeys }] = useTable({title: '查询结果',// 调用接口,之前的写死数据就不用了api: getListDataApi,// dataSource: data,columns: columns,bordered: true,useSearchForm: true, //开启搜索区域formConfig: formConfig,// striped:false,// showSummary:true,// loading:true,afterFetch: (data) => {console.log('data', data);clearSelectedRowKeys();},actionColumn: {width: 120,title: '操作',dataIndex: 'action',slots: { customRender: 'action' },},rowSelection: { type: 'radio' },pagination: { pageSize: 10 },showTableSetting: true,tableSetting: { fullScreen: true },showIndexColumn: true,indexColumnProps: { fixed: 'left' },},);// 注册Drawerconst [registerDrawer, { openDrawer: openAEVDrawerPage, setDrawerProps }] = useDrawer();// 配置Modal// const [registerModal, { openModal }] = useModal();async function handleOpen({ type, data }) {await openAEVDrawerPage(true, { type, data });if (type === 'add') {setDrawerProps({ title: '新增' });} else if (type === 'edit') {setDrawerProps({ title: '修改' });} else {setDrawerProps({ title: '查看' });}}// async function exitExcel() {// let tableData:[][] = getDataSource();// let columns = getColumns()// let titleArr = columns.map(item => {// return item.title// })// console.log('tableData', tableData,columns,titleArr);// // debugger;// aoaToSheetXlsx({// data: tableData,// header: titleArr,// filename: '导出excel.xlsx',// });// }// 新增按钮// function handleAdd() {// router.push({// path: '/testRoute/addPage',// });// }// 查看按钮// function handleView({ data }) {// openDrawer(true, data);// }// 编辑按钮// function handleEdit({ data }) {// openModal(true, data);// }// 删除按钮async function handleDel(record: Recordable) {console.log('删除数据', record);await delListDataApi(record).then(() => {createMessage.success('删除成功');reload();});}function handleReload() {reload();}return {registerTable,reload,handleOpen,// 新增路由跳转// handleAdd,// 查看抽屉registerDrawer,// handleView,handleReload,// 编辑弹窗// registerModal,// handleEdit,// 删除handleDel,// exitExcel,};},});
script><style scoped>style>
AEVDrawerPage.vue(除了主要的调用接口,还有点我自己练习的tabs等相关代码,可以忽略不看…)
<template><div:style="{overflow: 'hidden',}"><BasicDrawerv-bind="$attrs"@register="registerDrawer"@visibleChange="handleVisibleChange":isDetail="true"title="查看"placement="bottom"height="100%":destroyOnClose="true"><a-tabs><a-tab-pane key="1" tab="表单页面"><div><BasicForm @register="registerForm">BasicForm>div><Divider /><PageFooter v-if="showPageFooter"><template #right><a-button @click="handleCancel"> 取消a-button><a-button class="!ml-4" type="primary" @click="handleSubmit" :loading="isLoading">保存a-button>template>PageFooter>a-tab-pane><a-tab-pane key="2" tab="明细页面">{'新增'}}{{ '导出 Excel' }} -->a-tab-pane><a-tab-pane key="3" tab="其他页面">a-tab-pane>a-tabs>BasicDrawer>div>
template><script lang="ts">import { defineComponent, Ref, ref } from 'vue';import { Button, Divider, Tabs } from 'ant-design-vue';import { BasicTable, useTable, TableAction } from '/@/components/Table';import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';import { BasicForm, useForm } from '/@/components/Form';import { PageFooter } from '/@/components/Page';import { useMessage } from '/@/hooks/web/useMessage';import { schemasView } from './data';import {// getListDataApi,addListDataApi,editListDataApi,} from '/@/api/table/tableApi';// import { formConfig, columns, initData } from './data';export default defineComponent({name: 'AEVDrawerPage',components: {BasicDrawer,BasicForm,Divider,PageFooter,[Tabs.name]: Tabs,[Tabs.TabPane.name]: Tabs.TabPane,[Button.name]: Button,BasicTable,TableAction,},setup(_, { emit }) {const { createMessage } = useMessage();const currentType: Ref = ref('add');const showPageFooter: Ref = ref(true);const isLoading = ref(false);// const [registerTable, { }] = useTable(// {// title: '查询结果',// api: getListDataApi,// // dataSource: data,// columns: columns,// bordered: true,// // useSearchForm: true, //开启搜索区域// // formConfig: formConfig,// // striped:false,// // showSummary:true,// // loading:true,// actionColumn: {// width: 120,// title: '操作',// dataIndex: 'action',// slots: { customRender: 'action' },// },// rowSelection: { type: 'radio' },// pagination: { pageSize: 10 },// showTableSetting: true,// tableSetting: { fullScreen: true },// showIndexColumn: true,// indexColumnProps: { fixed: 'left' },// },// );// 配置Drawerconst [registerDrawer, { closeDrawer }] = useDrawerInner(async ({ type, data }) => {console.log('打印从table传递的数据:', type, data);currentType.value = type;console.log('currentType', currentType);setFieldsValue(data);if (type == 'view') {showPageFooter.value = false;setProps({ disabled: true });} else {showPageFooter.value = true;}});// 配置Formconst [registerForm, { validate, getFieldsValue, setFieldsValue, setProps }] = useForm({labelWidth: 150,baseColProps: {offset: 1,span: 10,},schemas: schemasView,showActionButtonGroup: false,});function handleVisibleChange(visible: boolean) {if (!visible) {emit('reload');}}async function handleSubmit() {console.log('handleSubmit', currentType);// await validate();const paramsData = await getFieldsValue();console.log('paramsData', paramsData);isLoading.value = true;if (currentType.value === 'add') {await addListDataApi({ ...paramsData }).then((res) => {isLoading.value = false;createMessage.success('保存成功');closeDrawer();});} else {await editListDataApi({ ...paramsData }).then((res) => {isLoading.value = false;createMessage.success('保存成功');closeDrawer();});}}// 取消按钮function handleCancel() {console.log('handleCancel', currentType);emit('back');closeDrawer();}return {currentType,showPageFooter,isLoading,registerDrawer,closeDrawer,registerForm,validate,getFieldsValue,setFieldsValue,setProps,handleVisibleChange,handleSubmit,handleCancel,// registerTable,};},});
script><style scoped>style>
页面效果
vben-admin 使用mock添加增删改接口逻辑及联调
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
