<template>
<el-form label-width="90px">
<el-form-item label="类别">
<el-cascader v-model="category" :props="category_props" :options="categoryData.category_options" filterable
clearable style="width:100%" />
</el-form-item>
<el-form-item label="信息标题">
<el-input v-model="form.title" />
</el-form-item>
<el-form-item label="缩略图">
<el-upload ref="uploadRef" class="avatar-uploader" action="#" :limit="1" :multiple="false"
:auto-upload="false" :show-file-list="false" :on-change="handleChange">
<img v-if="form.image_url" :src="form.image_url" class="avatar" />
<el-icon v-else class="avatar-uploader-icon">
<Plus />
</el-icon>
</el-upload>
</el-form-item>
<el-form-item label="内容">
<div style="border:1px solid #ccc;width:180%;">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig"
:mode="mode" />
<Editor style="height: 300px; overflow-y: hidden;" v-model="valueHtml" :defaultConfig="editorConfig"
:mode="mode" @onCreated="handleEditorCreated" @onChange="handleEditorChange" />
</div>
</el-form-item>
<el-form-item>
<el-button type="danger" @click="handleSubmit">确定</el-button>
<el-button type="primary">返回</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, toRefs } from 'vue'
import { onBeforeUnmount, ref, shallowRef, onBeforeMount } from 'vue'
import '@wangeditor/editor/dist/css/style.css'//入css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { useCategoryHook } from '@/hooks/categoryHook'
import useStore from '@/store'
const store = useStore()
const uploadRef = ref(null)
const { categoryData, getAllCategory } = useCategoryHook()
const data = reactive({
category: 0,
category_props: {
label: 'name',
value: 'id'
},
file: null,
form: {
category_id: [],
title: '',
image_url: '',
content: ''
},
})
const { category_props, form } = toRefs(data)
onBeforeMount(() => {
getAllCategory()
})
const checkUploadFile = (rawFile) => {
console.log('file.size', rawFile.size)
if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error('上传的文件大小不能超过2MB!')
return false
}
return true
}
const handleChange = (file) => {
if (!checkUploadFile(file)) return
data.file = file.raw
form.value.image_url = URL.createObjectURL(file.raw)
uploadRef.value.clearFiles()
}
const mode = 'default'
const editorRef = shallowRef()
//内容HTML
const valueHtml = ref('')
const toolbarConfig = {}
toolbarConfig.excludeKeys = ['group-video', 'insertTable', 'fullScreen']
const editorConfig = { placeholder: '请输入内容...' }
//组件销毁时,也即是销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleEditorCreated = (editor) => {
editorRef.value = editor//记录 editor 实例,重要!
}
const handleEditorChange = (editor) => {
form.value.content = editor.getHtml()
}
const handleSubmit = async () => {
const { category_id, title, content } = form.value
const fd = new FormData()
fd.append('category_id', category_id[category_id.length - 1])
fd.append('title', title)
fd.append('content', content)
fd.append('file', data.file)
console.log('fd', fd);
const res = await store.info.createInfoAction(fd)
console.log('res', res)
}
</script>
<style scoped>
.avatar {
width: 178px;
height: 178px;
object-fit: cover;
display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
display: inline-block;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
.w-e-text img {
max-width: 100%;
height: auto;
}
</style>
<template>
<div class="form-button-group margin-bottom-20">
<router-link :to="{ name: 'InfoDetail' }">
<el-button type="danger">新增</el-button>
</router-link>
</div>
<el-form :inline="true" ref="searchFormRef">
<el-form-item label="类别" class="type">
<el-cascader v-model="category" :props="category_props" :options="categoryData.category_options" filterable
clearable style="width:100%" />
</el-form-item>
<!-- <el-form-item label="关键词" prop="key">
<el-select class="select" v-model="keywords.key" placeholder="请选择">
<el-option v-for="item in keywords.options" :key="item.value" :value="item.value"
:label="item.label"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="value">
<el-input placeholder="请输入关键词" v-model="keywords.value" clearable />
</el-form-item> -->
<el-form-item>
<el-button type="danger" @click="handleSearch">搜索</el-button>
<el-button type="default" @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-table ref="table" :data="infoList" border style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="60" />
<el-table-column label="标题" width="200" prop="title" />
<el-table-column label="类别" width="100" prop="category.name" />
<el-table-column label="创建日期" width="200" prop="created_time" />
<el-table-column label="发布状态" width="120">
<template #default="scope">
<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0" :loading="scope.row.loading"
@change="handleChangStatus($event, scope.row)" />
</template>
</el-table-column>
<el-table-column label="发布日期" width="200" prop="release_time" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row.id)">
编辑
</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-row class="margin-top-20">
<el-col :span="6">
<el-button type="danger">批量删除</el-button>
</el-col>
<el-col :span="18">
<el-pagination class="pull-right" v-model:current-page="request_data.pageIndex"
v-model:page-size="request_data.pageSize" :page-sizes="[10, 20, 30, 50]" background small
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
@current-change="handleCurrentChange" />
</el-col>
</el-row>
</template>
<script setup>
import { ref, reactive, toRefs, onBeforeMount } from 'vue'
import { useRouter } from 'vue-router'
import useStore from '@/store'
import { useCategoryHook } from '@/hooks/categoryHook'
import { ElMessage } from 'element-plus'
const store = useStore()
const router = useRouter()
const { categoryData, getAllCategory } = useCategoryHook()
const data = reactive({
category: 0,
category_props: {
label: 'name',
value: 'id'
},
infoList: [],
total: 0,
request_data: { pageIndex: 1, pageSize: 10 }
})
const { category, category_props, infoList, total, request_data } = toRefs(data)
const getInfoList = async () => {
try {
const res = await store.info.getInfoListAction({
pageIndex: request_data.value.pageIndex,
pageSize: request_data.value.pageSize,
category_id: category.value || undefined
})
data.infoList = res.data.rows
data.total = res.data.count
} catch (error) {
console.error('获取列表失败', error)
}
}
const handleSizeChange = (val) => {
console.log(`${val} items per page`);
request_data.value.pageSize = val
};
const handleCurrentChange = (val) => {
console.log(`current page: ${val}`);
request_data.value.pageIndex = val
};
const handleEdit = (id) => {
console.log('handle id', id);
router.push({
name: 'InfoDetail'
})
}
onBeforeMount(() => {
getInfoList(),
getAllCategory()
})
</script>
<style lang="scss" scoped>
.type {
width: 200px;
}
</style>
import { defineStore } from "pinia";
import {
GetInfoList,
// ChangeInfoStatus,
GetAllCategory,
UploadFile,
CreateInfo,
// UpdateInfo,
// DeleteInfo,
} from "@/api/info";
export const useInfoStore = defineStore("info", () => {
function getInfoListAction(requestData) {
return new Promise((resolve, reject) => {
GetInfoList(requestData).then(resolve).catch(reject);
});
}
// function changeInfoStatusAction(requestData) {
// const { id, data } = requestData;
// return new Promise((resolve, reject) => {
// ChangeInfoStatus(id, data).then(resolve).catch(reject);
// });
// }
function getAllCategoryAction() {
return new Promise((resolve, reject) => {
GetAllCategory().then(resolve).catch(reject);
});
}
function uploadFileAction(requestData = {}) {
return new Promise((resolve, reject) => {
UploadFile(requestData)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(error);
});
});
}
function createInfoAction(requestData = {}) {
return new Promise((resolve, reject) => {
CreateInfo(requestData)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(error);
});
});
}
// function updateInfoAction({ id, data }) {
// return new Promise((resolve, reject) => {
// UpdateInfo(id, data).then(resolve).catch(reject);
// });
// }
// function deleteInfoAction({ id, data }) {
// return new Promise((resolve, reject) => {
// DeleteInfo(id, data).then(resolve).catch(reject);
// });
// }
return {
getInfoListAction,
// changeInfoStatusAction,
getAllCategoryAction,
uploadFileAction,
createInfoAction,
// updateInfoAction,
// deleteInfoAction,
};
});
import installer from "@/utils/request";
export function GetInfoList(params = {}) {
return installer.request({
url: "/infos",
method: "GET",
params,
});
}
// export function ChangeInfoStatus(id, data = {}) {
// return installer.request({
// url: `/infos/${id}/status`,
// method: "PUT",
// data,
// });
// }
export function GetAllCategory(params) {
return installer.request({
url: "/categories",
method: "GET",
params,
});
}
export function UploadFile(data = {}) {
return instance.request({
url: "/uplosd",
method: "POST",
data,
});
}
export function CreateInfo(data = {}) {
return installer.request({
url: "/infos",
headers: { "Content-Type": "multipart/form-data" },
method: "POST",
data,
});
}
// export function UpdateInfo(id, data = {}) {
// return installer.request({ url: `/infos/${id}`, method: "PUT", data });
// }
// export function DeleteInfo(id, data = {}) {
// return installer.request({ url: `/infos/${id}`, method: "DELETE", data });
// }
import { reactive } from "vue";
import useStore from "@/store";
export function useCategoryHook() {
const store = useStore();
const categoryData = reactive({
category_options: [],
});
const getAllCategory = async () => {
const res = await store.info.getAllCategoryAction();
categoryData.category_options = res.data;
};
return { categoryData, getAllCategory };
}
:8888/#/info-detail:1 Uncaught (in promise)
{code: 1, msg: 'id为undefined的类别不存在呀!', data: null}
code
:
1
data
:
null
msg
:
"id为undefined的类别不存在呀!"
[[Prototype]]
:
Object
constructor
:
ƒ Object()
hasOwnProperty
:
ƒ hasOwnProperty()
isPrototypeOf
:
ƒ isPrototypeOf()
propertyIsEnumerable
:
ƒ propertyIsEnumerable()
toLocaleString
:
ƒ toLocaleString()
toString
:
ƒ toString()
valueOf
:
ƒ valueOf()
__defineGetter__
:
ƒ __defineGetter__()
__defineSetter__
:
ƒ __defineSetter__()
__lookupGetter__
:
ƒ __lookupGetter__()
__lookupSetter__
:
ƒ __lookupSetter__()
__proto__
:
(…)
get __proto__
:
ƒ __proto__()
set __proto__
:
ƒ __proto__()
最新发布