修改文章编辑

增加审批流
This commit is contained in:
jacky 2024-04-16 22:41:13 +08:00
parent eaa9caa47c
commit 41e5d73c9b
9 changed files with 745 additions and 509 deletions

View File

@ -222,7 +222,7 @@ module.exports = {
} }
], ],
'space-before-blocks': [2, 'always'], 'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'], 'space-before-function-paren': [2, 'always'],
'space-in-parens': [2, 'never'], 'space-in-parens': [2, 'never'],
'space-infix-ops': 2, 'space-infix-ops': 2,
'space-unary-ops': [ 'space-unary-ops': [

View File

@ -35,6 +35,18 @@ export const deleteArticle = (data) => {
}) })
} }
// @Summary 批量删除文章
// @Param data body request.IdsReq true "批量删除文章"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /product/deleteProduct [delete]
export const deleteArticleByIds = (params) => {
return service({
url: '/cms/article/deleteByIds',
method: 'delete',
params
})
}
// @Summary 修改文章 // @Summary 修改文章
// @Produce application/json // @Produce application/json
// @Param menu Object // @Param menu Object
@ -47,7 +59,7 @@ export const updateArticle = (data) => {
}) })
} }
// @Tags 文章文章 // @Tags 文章
// @Summary 根据id获取文章 // @Summary 根据id获取文章
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @accept application/json // @accept application/json
@ -63,14 +75,50 @@ export const getArticleById = (params) => {
}) })
} }
// @Summary 发布文章 // @Summary 文章提审
// @Produce application/json
// @Param menu Object
// @Router /cms/article/submit [put]
export const submitArticle = (data) => {
return service({
url: '/cms/article/submit',
method: 'put',
data
})
}
// @Summary 文章审核
// @Produce application/json
// @Param menu Object
// @Router /cms/article/review [put]
export const reviewArticle = (data) => {
return service({
url: '/cms/article/review',
method: 'put',
data
})
}
// @Summary 文章发布
// @Produce application/json // @Produce application/json
// @Param menu Object // @Param menu Object
// @Router /cms/article/release [put] // @Router /cms/article/release [put]
export const releaseArticle = (data) => { export const releaseArticle = (data) => {
return service({ return service({
url: '/cms/article/release', url: '/cms/article/release',
method: 'post', method: 'put',
data
})
}
// @Summary 文章撤销
// @Produce application/json
// @Param menu Object
// @Router /cms/article/cancel [put]
export const cancelArticle = (data) => {
return service({
url: '/cms/article/cancel',
method: 'put',
data data
}) })
} }

12
src/api/tag.js Normal file
View File

@ -0,0 +1,12 @@
import service from '@/utils/request'
// @Summary 获取列表数据
// @Produce application/json
// @Router /cms/tag/getList [post]
export const getTagList = (data) => {
return service({
url: '/cms/tag/getList',
method: 'post',
data
})
}

View File

@ -72,8 +72,6 @@ const emit = defineEmits(['on-select', 'on-before-upload', 'on-upload-success',
const props = defineProps({ const props = defineProps({
category: { type: String, required: true }, category: { type: String, required: true },
size: { type: String, default: '800px' }, size: { type: String, default: '800px' },
target: { type: Object, default: null },
targetKey: { type: String, default: '' },
}) })
const drawer = ref(false) const drawer = ref(false)

View File

@ -22,6 +22,9 @@ const emit = defineEmits([
'on-success', 'on-success',
]) ])
const props = defineProps({ const props = defineProps({
category: {
type: String, required: true
},
imageUrl: { imageUrl: {
type: String, type: String,
default: '' default: ''

View File

@ -1,417 +0,0 @@
<template>
<div v-loading="fullscreenLoading">
<div class="gva-form-box">
<div v-if="showErrMessage != ''">
{{ showErrMessage }}
</div>
<el-form v-else ref="elEditFormRef" label-position="top" :model="editForm" :rules="formRules">
<el-row :gutter="10">
<el-col :span="17">
<el-row :gutter="10">
<el-col :span="16">
<el-form-item label="标题" prop="title">
<el-input v-model="editForm.title" autocomplete="off" :show-word-limit="true" maxlength="50" />
</el-form-item>
<el-form-item label="副标题" prop="subtitle">
<el-input v-model="editForm.subtitle" autocomplete="off" :show-word-limit="true" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="文章类型" prop="articleType">
<el-select v-model="editForm.articleType" placeholder="请选择">
<el-option v-for="item in articleTypeOptions" :key="item.key" :label="item.label"
:value="item.key" />
</el-select>
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input v-model="editForm.author" autocomplete="off" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="所属栏目" prop="channels">
<el-cascader v-model="channelIdList" :options="channelOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
:collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="3" filterable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="文章分类" prop="categories">
<el-cascader v-model="categoryIdList" :options="categoryOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
:collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="2" filterable />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="文章内容" prop="content">
<RichEdit v-model="editForm.content" style="height: 50rem;" />
</el-form-item>
</el-col>
<el-col :span="1" align="center">
<el-divider direction="vertical" style="height: 100%" />
</el-col>
<el-col :span="6">
<el-form-item label="摘要" prop="desc">
<el-input v-model="editForm.desc" type="textarea" rows="7" :show-word-limit="true" maxlength="100"
autocomplete="off" resize="none" />
</el-form-item>
<el-form-item label="来源" prop="source">
<el-select v-model="editForm.source" placeholder="请选择" allow-create clearable filterable>
<el-option v-for="item in sourceOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="跳转链接" prop="source">
<el-input v-model="editForm.url" autocomplete="off" placeholder="https://" clearable />
</el-form-item>
<el-form-item label="发布时间">
<el-date-picker v-model="editForm.publishDate" type="datetime" placeholder="请选择" style="width:100%" />
</el-form-item>
<el-form-item label="文章标签" prop="tags">
<div class="flex flex-wrap gap-2">
<el-tag v-for="(item, index) in tagList" :key="index" type="info" closable size="large"
@close="tagList.splice(index, 1)">
{{ item }}
</el-tag>
<el-input v-if="tagInputFlag" ref="InputRef" v-model="inputTag" class="w-20" size="default"
style="width: 80px;" @keyup.enter="handleTagOK" @keyup.esc="handleTagCancel" @blur="handleTagOK" />
<el-button v-else type="primary" plain icon="plus" class="button-new-tag" size="default"
style="width: 80px;" @click="handleTagAdd">
添加
</el-button>
</div>
</el-form-item>
<el-form-item label="图片(首张图可用来做栏目列表用)" prop="imgs">
<ChooseImg ref="chooseImg" category="article_imgs" size="800px" @on-select="handleSelectImg" />
<template #label>
<div style="margin-bottom: 10px;">图片首张图可用来做栏目列表用</div>
<div class="flex gap-3">
<el-button type="success" plain icon="folder" @click="handleChooseImg">媒体库</el-button>
<upload-common class="upload-btn-media-library" category="article_imgs"
@on-success="handleImgUpload" />
<el-tooltip effect="dark" content="图片超过 512K 或者 长宽 > 1080 会自动压缩后再上传" placement="top-start">
<upload-image :file-size="512" :max-w-h="1080" category="article_imgs"
@on-success="handleImgUpload" />
</el-tooltip>
</div>
</template>
<div class="media">
<div v-for="(item, key) in imgFileList" :key="key" class="media-box">
<div class="img-box-list">
<el-image :key="key" :src="getUrl(item.url)" fit="cover" :preview-src-list="[getUrl(item.url)]"
hide-on-click-modal style="width: 138px; height: 138px;">
<template #error>
<div class="img-box-list">
<el-icon>
<picture />
</el-icon>
</div>
</template>
</el-image>
</div>
<div class="img-title">
<el-button size="small" type="default" icon="delete" @click="handleImgRemove(item)">删除</el-button>
</div>
</div>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item>
<el-button type="primary" icon="check" style="width: 150px;" @click="handleFormSubmit">保存</el-button>
<el-button type="default" icon="close" @click="handleFormClose">关闭</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</template>
<script setup>
import { getUrl } from '@/utils/image'
import { reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import RichEdit from '@/components/richtext/rich-edit.vue'
import ChooseImg from '@/components/chooseImg/index.vue'
import { getSourceList } from '@/api/source'
import { getCategoryTree } from '@/api/category'
import { getChannelTree } from '@/api/channel'
import UploadCommon from '@/components/upload/common.vue'
import UploadImage from '@/components/upload/image.vue'
import {
addArticle,
updateArticle,
getArticleById,
} from '@/api/article'
import { getFetcherArticleById } from '@/api/fetcher'
const showErrMessage = ref('')
const fullscreenLoading = ref(true)
const route = useRoute()
const router = useRouter()
const isEdit = ref(false) // isEdit = true
const elEditFormRef = ref()
const formRules = reactive({
articleType: [
{ required: true, message: '请输选择文章类型', trigger: 'blur' }
],
author: [
{ required: true, message: '请输入作者', trigger: 'blur' }
],
title: [
{ required: true, message: '请输入文章名称', trigger: 'blur' }
],
subtitle: [
{ required: true, message: '请输入文章副标题', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入文章内容', trigger: 'blur' }
],
})
const articleTypeOptions = ref([
{ key: 1, label: '图文' },
{ key: 2, label: '视频' },
])
const editForm = ref({
ID: 0,
articleType: '',
title: '',
subtitle: '',
author: '',
channels: [],
categories: [],
desc: '',
source: '',
url: '',
publishDate: '',
articleTime: '',
tags: '',
imgs: '',
})
// options
const initOptions = (data, optionsData) => {
data &&
data.forEach(item => {
if (item.children && item.children.length) {
const option = {
title: item.title,
ID: String(item.ID),
children: []
}
initOptions(
item.children,
option.children,
)
optionsData.push(option)
} else {
const option = {
title: item.title,
ID: String(item.ID),
}
optionsData.push(option)
}
})
}
// options 使
const channelOptions = ref([])
const categoryOptions = ref([])
const sourceOptions = ref([])
const getCategoryData = async () => {
categoryOptions.value = []
const res = await getCategoryTree()
if (res.code === 0) {
initOptions(res.data.categoryTree, categoryOptions.value, false)
}
}
const getChannelData = async () => {
channelOptions.value = []
const res = await getChannelTree()
if (res.code === 0) {
initOptions(res.data.channelTree, channelOptions.value, false)
}
}
const getSourceData = async () => {
sourceOptions.value = []
const res = await getSourceList({ page: 1, pageSize: 999 })
if (res.code === 0) {
sourceOptions.value = res.data.list && res.data.list.map(item => item.name)
}
}
//
const initPage = async () => {
getCategoryData()
getChannelData()
getSourceData()
// urlID find createupdate idurl
if (route.query && route.query.id && route.query.id > 0) {
const res = await getArticleById({ ID: route.query.id })
if (res.code === 0) {
//
editForm.value = res.data.article
isEdit.value = true
//
const { categories, channels, imgs, tags } = res.data.article
categoryIdList.value = categories && categories.map(item => String(item.ID))
channelIdList.value = channels && channels.map(item => String(item.ID))
if (imgs && (imgs !== '')) {
imgFileList.value = JSON.parse(imgs)
}
tagList.value = tags && tags.split(',')
fullscreenLoading.value = false
} else {
ElMessage({
type: 'error',
message: '获取数据失败'
})
showErrMessage.value = '获取数据失败'
}
} else if (route.query && route.query.fetcherId && route.query.fetcherId > 0) {
//
const res = await getFetcherArticleById({ ID: route.query.fetcherId })
if (res.code === 0 && res.data && res.data.article) {
console.log(res.data)
const { title, author, source, content, publicTime } = res.data.article
editForm.value.title = title
editForm.value.subtitle = title
editForm.value.author = author
editForm.value.source = source
editForm.value.content = content
editForm.value.publishDate = publicTime
editForm.value.articleTime = publicTime
} else {
ElMessage({
type: 'error',
message: '获取数据失败'
})
showErrMessage.value = '获取数据失败'
}
}
fullscreenLoading.value = false
}
initPage()
// ---- ----
const chooseImg = ref(null)
const imgFileList = ref([])
const handleChooseImg = (event) => {
chooseImg.value.open()
event.preventDefault()
return false
}
const handleSelectImg = (file) => {
imgFileList.value.push({
key: file.key,
name: file.name,
url: file.url,
})
}
const handleImgRemove = (file) => {
imgFileList.value = imgFileList.value.filter(item => item.key !== file.key)
}
const handleImgUpload = (file) => {
imgFileList.value.push({
key: file.key,
name: file.name,
url: file.url,
})
}
// ---- tag ----
const tagInputFlag = ref(false)
const inputTag = ref('')
const tagList = ref([])
const handleTagOK = (key) => {
const val = inputTag.value.trim()
if (val !== '' && !tagList.value.includes(val)) {
tagList.value.push(val)
tagInputFlag.value = false
inputTag.value = ''
}
}
const handleTagCancel = (key) => {
if (key.keyCode === 27) {
// esc
tagInputFlag.value = false
inputTag.value = ''
}
}
const handleTagAdd = () => {
tagInputFlag.value = true
}
const categoryIdList = ref([])
const channelIdList = ref([])
// /
const handleFormSubmit = async () => {
const rel = {}
rel.categoryIds = categoryIdList.value.map(item => parseInt(item, 10))
rel.channelIds = channelIdList.value.map(item => parseInt(item, 10))
rel.imgList = imgFileList.value
rel.tagList = tagList.value
if (editForm.value.publishDate === '') {
editForm.value.publishDate = null
}
if (editForm.value.articleTime === '') {
editForm.value.articleTime = null
}
elEditFormRef.value.validate(async valid => {
if (valid) {
let res
if (isEdit.value) {
res = await updateArticle({ article: editForm.value, rel: rel })
} else {
res = await addArticle({ article: editForm.value, rel: rel })
}
if (res.code === 0) {
ElMessage({
type: 'success',
message: isEdit.value ? '修改成功' : '添加成功!'
})
if (!isEdit.value && res.data && res.data.article) {
const query = { id: res.data.article.ID }
router.replace({ name: 'articleEdit', query })
}
}
}
})
}
//
const handleFormClose = () => {
router.go(-1)
}
</script>
<style type="scss">
.admin-box .el-table td .cell {
line-height: 28px;
}
.text-truncate .cell {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}
.img-item {
width: 90px;
height: 90px;
}
</style>

View File

@ -1,36 +1,23 @@
<template> <template>
<div> <div>
<div class="gva-search-box"> <div class="gva-search-box">
<el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" label-width="90px" class="demo-form-inline" <el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" label-width="0" class="demo-form-inline"
@keyup.enter="handleSubmitSearch"> @keyup.enter="handleSubmitSearch">
<el-form-item label="创建日期" prop="createdAt" style="width:300px"> <el-form-item prop="createdAt" style="width:260px">
<template #label>
<span>
<el-tooltip content="搜索范围是创建开始日期(包含)至创建结束日期(包含)" placement="top-start"> <el-tooltip content="搜索范围是创建开始日期(包含)至创建结束日期(包含)" placement="top-start">
<el-icon> <el-icon>
<QuestionFilled /> <QuestionFilled />
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
创建日期
</span>
</template>
<el-date-picker v-model="searchInfo.dateRange" type="daterange" value-format="YYYY-MM-DD" :clearable="false" <el-date-picker v-model="searchInfo.dateRange" type="daterange" value-format="YYYY-MM-DD" :clearable="false"
:editable="false" /> :editable="false" />
</el-form-item> </el-form-item>
<el-form-item label="关键词" style="width:300px"> <el-form-item style="width:200px">
<template #label>
<span>
<el-tooltip content="从标题、副标题、摘要中搜索" placement="top-start"> <el-tooltip content="从标题、副标题、摘要中搜索" placement="top-start">
<el-icon> <el-input v-model="searchInfo.keyword" class="keyword" placeholder="请输入关键词" clearable style="width:100%" />
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
关键词
</span>
</template>
<el-input v-model="searchInfo.keyword" class="keyword" placeholder="请输入" clearable style="width:100%" />
</el-form-item> </el-form-item>
<el-form-item label="所属栏目" prop="channelId" style="width:300px"> <!-- <el-form-item label="所属栏目" prop="channelId" style="width:300px">
<el-cascader v-model="searchChannelId" :options="channelOptions" style="width:100%" <el-cascader v-model="searchChannelId" :options="channelOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true" :props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true"
clearable placeholder="请选择" filterable /> clearable placeholder="请选择" filterable />
@ -39,9 +26,9 @@
<el-cascader v-model="searchCategoryId" :options="categoryOptions" style="width:100%" <el-cascader v-model="searchCategoryId" :options="categoryOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true" :props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true"
clearable placeholder="请选择" filterable /> clearable placeholder="请选择" filterable />
</el-form-item> </el-form-item> -->
<el-form-item label="发布状态" prop="status" style="width:300px"> <el-form-item label="" prop="status" style="width:200px">
<el-select v-model="searchInfo.status" placeholder="请选择" clearable style="width:300px"> <el-select v-model="searchInfo.status" placeholder="请选择状态" clearable style="width:300px">
<el-option v-for="item in statusOptions" :key="item.key" :label="item.label" :value="item.key" /> <el-option v-for="item in statusOptions" :key="item.key" :label="item.label" :value="item.key" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -56,8 +43,6 @@
<el-button type="primary" icon="plus" @click="handleAdd('0')">新增文章</el-button> <el-button type="primary" icon="plus" @click="handleAdd('0')">新增文章</el-button>
<el-button icon="delete" style="margin-left: 10px;" :disabled="!multipleSelection.length" <el-button icon="delete" style="margin-left: 10px;" :disabled="!multipleSelection.length"
@click="handleMultiDelete">删除</el-button> @click="handleMultiDelete">删除</el-button>
<el-button icon="plus" style="margin-left: 10px;" :disabled="!multipleSelection.length"
@click="handleMultiPublish">发布</el-button>
</div> </div>
<!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 --> <!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 -->
@ -114,21 +99,24 @@
<el-table-column align="left" label="状态" width="80"> <el-table-column align="left" label="状态" width="80">
<template #default="scope">{{ formatStatus(scope.row.status) }}</template> <template #default="scope">{{ formatStatus(scope.row.status) }}</template>
</el-table-column> </el-table-column>
<el-table-column align="left" fixed="right" label="操作" width="80"> <el-table-column align="left" fixed="right" label="操作" width="140">
<template #default="scope"> <template #default="scope">
<div> <div class="flex md-2">
<el-button type="primary" link icon="memo" :disabled="scope.row.status === 2" <el-button type="primary" link icon="memo" @click="handleRowPreview(scope.row)">预览</el-button>
@click="handleRowPreview(scope.row)">预览</el-button> <el-button v-if="scope.row.status === 1" type="success" link icon="check"
@click="handleRowChange(scope.row, 2)">提审</el-button>
<el-button v-if="scope.row.status === 2" type="primary" link icon="WindPower"
@click="handleRowReview(scope.row)">审核</el-button>
<el-button v-if="scope.row.status === 3" type="success" link icon="top"
@click="handleRowChange(scope.row, 4)">发布</el-button>
<el-button v-if="scope.row.status === 4" type="warning" link icon="bottom"
@click="handleRowChange(scope.row, 5)">撤销</el-button>
</div> </div>
<div> <div class="flex">
<el-button type="primary" link icon="plus" :disabled="scope.row.status === 2" <el-button :type="scope.row.status === 1 || scope.row.status === 5 ? 'primary' : 'info'" link icon="edit"
@click="handleRowChange(scope.row)">发布</el-button> :disabled="scope.row.status === 4 || scope.row.status === 2"
</div> @click="handleRowEdit(scope.row.ID)">编辑</el-button>
<div> <el-button type="danger" link icon="delete" @click="handleRowDelete(scope.row.ID)">删除</el-button>
<el-button type="primary" link icon="edit" @click="handleRowEdit(scope.row.ID)">编辑</el-button>
</div>
<div>
<el-button type="primary" link icon="delete" @click="handleRowDelete(scope.row.ID)">删除</el-button>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -139,12 +127,13 @@
@size-change="handleSizeChange" /> @size-change="handleSizeChange" />
</div> </div>
</div> </div>
<ArticleEdit ref="articleEditRef" :title="articleEditTitle" @on-save="handlerSaveArticle" />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch, nextTick } from 'vue' import { ref, watch, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { formatDate } from '@/utils/format' import { formatDate } from '@/utils/format'
import { getSourceList } from '@/api/source' import { getSourceList } from '@/api/source'
@ -154,14 +143,19 @@ import { formatTimeToStr } from '@/utils/date'
import { equalArr } from '@/utils/arr' import { equalArr } from '@/utils/arr'
import { import {
getArticleList, getArticleList,
releaseArticle,
deleteArticle, deleteArticle,
deleteArticleByIds,
setArticleChannels, setArticleChannels,
setArticleCategories setArticleCategories,
submitArticle,
reviewArticle,
releaseArticle,
cancelArticle
} from '@/api/article' } from '@/api/article'
import ArticleEdit from '@/view/content/components/articleEdit.vue'
const router = useRouter() const articleEditTitle = ref('')
const articleEditRef = ref(false)
const page = ref(1) const page = ref(1)
const total = ref(0) const total = ref(0)
const pageSize = ref(10) const pageSize = ref(10)
@ -176,8 +170,11 @@ const articleTypeOptions = ref([
{ key: 2, label: '视频' }, { key: 2, label: '视频' },
]) ])
const statusOptions = ref([ const statusOptions = ref([
{ key: 1, label: '未发布' }, { key: 1, label: '草稿' },
{ key: 2, label: '已发布' }, { key: 2, label: '待审核' },
{ key: 3, label: '待发布' },
{ key: 4, label: '已发布' },
{ key: 5, label: '已撤销' },
]) ])
const formatArticleType = (value) => { const formatArticleType = (value) => {
@ -217,10 +214,35 @@ const handleSelectionChange = (val) => {
} }
const handleMultiDelete = () => { const handleMultiDelete = () => {
// @todo ElMessageBox.confirm('确定要删除所选文章吗?', '请确认', {
} confirmButtonText: '确定',
const handleMultiPublish = () => { cancelButtonText: '取消',
// @todo type: 'warning'
}).then(async valid => {
const IDs = []
if (multipleSelection.value.length === 0) {
ElMessage({
type: 'warning',
message: '请选择要删除的数据'
})
return
}
multipleSelection.value &&
multipleSelection.value.map(item => {
IDs.push(item.ID)
})
const res = await deleteArticleByIds({ IDs })
if (res.code === 0) {
ElMessage({
type: 'success',
message: '删除成功'
})
if (tableData.value.length === IDs.length && page.value > 1) {
page.value--
}
getTableData()
}
})
} }
// //
@ -231,7 +253,7 @@ const handleResetSearch = () => {
// //
const handleSubmitSearch = () => { const handleSubmitSearch = () => {
elSearchFormRef.value?.validate(async (valid) => { elSearchFormRef.value?.validate(async valid => {
if (!valid) return if (!valid) return
if (searchInfo.value.status === '') { if (searchInfo.value.status === '') {
searchInfo.value.status = null searchInfo.value.status = null
@ -260,22 +282,28 @@ const handleCurrentChange = (val) => {
// //
const handleAdd = () => { const handleAdd = () => {
router.push({ name: 'articleEdit' }) articleEditTitle.value = '添加文章'
articleEditRef.value.openPage({ articleId: 0 })
} }
// //
const handleRowEdit = (ID) => { const handleRowEdit = (ID) => {
const query = { id: ID } articleEditTitle.value = '编辑文章 ID:' + ID
router.push({ name: 'articleEdit', query }) articleEditRef.value.openPage({ articleId: ID })
}
//
const handlerSaveArticle = () => {
getTableData()
} }
// //
const handleRowDelete = (ID) => { const handleRowDelete = (ID) => {
ElMessageBox.confirm('此操作将永久删除文章, 是否继续?', '提示', { ElMessageBox.confirm('此操作将删除文章, 是否继续?', '请确认', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(async () => { }).then(async valid => {
const res = await deleteArticle({ ID }) const res = await deleteArticle({ ID })
if (res.code === 0) { if (res.code === 0) {
ElMessage({ ElMessage({
@ -290,23 +318,67 @@ const handleRowDelete = (ID) => {
}) })
} }
// //
const handleRowChange = (row) => { const handleRowChange = (row, status) => {
ElMessageBox.confirm('此操作将发布文章, 是否继续?', '提示', { let msg
if (status === 2) {
msg = '文章提交审核'
} else if (status === 4) {
msg = '发布文章到网站'
} else if (status === 5) {
msg = '从网站撤销文章'
}
ElMessageBox.confirm('此操作将' + msg + ', 是否继续?', '请确认', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(async () => { }).then(async valid => {
const res = await releaseArticle({ ID: row.ID, status: 2 }) let res
if (status === 2) {
res = await submitArticle({ ID: row.ID })
} else if (status === 4) {
res = await releaseArticle({ ID: row.ID })
} else if (status === 5) {
res = await cancelArticle({ ID: row.ID, status: 2 })
}
if (res.code === 0) { if (res.code === 0) {
ElMessage({ ElMessage({
type: 'success', type: 'success',
message: '发布成功!' message: msg + '成功!'
}) })
if (tableData.value.length === 1 && page.value > 1) { row.status = status
page.value-- }
})
}
//
const handleRowReview = row => {
ElMessageBox.confirm('请确认是否审核通过确认请按“是”否则请按“否”取消请按“ESC”关闭弹窗', '请确认', {
distinguishCancelAndClose: true,
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning'
}).then(async valid => {
//
const res = await reviewArticle({ ID: row.ID, status: 3 })
if (res.code === 0) {
ElMessage({
type: 'success',
message: '审核确认通过!'
})
row.status = 3
}
}).catch(async (action) => {
//
if (action === 'cancel') {
const res = await reviewArticle({ ID: row.ID, status: 1 })
if (res.code === 0) {
ElMessage({
type: 'warning',
message: '审核确认不通过!'
})
row.status = 1
} }
getTableData()
} }
}) })
} }
@ -314,13 +386,13 @@ const handleRowChange = (row) => {
// //
const handleRowPreview = (row) => { const handleRowPreview = (row) => {
ElMessage({ ElMessage({
type: 'success', type: 'warning',
message: '开发中。。。' message: '开发中。。。'
}) })
} }
// ----- ----- // ----- -----
const handleChangeChannels = async (row) => { const handleChangeChannels = async row => {
await nextTick() await nextTick()
const ids = row.channelIds.map(i => { return parseInt(i) }) const ids = row.channelIds.map(i => { return parseInt(i) })
if (ids.length === 0) { if (ids.length === 0) {
@ -349,7 +421,7 @@ const restoreChannels = (row, message) => {
ElMessage({ type: 'error', message: message }) ElMessage({ type: 'error', message: message })
} }
// ----- ----- // ----- -----
const handleChangeCategories = async (row) => { const handleChangeCategories = async row => {
await nextTick() await nextTick()
const ids = row.categoryIds.map(i => { return parseInt(i) }) const ids = row.categoryIds.map(i => { return parseInt(i) })
if (ids.length === 0) { if (ids.length === 0) {
@ -385,7 +457,7 @@ watch(() => tableData.value, () => {
}) })
// ----- ----- // ----- -----
const getTableData = async () => { const getTableData = async valid => {
const res = await getArticleList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value }) const res = await getArticleList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value })
if (res.code === 0) { if (res.code === 0) {
tableData.value = res.data.list tableData.value = res.data.list
@ -433,21 +505,21 @@ const initOptions = (data, optionsData, disabled) => {
const channelOptions = ref([]) const channelOptions = ref([])
const categoryOptions = ref([]) const categoryOptions = ref([])
const getCategoryData = async () => { const getCategoryData = async valid => {
categoryOptions.value = [] categoryOptions.value = []
const res = await getCategoryTree() const res = await getCategoryTree()
if (res.code === 0) { if (res.code === 0) {
initOptions(res.data.categoryTree, categoryOptions.value, false) initOptions(res.data.categoryTree, categoryOptions.value, false)
} }
} }
const getChannelData = async () => { const getChannelData = async valid => {
channelOptions.value = [] channelOptions.value = []
const res = await getChannelTree() const res = await getChannelTree()
if (res.code === 0) { if (res.code === 0) {
initOptions(res.data.channelTree, channelOptions.value, false) initOptions(res.data.channelTree, channelOptions.value, false)
} }
} }
const getSourceData = async () => { const getSourceData = async valid => {
channelOptions.value = [] channelOptions.value = []
const res = await getSourceList({ page: 1, pageSize: 999 }) const res = await getSourceList({ page: 1, pageSize: 999 })
if (res.code === 0) { if (res.code === 0) {

View File

@ -0,0 +1,490 @@
<template>
<el-drawer v-model="showDrawer" size="90%" :show-close="false" :close-on-press-escape="false"
:close-on-click-modal="false">
<template #header>
<div class="flex justify-between items-center">
<span class="text-lg">{{ props.title }}</span>
<div>
<el-button type="primary" style="width: 120px;" @click="handleFormSubmit"> </el-button>
<el-button @click="handleFormClose"> </el-button>
</div>
</div>
</template>
<div v-loading="fullscreenLoading">
<div class="gva-form-box">
<div v-if="showErrMessage != ''">
{{ showErrMessage }}
</div>
<el-form v-else ref="elEditFormRef" label-position="top" :model="editForm" :rules="formRules">
<el-row :gutter="10">
<el-col :span="17">
<el-row :gutter="10">
<el-col :span="24">
<el-form-item label="标题" prop="title">
<el-input v-model="editForm.title" autocomplete="off" :show-word-limit="true" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="副标题" prop="subtitle">
<el-input v-model="editForm.subtitle" autocomplete="off" :show-word-limit="true" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="文章类型" prop="articleType">
<el-select v-model="editForm.articleType" placeholder="请选择">
<el-option v-for="item in articleTypeOptions" :key="item.key" :label="item.label"
:value="item.key" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="所属栏目" prop="channels">
<el-cascader v-model="channelIdList" :options="channelOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
:collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="3" filterable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="文章分类" prop="categories">
<el-cascader v-model="categoryIdList" :options="categoryOptions" style="width:100%"
:props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
:collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="2" filterable />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="文章内容" prop="content">
<RichEdit v-model="editForm.content" style="height: 50rem;" />
</el-form-item>
</el-col>
<el-col :span="1" align="center">
<el-divider direction="vertical" style="height: 100%" />
</el-col>
<el-col :span="6">
<el-form-item label="摘要" prop="desc">
<el-input v-model="editForm.desc" type="textarea" rows="7" :show-word-limit="true" maxlength="100"
autocomplete="off" resize="none" />
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input v-model="editForm.author" autocomplete="off" />
</el-form-item>
<el-form-item label="来源" prop="source">
<el-select v-model="editForm.source" placeholder="请选择" allow-create clearable filterable>
<el-option v-for="item in sourceOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="跳转链接" prop="source">
<el-input v-model="editForm.url" autocomplete="off" placeholder="https://" clearable />
</el-form-item>
<el-form-item label="发布时间">
<el-date-picker v-model="editForm.publishDate" type="datetime" placeholder="请选择" style="width:100%" />
</el-form-item>
<el-form-item label="文章标签" prop="tags">
<div class="flex flex-wrap gap-2">
<el-tag v-for="(item, index) in tagList" :key="index" type="info" closable size="large"
@close="tagList.splice(index, 1)">
{{ item }}
</el-tag>
<el-select v-model="selectTag" filterable remote allow-create reserve-keyword placeholder="请输入"
:remote-method="loadRemoteTag" :loading="loadingTag" style="width: 100px" @change="handleSelectTag">
<el-option v-for="item in tagOptions" :key="item" :label="item" :value="item" />
</el-select>
</div>
</el-form-item>
<el-form-item label="图片(首张图可用来做栏目列表用)" prop="imgs">
<ChooseImg ref="chooseImg" category="article_imgs" size="800px" @on-select="handleSelectImg" />
<template #label>
<div style="margin-bottom: 10px;">图片首张图可用来做栏目列表用</div>
<div class="flex gap-3">
<el-button type="success" plain icon="folder" @click="handleChooseImg">媒体库</el-button>
<upload-common class="upload-btn-media-library" category="article_imgs"
@on-success="handleImgUpload" />
<el-tooltip effect="dark" content="图片超过 512K 或者 长宽 > 1080 会自动压缩后再上传" placement="top-start">
<upload-image :file-size="512" :max-w-h="1080" category="article_imgs"
@on-success="handleImgUpload" />
</el-tooltip>
</div>
</template>
<div class="media">
<div v-for="(item, key) in imgFileList" :key="key" class="media-box">
<div class="img-box-list">
<el-image :key="key" :src="getUrl(item.url)" fit="cover" :preview-src-list="[getUrl(item.url)]"
hide-on-click-modal style="width: 138px; height: 138px;">
<template #error>
<div class="img-box-list">
<el-icon>
<picture />
</el-icon>
</div>
</template>
</el-image>
</div>
<div class="img-title">
<el-button size="small" type="default" icon="delete" @click="handleImgRemove(item)">删除</el-button>
</div>
</div>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</el-drawer>
</template>
<script setup>
import { getUrl } from '@/utils/image'
import { reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import RichEdit from '@/components/richtext/rich-edit.vue'
import ChooseImg from '@/components/chooseImg/index.vue'
import { getSourceList } from '@/api/source'
import { getCategoryTree } from '@/api/category'
import { getChannelTree } from '@/api/channel'
import { getTagList } from '@/api/tag'
import UploadCommon from '@/components/upload/common.vue'
import UploadImage from '@/components/upload/image.vue'
import {
addArticle,
updateArticle,
getArticleById,
} from '@/api/article'
import { getFetcherArticleById } from '@/api/fetcher'
//
defineOptions({
name: 'ArticleEdit',
})
const emit = defineEmits(['on-save', 'on-close'])
const props = defineProps({
title: { type: String, default: '' }
})
const showDrawer = ref(false)
const showErrMessage = ref('')
const fullscreenLoading = ref(true)
const isEdit = ref(false) // isEdit = true
const fetcherArticleId = ref(0) // id
const elEditFormRef = ref()
const checkCategories = (rule, value, callback) => {
if (categoryIdList.value.length === 0) {
callback(new Error(rule.message))
} else {
callback()
}
}
const checkChannels = (rule, value, callback) => {
if (channelIdList.value.length === 0) {
callback(new Error(rule.message))
} else {
callback()
}
}
const formRules = reactive({
articleType: [
{ required: true, message: '请输选择文章类型', trigger: 'blur' }
],
title: [
{ required: true, message: '请输入文章名称', trigger: 'blur' }
],
subtitle: [
{ required: true, message: '请输入文章副标题', trigger: 'blur' }
],
categories: [
{ validator: checkCategories, message: '请选择文章分类', trigger: 'blur' }
],
channels: [
{ validator: checkChannels, message: '请选择所属栏目', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入文章内容', trigger: 'blur' }
],
})
const articleTypeOptions = ref([
{ key: 1, label: '图文' },
{ key: 2, label: '视频' },
])
const editForm = ref({
ID: 0,
articleType: '',
title: '',
subtitle: '',
author: '',
channels: [],
categories: [],
desc: '',
source: '',
url: '',
publishDate: '',
articleTime: '',
tags: '',
imgs: '',
})
// options
const initOptions = (data, optionsData) => {
data &&
data.forEach(item => {
if (item.children && item.children.length) {
const option = {
title: item.title,
ID: String(item.ID),
children: []
}
initOptions(
item.children,
option.children,
)
optionsData.push(option)
} else {
const option = {
title: item.title,
ID: String(item.ID),
}
optionsData.push(option)
}
})
}
// options 使
const channelOptions = ref([])
const categoryOptions = ref([])
const sourceOptions = ref([])
const getCategoryData = async () => {
categoryOptions.value = []
const res = await getCategoryTree()
if (res.code === 0) {
initOptions(res.data.categoryTree, categoryOptions.value, false)
}
}
const getChannelData = async () => {
channelOptions.value = []
const res = await getChannelTree()
if (res.code === 0) {
initOptions(res.data.channelTree, channelOptions.value, false)
}
}
const getSourceData = async () => {
sourceOptions.value = []
const res = await getSourceList({ page: 1, pageSize: 999 })
if (res.code === 0) {
sourceOptions.value = res.data.list && res.data.list.map(item => item.name)
}
}
const emptyForm = () => {
channelIdList.value = []
categoryIdList.value = []
imgFileList.value = []
tagList.value = []
editForm.value = {
ID: 0,
articleType: '',
title: '',
subtitle: '',
author: '',
channels: [],
categories: [],
desc: '',
source: '',
url: '',
publishDate: '',
articleTime: '',
tags: '',
imgs: '',
}
}
//
const openPage = async (params) => {
showDrawer.value = true
isEdit.value = false
emptyForm()
getCategoryData()
getChannelData()
getSourceData()
// urlID find createupdate idurl
if (params.articleId && params.articleId > 0) {
//
isEdit.value = true
initFormByArticle(params.articleId)
} else if (params.fetcherId && params.fetcherId > 0) {
//
initFormByFetcher(params.fetcherId)
} else {
//
}
fullscreenLoading.value = false
}
const initFormByArticle = async (id) => {
const res = await getArticleById({ ID: id })
if (res.code === 0) {
//
editForm.value = res.data.article
//
const { categories, channels, imgs, tags } = res.data.article
categoryIdList.value = categories && categories.map(item => String(item.ID))
channelIdList.value = channels && channels.map(item => String(item.ID))
if (imgs && (imgs !== '')) {
imgFileList.value = JSON.parse(imgs)
}
if (tags !== '') {
tagList.value = tags.split(',')
}
fullscreenLoading.value = false
} else {
ElMessage({
type: 'error',
message: '获取数据失败'
})
showErrMessage.value = '获取数据失败'
}
}
//
const initFormByFetcher = async (id) => {
const res = await getFetcherArticleById({ ID: id })
if (res.code === 0 && res.data && res.data.article) {
fetcherArticleId.value = id
const { title, author, source, content, publicTime } = res.data.article
editForm.value.title = title
editForm.value.subtitle = title
editForm.value.author = author
editForm.value.source = source
editForm.value.content = content
editForm.value.publishDate = publicTime
editForm.value.articleTime = publicTime
editForm.value.articleType = 1
} else {
ElMessage({
type: 'error',
message: '获取数据失败'
})
showErrMessage.value = '获取数据失败'
}
}
// ---- ----
const chooseImg = ref(null)
const imgFileList = ref([])
const handleChooseImg = () => {
chooseImg.value.open()
return false
}
const handleSelectImg = (file) => {
imgFileList.value.push({
key: file.key,
name: file.name,
url: file.url,
})
}
const handleImgRemove = (file) => {
imgFileList.value = imgFileList.value.filter(item => item.key !== file.key)
}
const handleImgUpload = (file) => {
imgFileList.value.push({
key: file.key,
name: file.name,
url: file.url,
})
}
// ---- tag ----
const tagInputFlag = ref(false)
const selectTag = ref('')
const tagList = ref([])
const tagOptions = ref([])
const loadingTag = ref(false)
const loadRemoteTag = (query) => {
if (query) {
loadingTag.value = true
setTimeout(async () => {
const res = await getTagList({ page: 1, pageSize: 30, keyword: query })
if (res.code === 0) {
tagOptions.value = res.data.list.map(item => item.name)
}
loadingTag.value = false
}, 200)
} else {
tagOptions.value = []
}
}
const handleSelectTag = (val) => {
if (!tagList.value.includes(val)) {
tagList.value.push(val)
}
tagInputFlag.value = false
selectTag.value = ''
}
const categoryIdList = ref([])
const channelIdList = ref([])
// /
const handleFormSubmit = async valid => {
if (editForm.value.publishDate === '') {
editForm.value.publishDate = null
}
if (editForm.value.articleTime === '') {
editForm.value.articleTime = null
}
elEditFormRef.value.validate(async valid => {
if (!valid) {
return
}
const rel = {
categoryIds: categoryIdList.value.map(item => parseInt(item, 10)),
channelIds: channelIdList.value.map(item => parseInt(item, 10)),
imgList: imgFileList.value,
tagList: tagList.value,
fetcherArticleId: fetcherArticleId.value
}
let res
if (isEdit.value) {
res = await updateArticle({ article: editForm.value, rel: rel })
} else {
res = await addArticle({ article: editForm.value, rel: rel })
}
if (res.code === 0) {
ElMessage({
type: 'success',
message: isEdit.value ? '修改成功' : '添加成功!'
})
showDrawer.value = false
emit('on-save')
}
})
}
//
const handleFormClose = () => {
showDrawer.value = false
emit('on-close')
}
//
defineExpose({ openPage })
</script>
<style type="scss">
.admin-box .el-table td .cell {
line-height: 28px;
}
.text-truncate .cell {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}
.img-item {
width: 90px;
height: 90px;
}
</style>

View File

@ -17,6 +17,11 @@
<el-date-picker v-model="searchInfo.dateRange" type="daterange" value-format="YYYY-MM-DD" :clearable="false" <el-date-picker v-model="searchInfo.dateRange" type="daterange" value-format="YYYY-MM-DD" :clearable="false"
:editable="false" /> :editable="false" />
</el-form-item> </el-form-item>
<!-- <el-form-item prop="state" style="width:200px">
<el-select v-model="searchInfo.state" placeholder="请选择状态" clearable style="width:300px">
<el-option v-for="item in statusOptions" :key="item.key" :label="item.label" :value="item.key" />
</el-select>
</el-form-item> -->
<el-form-item label="关键词" style="width:300px"> <el-form-item label="关键词" style="width:300px">
<template #label> <template #label>
<span> <span>
@ -40,8 +45,8 @@
<!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 --> <!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 -->
<el-table ref="multipleTable" :data="tableData" row-key="ID"> <el-table ref="multipleTable" :data="tableData" row-key="ID">
<el-table-column align="left" label="ID" min-width="60" prop="ID" /> <el-table-column align="left" label="ID" min-width="60" prop="ID" />
<el-table-column align="left" label="标题" min-width="270" prop="title" /> <el-table-column align="left" label="标题" min-width="300" prop="title" />
<el-table-column align="left" label="来源" min-width="120" prop="source"> <el-table-column align="left" label="来源" min-width="240" prop="source">
<template #default="scope"> <template #default="scope">
<a :href="scope.row.sourceUrl" target="_blank">{{ scope.row.source }}</a> <a :href="scope.row.sourceUrl" target="_blank">{{ scope.row.source }}</a>
</template> </template>
@ -52,6 +57,11 @@
{{ formatDate(scope.row.createTime) }} {{ formatDate(scope.row.createTime) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="left" label="状态" min-width="80" prop="state">
<template #default="scope">
{{ formatStatus(scope.row.state) }}
</template>
</el-table-column>
<el-table-column align="left" label="发布时间" min-width="120" prop="createtime"> <el-table-column align="left" label="发布时间" min-width="120" prop="createtime">
<template #default="scope"> <template #default="scope">
{{ formatDate(scope.row.publicTime) }} {{ formatDate(scope.row.publicTime) }}
@ -60,8 +70,8 @@
<el-table-column align="left" fixed="right" label="操作" width="80"> <el-table-column align="left" fixed="right" label="操作" width="80">
<template #default="scope"> <template #default="scope">
<div> <div>
<el-button type="primary" link icon="plus" :disabled="scope.row.status === 2" <el-button :type="scope.row.state === 1 ? 'info' : 'primary'" link icon="plus"
@click="handleRowEdit(scope.row.ID)">发布</el-button> :disabled="scope.row.state === 1" @click="handleRowEdit(scope.row.ID)">导入</el-button>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -72,17 +82,20 @@
@size-change="handleSizeChange" /> @size-change="handleSizeChange" />
</div> </div>
</div> </div>
<ArticleEdit ref="articleEditRef" title="导入文章" @on-save="handlerSaveArticle" />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { formatDate } from '@/utils/format' import { formatDate } from '@/utils/format'
import { formatTimeToStr } from '@/utils/date' import { formatTimeToStr } from '@/utils/date'
import { getFetcherArticleList } from '@/api/fetcher' import { getFetcherArticleList } from '@/api/fetcher'
import ArticleEdit from '@/view/content/components/articleEdit.vue'
const router = useRouter() const showDrawer = ref(false)
const articleEditRef = ref(null)
const page = ref(1) const page = ref(1)
const total = ref(0) const total = ref(0)
@ -90,6 +103,15 @@ const pageSize = ref(10)
const searchInfo = ref({}) const searchInfo = ref({})
const tableData = ref([]) const tableData = ref([])
const elSearchFormRef = ref() const elSearchFormRef = ref()
const statusOptions = ref([
{ key: 0, label: '未导入' },
{ key: 1, label: '已导入' },
])
const formatStatus = (value) => {
const rowLabel = statusOptions.value.filter(item => item.key === value)
return rowLabel && rowLabel[0] && rowLabel[0].label
}
const initSearchInfo = () => { const initSearchInfo = () => {
const endDate = new Date() const endDate = new Date()
@ -98,7 +120,7 @@ const initSearchInfo = () => {
dateRange: [ dateRange: [
formatTimeToStr(startDate, 'yyyy-MM-dd'), formatTimeToStr(startDate, 'yyyy-MM-dd'),
formatTimeToStr(endDate, 'yyyy-MM-dd'), formatTimeToStr(endDate, 'yyyy-MM-dd'),
] ],
} }
} }
@ -132,13 +154,16 @@ const handleCurrentChange = (val) => {
// //
const handleRowEdit = (ID) => { const handleRowEdit = (ID) => {
const query = { fetcherId: ID } // const query = { fetcherId: ID }
router.push({ name: 'articleEdit', query }) // router.push({ name: 'articleEdit', query })
showDrawer.value = true
articleEditRef.value.openPage({ fetcherId: ID })
} }
// ----- ----- // ----- -----
const getTableData = async () => { const getTableData = async () => {
const res = await getFetcherArticleList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value }) const state = 0
const res = await getFetcherArticleList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value, state })
if (res.code === 0) { if (res.code === 0) {
tableData.value = res.data.list tableData.value = res.data.list
total.value = res.data.total total.value = res.data.total
@ -146,6 +171,11 @@ const getTableData = async () => {
} }
getTableData() getTableData()
//
const handlerSaveArticle = () => {
getTableData()
}
</script> </script>
<style type="scss"> <style type="scss">