我不想开发电子书,想结合教程开发三个基本功能:1.上传图片展示库,2.发布文章,3.文章管理/人员管理表格,可实现编辑和修改功能。
教程中的内容都是解析电子书,发布电子书,看的磕磕绊绊,照猫画虎,对应着源码适当改来改去。
其实这个板块都在作者花裤衩原始的原始文稿中都有模拟数据,但没研究明白,现在的问题是:
在开发功能1时,数据始终无法解析到那片表单中,我觉得问题可能出在parse,毕竟电子书一堆东西要解析,图片解析什么?自动写进表单中的也就路径和上传的图名这类元素。
但是我确实想解决这个问题,请给予指点。
前端:
router/index:
{
path: '/art',
component: Layout,
redirect: '/art/create',
name: 'art',
meta: {
title: '图库管理',
icon: 'documentation',
roles: ['admin', 'editor']
},
children: [
{
path: 'create',
component: () => import('@/views/art/create'),
name: 'artCreate',
meta: {
title: '上传图片',
icon: 'edit',
roles: ['admin'],
noCache: true
}
},
{
path: 'edit',
component: () => import('@/views/art/edit'),
name: 'artEdit',
hidden: true,
meta: {
title: '作品编辑',
icon: 'list',
roles: ['admin', 'editor'],
noCache: true,
activeMenu: '/art/list'
}
},
{
path: 'list-art',
component: () => import('@/views/art/list'),
name: 'artList',
meta: {
title: '作品列表',
icon: 'list',
roles: ['admin', 'editor'],
activeMenu: '/art/list'
}
},
{
path: 'list',
component: () => import('@/views/art/edit'),
name: 'artistList',
meta: {
title: '人物列表',
icon: 'list',
roles: ['admin', 'editor'],
activeMenu: '/art/list'
}
}
]
},
Detail:
<template>
<el-form ref="postForm" :model="postForm" :rules="rules">
<sticky :class-name="'sub-navbar'">
<el-button v-if="!isEdit" @click="showGuide">显示帮助</el-button>
<el-button v-loading="loading" type="success" style="margin-left: 10px" @click="submitForm">
{{ isEdit ? '编辑图库' : '添加作品' }}
</el-button>
</sticky>
<div class="detail-container">
<el-row>
<warning />
<el-col :span="24">
<!-- 上传控件的具体样式 -->
<art-upload
:file-list="fileList"
:disabled="isEdit"
@onSucess="onUploadSucess"
@onRemove="onUploadRemove"
/>
</el-col>
<el-col :span="24">
<el-form-item prop="title">
<MdInput v-model="postForm.title" :maxlength="100" name="name" required>
图片名
</MdInput>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item prop="author" label="作者:" :label-width="labelWidth">
<el-input
v-model="postForm.author"
placeholder="作者"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="country" label="国家地区:" :label-width="labelWidth">
<el-input
v-model="postForm.country"
placeholder="国家地区"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item prop="category" label="类别:" :label-width="labelWidth">
<el-input
v-model="postForm.category"
placeholder="类别"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="createDate" label="创作时间:" :label-width="labelWidth">
<el-input
v-model="postForm.createDate"
placeholder="创作时间"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="文件大小:" :label-width="labelWidth">
<el-input
v-model="postForm.fileSize"
placeholder="文件大小"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="文件路径:" :label-width="labelWidth">
<el-input
v-model="postForm.filePath"
placeholder="文件路径"
disabled
/>
</el-form-item>
</el-col>
</el-row>
<略>
<script>
import Sticky from '../../../components/Sticky'
import Warning from './Warning'
import ArtUpload from '../../../components/ArtUpload'
import MdInput from '../../../components/MDinput/index'
import { createArt } from '../../../api/art'
const defaultForm = {
title: '',
filename: '',
filePath: '',
fileSize: ''
}
const fields = {
title: '图片名',
author: '作者',
country: '国家地区',
category: '类别',
createDate: '创作时间'
}
export default {
components: { MdInput, Sticky, Warning, ArtUpload },
props: {
isEdit: {
type: Boolean
}
},
data() {
const validateRequire = (rule, value, callback) => {
if (value === '') {
this.$message({
message: rule.field + '为必传项',
type: 'error'
})
callback(new Error(rule.field + '为必传项'))
} else {
callback()
}
}
return {
postForm: Object.assign({}, defaultForm),
loading: false,
// postForm: {},
fileList: [],
labelWidth: '120px',
rules: {
title: [{ validator: validateRequire }],
image_uri: [{ validator: validateRequire }],
author: [{ validator: validateRequire }],
country: [{ validator: validateRequire }],
category: [{ validator: validateRequire }],
createDate: [{ validator: validateRequire }]
}
}
},
methods: {
setData(data) {
const {
title,
filename,
filePath,
fileSize
} = data
this.postForm = {
...this.postForm,
title,
filename,
filePath,
fileSize
}
},
onUploadSucess(data) {
console.log('onUploadSucess', data)
this.setData(data)
},
setDefault() {
this.postForm = Object.assign({}, defaultForm)
},
onUploadRemove() {
this.setDefault()
},
submitForm() {
// if (!this.loading) {
this.loading = true
this.$refs.postForm.validate((valid, fields) => {
console.log(valid, fields)
if (valid) {
const art = Object.assign({}, this.postForm)
delete art.unzipPath
delete art.unzipUrl
if (!this.isEdit) {
createArt(art).then(response => {
const { msg } = response
this.$notify({
title: '操作成功',
message: msg,
type: 'success',
duration: 2000
})
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
// updateArt(art)
}
} else {
const message = fields[Object.keys(fields)[0]][0].message
this.$message({ message, type: 'error' })
this.loading = false
}
})
// }
后端:
models/
class Art {
constructor(file, data) {
if (file) {
this.createArtFromFile(file)
} else {
this.createArtFromData(data)
}
}
createArtFromFile(file) {
console.log('createArtFromFile', file)
const {
destination,
filename,
mimetype = MIME_TYPE_ART,
path,
originalname,
size
} = file
// 图片的文件后缀名
const suffix = mimetype === MIME_TYPE_ART ? '.jpg' : ''
// 图片的原有路径
const oldArtPath = path
// 图片的新路径
const artPath = `${destination}/${filename}${suffix}`
// 图片的下载URL
const url = `${UPLOAD_URL}/art/${filename}${suffix}`
// 图片解压后的文件夹路径
const unzipPath = `${UPLOAD_PATH}/unzip/${filename}`
// 图片解压后的文件夹URL
const unzipUrl = `${UPLOAD_URL}/unzip/${filename}`
if (!fs.existsSync(unzipPath)) {
fs.mkdirSync(unzipPath, { recursive: true })
}
if (fs.existsSync(oldArtPath) && !fs.existsSync(artPath)) {
fs.renameSync(oldArtPath, artPath)
}
this.title = originalname //图片名
this.fileName = filename //文件名
this.path = `/art/${filename}${suffix}` // 图片文件相对路径
this.filePath = this.path
this.unzipPath = `/art/${filename}` // 图片解压后相对路径
this.url = url
this.fileSize = size //文件大小
this.unzipUrl = unzipUrl //解压后文件夹链接
this.originalname = originalname //图片文件的原名
}
createArtFromData(data) {
this.title = data.originalname
this.author = data.author
this.country = data.country
this.category = data.category
this.createDate = data.createDate
this.fileName = data.filename
this.filePath = data.filePath
this.fileSize = data.size
this.url = data.url
}
parse() {
return new Promise((resolve, reject) => {
const artPath = `${UPLOAD_PATH}${this.filePath}`
if (!fs.existsSync(artPath)) {
reject(new Error('图片不存在'))
}
const image = new Image(artPath)
//解析失败
image.on('err', err => {
reject(err)
})
// 解析成功
image.on('end', err => {
if (err) {
reject(err)
} else {
// console.log(image.metadata)// 获取一些信息,比如metadata
const {
title,
mimetype,
filePath,
url
} = image.metadata
if (!title) {
reject(new Error('图片名为空'))
} else {
this.title = filename
this.fileName = originalname
this.mimeType = mimetype
this.url = url
this.filePath = filePath
this.rootFile = image.rootFile
const handleGetImage = function(err, file, mimeType) {
if (error) {
reject(error)
} else {
resolve(this)// 解析结束
}
}
image.getImage(preview, handleGetImage)
}
}
})
image.parse()//来进行解析的过程
this.image = image
})
}
toJson() {
return {
title: this.title,
author: this.author,
country: this.country,
category: this.category,
createDate: this.createDate,
fileName: this.fileName,
filePath: this.filePath,
fileSize: this.fileSize,
url: this.url,
path: this.path
}
}
toDb() {
return {
title: this.originalname,
author: this.author,
country: this.country,
category: this.category,
createDate: this.createDate,
fileName: this.filename,
filePath: this.filePath,
fileSize: this.size
}
}
static genPath(path) {
if (path.startsWith('/')) {
return `${UPLOAD_PATH}${path}`
} else {
return `${UPLOAD_PATH}/${path}`
}
}
static pathExists(path) {
if (path.startsWith(UPLOAD_PATH)) {
return fs.existsSync(path)
} else {
return fs.existsSync(Book.genPath(path))
}
}
router:
const express = require('express')
const multer = require('multer')
const { UPLOAD_PATH } = require('../utils/constant')
const Result = require('../models/Result')
const Art = require('../models/Art')
const boom = require('boom')
const { decoded } = require('../utils')
const artService = require('../services/art')
const router = express.Router()
router.post(
'/upload',
multer({ dest: `${UPLOAD_PATH}/art` }).single('file'),
function(req, res) {
if (!req.file || req.file.length === 0) {
new Result('上传文件失败').fail(res)
} else {
const art = new Art(req.file)
console.log(art)
new Result(art, '上传文件成功').success(res)
}
}
)
router.post(
'/upload',
multer({ dest: `${UPLOAD_PATH}/art` }).single('file'),
function(req, res, next) {
if (!req.file || req.file.length === 0) {
new Result('上传文件失败').fail(res)
} else {
const art = new Art(req.file)
art.parse()
.then(art => {
// console.log('art', art)
new Result(art, '上传文件成功').success(res)
})
.catch(err => {
next(boom.badImplementation(err))
})
}
}
)
router.post(
'/create',
function(req, res, next) {
const decode = decoded(req)
console.log(req.body)
if (decode && decode.username) {
req.body.username = decode.username
}
const art = new Art(null, req.body)
console.log(art)
artService.insertArt(art).then(() => {
}).catch(err => {
next(boom.badImplementation(err))
})
}
)
module.exports = router
反馈:
现在目标是:怎么将图片标题和路径自动挂进表单中?需要修改哪里?
基于Element的中后台课程,一套中小型企业通用的后台管理系统
了解课程