效果图
ArticleChannel.vue页面代码
html
<script setup>
import {artGetChannelsService ,artDelChannelService} from '@/api/article.js'
import { Edit, Delete } from '@element-plus/icons-vue'
//调用open方法,ChannelEdit去修改组件内部类容
import ChannelEdit from '@/views/article/components/ChannelEdit.vue'
import{ref}from 'vue'
const loading=ref(false)
const channelList=ref([])
const getChannelList=async()=>{2
loading.value=true
const res=await artGetChannelsService()
channelList.value=res.data.data
// channelList.value=""
console.log();
loading.value=false
}
//触发dialog
const dialog=ref()
getChannelList()
const onEditChannel=(row)=>{
dialog.value.open(row)
}
const onDelChannel = async (row) => {
await ElMessageBox.confirm('你确认要删除该分类么', '温馨提示', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await artDelChannelService(row.id)
ElMessage.success('删除成功')
getChannelList()
}
//点击触发对话框
const onAddChannel = () => {
dialog.value.open({})
}
//
const onSuccess=()=>{
getChannelList()
}
</script>
<template>
<page-container title='文章分类'>
<template #extra>
<el-button @click="onAddChannel">添加按钮</el-button>
</template>
<!-- 表格部分 label是最上面名称,prop接收数据并遍历 -->
<!-- -加载效果 -->
<el-table :data="channelList" style="width: 100%" v-loading="loading">
<el-table-column label="序号" type="index" width="90" ></el-table-column>
<el-table-column label="分类名称" prop="cate_name"></el-table-column>
<el-table-column label="分类别名" prop="cate_alias" ></el-table-column>
<el-table-column label="操作" width="150">
<!-- 可以在这里添加默认插槽default并且通过这个插槽可以拿到数据
通过 slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据,用法参考 demo
默认插槽中可以自定义类容 -->
<template #default="{row,$index}">
<!-- 按钮是支持图标的 用icon,圆的加上circle -->
<!-- 颜色type -->
<el-button @click="onEditChannel(row, $index)" type="primary" plain :icon="Edit" circle> </el-button>
<el-button @click="onDelChannel(row, $index)" type="danger" plain :icon="Delete" circle> </el-button>
</template>
</el-table-column>
<!-- table是支持#empty插槽,如果没有数据显示的页面 -->
<template #empty>
<el-empty description="没有数据"></el-empty>
</template>
</el-table>
<ChannelEdit ref="dialog" @success1="onSuccess"></ChannelEdit>
</page-container>
</template>
<style lang="scss" scoped></style>
ChannelEdit.vue组件代码
html
<script setup>
import { ref } from 'vue'
import { artEditChannelService, artAddChannelService } from '@/api/article.js'
const dialogVisible = ref(false)
const formRef=ref()
const formModel=ref({
cate_name:'',
cate_alias:''
})
//配置校验规则
const rules={
cate_name:[
{required:true,message:'请输入分类名称',trigger:'blur'},
{pattern:/^\S{1,10}$/,message:'分类名称必须是1-10位非空字符',trigger:'blur'}
],
cate_alias:[
{required:true, message:'请输入分类别名', trigger:'blur'},
{pattern:/^[a-zA-Z0-9]{1,15}$/, message:'分类别名必须是1-15位字母或数字', trigger:'blur'}
]
}
//确认按钮的相关事件
const emit = defineEmits(['success'])//子传父调用
const onSubmit = async () => {
await formRef.value.validate()
const isEdit = formModel.value.id
if (isEdit) {
await artEditChannelService(formModel.value)
ElMessage.success('编辑成功')
} else {
await artAddChannelService(formModel.value)
ElMessage.success('添加成功')
}
dialogVisible.value = false
//遇到子传父,通知页面更新
emit('success1')
}
//要对外暴露,这样其他页面才可以在这里面改类容
// 组件对外暴露一个方法 open,基于open传来的参数,区分添加还是编辑
// open({}) => 表单无需渲染,说明是添加
// open({ id, cate_name, ... }) => 表单需要渲染,说明是编辑
// open调用后,可以打开弹窗
const open=(row)=>{
dialogVisible.value=true;
//用展开运算符...row
formModel.value= { ...row}//添加->重置了表单类容,编辑相当于存储了回显的数据
console.log(formModel.value);
}
//向外暴露组件方法
defineExpose({
open
})
</script>
<template>
<el-dialog
v-model="dialogVisible"
:title="formModel.id?'编辑分类':'添加分类'"
width="30%"
>
<!-- <span>内容部分</span> -->
<el-form ref="formRef" :model="formModel" :rules="rules" label-width="100px" style="padding-right:30px">
<el-form-item label="分类名称" prop="cate_name">
<el-input v-model="formModel.cate_name" placeholder="请输入分类名称"></el-input>
</el-form-item>
<el-form-item label="分类别名" prop="cate_alias">
<el-input v-model="formModel.cate_alias" placeholder="请输入分类别名"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit"
>确认</el-button
>
</span>
</template>
</el-dialog>
</template>
API中article.js代码
html
import request from '@/utils/request.js'
//获取文章分类
export const artGetChannelsService=()=>request.get('/my/cate/list')
//添加文章分类
export const artAddChannelService = (data) => request.post('/my/cate/add', data)
//编辑文章分类
export const artEditChannelService = (data) =>
request.put('/my/cate/info', data)
//删除文章分类
export const artDelChannelService = (id) =>
request.delete('/my/cate/del', {
params: { id }
})
utils里面request代码
html
import axios from 'axios'
import { useUserStore } from '@/stores'
import { ElMessage } from 'element-plus'
import router from '@/router'
const baseURL = 'http://big-event-vue-api-t.itheima.net'
const instance = axios.create({
// TODO 1. 基础地址,超时时间
baseURL,
timeout: 10000
})
// 请求拦截器
instance.interceptors.request.use(
(config) => {
// TODO 2. 携带token
const useStore = useUserStore()
if (useStore.token) {
//往请求头上携带
config.headers.Authorization = useStore.token
}
return config
},
(err) => Promise.reject(err)
)
// 响应拦截器
instance.interceptors.response.use(
(res) => {
// TODO 4. 摘取核心响应数据
if (res.data.code === 0) {
return res
}
// TODO 3. 处理业务失败
// 处理业务失败, 给错误提示,抛出错误
ElMessage.error(res.data.message || '服务异常')
return Promise.reject(res.data)
},
(err) => {
// TODO 5. 处理401错误
// 错误的特殊情况 => 401 权限不足 或 token 过期 => 拦截到登录
if (err.response?.status === 401) {
router.push('/login')
}
// 错误的默认情况 => 只要给提示
ElMessage.error(err.response.data.message || '服务异常')
return Promise.reject(err)
}
)
export default instance
export { baseURL }
所需包