@ -1,5 +1,618 @@
< template >
< div class = "content" >
待开发
< div class = "app-container customer-control" >
< div class = "container-custom" >
<!-- 搜索栏 -- >
< div ref = "searchBarRef" class = "search-box" >
< div class = "search-bar" >
< div class = "search-bar-left" >
< el-form
ref = "searchForm"
: inline = "true"
: model = "formInline"
class = "demo-form-inline"
: label - width = "'auto'"
>
< el-form-item label = "标题" prop = "title" >
< el-input
v - model = "formInline.title"
placeholder = "请输入品牌名称"
clearable
/ >
< / el-form-item >
< el-form-item label = "资讯分类" prop = "category" >
< el-select v-model = "formInline.category" placeholder="请选择资讯分类" clearable >
< el-option
v - for = "dict in sys_good_category"
: key = "dict.value" : label = "dict.label" : value = "dict.value"
/ >
< / el-select >
< / el-form-item >
< el-form-item label = "状态" prop = "status" >
< el-select v-model = "formInline.status" placeholder="请选择" clearable >
< el-option v-for = "item in statusList" :key="item.id" :value="item.id" :label="item.name" / >
< / el-select >
< / el-form-item >
< el-form-item
label = "添加时间"
prop = "startDate"
style = "margin-right: 0"
>
< el-date-picker
v - model = "formInline.startDate"
type = "date"
value - format = "YYYY-MM-DD"
placeholder = "请选择起始日期"
clearable
: disabled - date = "disableStartDate"
style = "width: 160px"
/ >
< span
style = "width: 30px; text-align: center; display: inline-block"
>
-
< / span >
< el-date-picker
v - model = "formInline.endDate"
type = "date"
value - format = "YYYY-MM-DD"
placeholder = "请选择截止日期"
clearable
: disabled - date = "disableEndDate"
style = "width: 160px"
/ >
< / el-form-item >
< / el-form >
< / div >
< div class = "search-bar-right" >
< el-button class = "el-button-gry" type = "primary" icon = "Search" @click ="onSubmit"
> 查询 < / e l - b u t t o n
>
< el-button
icon = "Refresh"
style = "margin: 16px 0 0 0"
@ click = "resetForm"
> 重置 < / e l - b u t t o n
>
< / div >
< / div >
< / div >
<!-- 表格 -- >
< div class = "table-cont" : style = "{ height: tableViewportHeight + 'px' }" >
< div class = "table-toolbar" >
< el-button
icon = "delete"
@ click = "batchDelete"
: disabled = "btnStatus"
style = "margin-right: 10px"
> 批量删除 < / e l - b u t t o n
>
< el-button type = "primary" class = "el-button-gry" icon = "plus" @click ="handleAdd"
> 添加内容 < / e l - b u t t o n
>
< / div >
< tableComponent
: table - data = "tableData"
: columns = "columns"
: show - border = "false"
: show - selection = "true"
: header - cell - class - name = "getHeaderClass"
@ page - change = "handlePaginationChange"
: loading = "tableLoading"
@ selection - change = "handleSelectionChange"
: total = "tableTotal"
: current - page = "formInline.current"
: page - size = "formInline.size"
: showSort = "true"
: rowkey = "'id'"
>
<!-- 自定义 - 图片 -- >
< template # imgPath = "slotProps" >
< div class = "table-cell-img-box" >
< img :src = "slotProps.row.imgPath" class = "table-cell-img" alt = "" / >
< / div >
< / template >
<!-- 自定义 - 资讯分类 -- >
< template # category = "slotProps" >
< span > { { sys _good _category [ parseInt ( slotProps . row . category ) ] ? . label } } < / span >
< / template >
<!-- 自定义 - 发布位置 -- >
< template # publishLocation = "slotProps" >
< span > { { sys _good _content [ parseInt ( slotProps . row . publishLocation ) ] ? . label } } < / span >
< / template >
<!-- 自定义 - 状态 -- >
< template # status = "slotProps" >
< span v-if = "slotProps.row.status == 1" class = "color-green"
> 使用中 < / s p a n
>
< span v -else -if = " slotProps.row.status = = 0 " class = "color-red"
> 已停用 < / s p a n
>
< / template >
<!-- 自定义 - 操作 -- >
< template # action = "slotProps" >
< el-button v-if = "slotProps.row.status == 0" text class="el-button-custom" @click="startStop(slotProps.row)" > 启用 < / el -button >
< el-button v-if = "slotProps.row.status == 1" text class="el-button-custom" @click="startStop(slotProps.row)" > 停用 < / el -button >
< el-button text class = "el-button-custom" @click ="handleEdit(slotProps.row)" > 编辑 < / el -button >
< el-button text class = "el-button-custom" @click ="handleView(slotProps.row)" > 查看 < / el -button >
< el-button text class = "el-button-delete" @click ="handleDelete(slotProps.row)" > 删除 < / el -button >
< / template >
< / tableComponent >
< / div >
< / div >
<!-- 添加 / 编辑 -- >
< el-dialog v-model = "dialogFormVisible" :title="dialogTitle" width="500" :close-on-click-modal="false" >
< el-form :disabled = "disabled" :model = "dialogForm" :label-width = "'80'" :rules = "dialogFormRules" ref = "dialogRef" >
< el-form-item label = "标题" prop = "title" >
< el-input v-model = "dialogForm.title" autocomplete="off" placeholder="请输入内容标题" / >
< / el-form-item >
< el-form-item label = "资讯分类" prop = "category" >
< el-select v-model = "dialogForm.category" placeholder="请选择资讯分类" >
< el-option
v - for = "dict in sys_good_category"
: key = "dict.value" : label = "dict.label" : value = "dict.value"
/ >
< / el-select >
< / el-form-item >
< el-form-item label = "发布位置" prop = "publishLocation" >
< el-select v-model = "dialogForm.publishLocation" placeholder="请选择发布位置" >
< el-option
v - for = "dict in sys_good_content"
: key = "dict.value" : label = "dict.label" : value = "dict.value"
/ >
< / el-select >
< / el-form-item >
< el-form-item label = "内容" prop = "content" >
< div style = "border: 1px solid #ccc; margin-top: 10px" >
< Toolbar
: editor = "editorRef"
: defaultConfig = "toolbarConfig"
: mode = "mode"
style = "border-bottom: 1px solid #ccc"
/ >
< Editor
: defaultConfig = "editorConfig"
: mode = "mode"
: disabled = "disabled"
v - model = "dialogForm.content"
style = "height: 300px; overflow-y: scroll"
@ onCreated = "handleCreated"
@ onChange = "handleChange"
@ onDestroyed = "handleDestroyed"
@ onFocus = "handleFocus"
@ onBlur = "handleBlur"
@ customAlert = "customAlert"
@ customPaste = "customPaste"
/ >
< / div >
< / el-form-item >
< / el-form >
< template # footer >
< div class = "dialog-footer" >
< el-button type = "primary" @click ="onSaveCategory" >
保存
< / el-button >
< el-button @click ="cancelDialog" > 取消 < / el -button >
< / div >
< / template >
< / el-dialog >
< / div >
< / template >
< / template >
< script setup >
import { ref , reactive , computed , onMounted , onBeforeUnmount } from "vue" ;
import tableComponent from "@/components/tableComponent.vue" ;
import myUploadImage from "@/components/myUploadImage.vue" ;
import Mock from "mockjs" ;
import { getInformation , addConten , updateInformation , deleteInformation , getInfo , updateInformationEnable } from "@/api/content/index" ;
/ / i m p o r t { g e t D i c t s } f r o m " @ / a p i / s y s t e m / d i c t / d a t a " ;
const { proxy } = getCurrentInstance ( )
const { sys _good _category , sys _good _content } = proxy . useDict ( "sys_good_category" , "sys_good_content" )
/ / c o n s o l e . l o g ( ' s y s _ g o o d _ c a t e g o r y 资 讯 分 类 ' , s y s _ g o o d _ c a t e g o r y ) ;
/ / c o n s o l e . l o g ( ' s y s _ g o o d _ c o n t e n t 发 布 位 置 ' , s y s _ g o o d _ c o n t e n t ) ;
import { id } from "element-plus/es/locales.mjs" ;
import { ElMessage , ElMessageBox } from "element-plus" ;
import '@wangeditor/editor/dist/css/style.css' ;
import { Editor , Toolbar } from '@wangeditor/editor-for-vue'
import { getToken } from "@/utils/auth"
/ / 编 辑 器 实 例 , 必 须 用 s h a l l o w R e f
const editorRef = shallowRef ( )
const toolbarConfig = { }
const editorConfig = reactive ( {
placeholder : '请输入内容...' ,
MENU _CONF : {
uploadImage : {
server : import . meta . env . VITE _APP _BASE _API + "/uploadApis/upload" ,
fieldName : 'file' ,
maxFileSize : 10 * 1024 * 1024 ,
maxNumberOfFiles : 1 ,
allowedFileTypes : [ 'image/*' ] ,
headers : {
'Authorization' : 'Bearer ' + getToken ( ) ,
} ,
/ / 自 定 义 上 传 结 果 处 理
customInsert ( res , insertFn ) {
console . log ( 'customInsert 被调用:' , res ) / / 检 查 是 否 执 行
if ( res . code === 200 ) {
insertFn ( "http://gov-cloud.oss-cn-chengdu.aliyuncs.com/" + res . data . url , '' , '' )
}
}
}
}
} )
const mode = 'default' / / 或 ' s i m p l e '
/ / 组 件 销 毁 时 , 也 及 时 销 毁 编 辑 器
onBeforeUnmount ( ( ) => {
const editor = editorRef . value
if ( editor == null ) return
editor . destroy ( )
} )
const handleCreated = ( editor ) => {
editorRef . value = editor / / 记 录 e d i t o r 实 例 , 重 要 !
}
/ / 自 动 暴 露 所 有 顶 层 绑 定
defineExpose ( {
editorRef ,
mode ,
toolbarConfig ,
editorConfig ,
handleCreated
} )
const formInline = reactive ( {
id : "" ,
title : "" , / / 商 品 名 称
useNum : '' , / / 使 用 数 量
status : "" , / / 状 态
startDate : "" , / / 开 始 时 间
endDate : "" , / / 结 束 时 间
category : "" , / / 分 类
current : 1 ,
size : 10 ,
} ) ;
let isADD = ref ( true ) ;
const dialogFormVisible = ref ( false ) ;
const dialogRef = ref ( null ) ;
const dialogTitle = ref ( "添加品牌" ) ;
const categoryList = ref ( [ ] ) ;
const disabled = ref ( false ) ;
let dialogForm = reactive ( {
id : "" ,
title : "" ,
content : "" ,
category : "" ,
publishLocation : '' ,
} ) ;
const dialogFormRules = ref ( {
title : [
{ required : true , message : "请输入品牌名称" , trigger : "blur" } ,
] ,
content : [
{ required : true , message : "请输入内容" , trigger : "blur" } ,
] ,
category : [
{ required : true , message : "请选择分类" , trigger : "blur" } ,
] ,
publishLocation : [
{ required : true , message : "请选择发布位置" , trigger : "blur" } ,
] ,
} ) ;
const statusList = ref ( [
{ name : "使用中" , id : "1" } ,
{ name : "已停用" , id : "0" } ,
] ) ;
/ / 禁 用 开 始 日 期 的 逻 辑 ( 不 能 晚 于 已 选 的 结 束 日 期 )
const disableStartDate = ( time ) => {
if ( ! formInline . endDate ) return false ;
const endDate = new Date ( formInline . endDate ) ;
return time . getTime ( ) > endDate . getTime ( ) ;
} ;
/ / 禁 用 结 束 日 期 的 逻 辑 ( 不 能 早 于 已 选 的 开 始 日 期 )
const disableEndDate = ( time ) => {
if ( ! formInline . startDate ) return false ;
const startDate = new Date ( formInline . startDate ) . setHours ( 0 , 0 , 0 , 0 ) ;
const currentDate = new Date ( time ) . setHours ( 0 , 0 , 0 , 0 ) ;
return currentDate < startDate ;
} ;
const searchForm = ref ( null ) ;
/ / 加 载 数 据
const loadData = async ( ) => {
tableLoading . value = true ;
let prams = { ... formInline } ;
try {
prams . startDate = formInline . startDate ? formInline . startDate + " 00:00:00" : "" ;
prams . endDate = formInline . endDate ? formInline . endDate + " 23:59:59" : "" ;
let response = await getInformation ( prams ) ;
if ( response . code == 200 ) {
tableData . value = response . data . records ;
tableTotal . value = response . data . total ;
}
} catch ( error ) {
}
tableLoading . value = false ;
} ;
const onSubmit = ( ) => {
formInline . current = 1 ;
loadData ( ) ;
} ;
const resetForm = ( ) => {
searchForm . value . resetFields ( ) ;
formInline . endDate = "" ;
loadData ( ) ;
} ;
/ / 表 格 数 据
const tableData = ref ( [ ] ) ;
const selectedIds = ref ( [ ] ) ;
const btnStatus = computed ( ( ) => {
return selectedIds . value . length <= 0 ;
} ) ;
const tableLoading = ref ( false ) ;
const tableTotal = ref ( 0 ) ;
let nowClickRow = ref ( { } ) ;
/ / 列 配 置
const columns = ref ( [
{ prop : "title" , label : "标题" } ,
{ prop : "category" , label : "资讯分类" , slotName : "category" , } ,
{ prop : "publishLocation" , label : "发布位置" , slotName : "publishLocation" , } ,
{ prop : "createTime" , label : "发布日期" , } ,
{ prop : "views" , label : "浏览量" , } ,
{ prop : "status" , label : "状态" , slotName : "status" , } ,
{ prop : "action" , label : "操作" , slotName : "action" , width : "180" , align : "center" } ,
] ) ;
/ / 自 定 义 表 头 类 名 , 也 可 以 在 c o l u m n s 指 定 列 中 添 加 h e a d e r C l a s s N a m e : ' c u s t o m - h e a d e r '
const getHeaderClass = ( { column } ) => {
return "custom-header" ;
} ;
/ / 分 页 变 化
const handlePaginationChange = ( { page , pageSize } ) => {
console . log ( "分页变化:" , page , pageSize ) ;
formInline . current = page ;
formInline . size = pageSize ;
/ / 这 里 可 以 调 用 A P I 获 取 新 数 据
loadData ( ) ;
} ;
/ / 多 选 框 变 化
const handleSelectionChange = ( selection ) => {
console . log ( "选中项:" , selection ) ;
selectedIds . value = [ ] ;
selection . forEach ( element => {
selectedIds . value . push ( element . id ) ;
} ) ;
} ;
/ / 批 量 删 除
const batchDelete = async ( ) => {
/ / d e l e t e G o o d s ( s e l e c t e d I d s . v a l u e . j o i n ( " , " ) ) ;
ElMessageBox . confirm ( "确定要删除选中的数据吗?" , "提示" , {
confirmButtonText : "确定" ,
cancelButtonText : "取消" ,
type : "warning" ,
} )
. then ( async ( ) => {
deleteGoods ( selectedIds . value ) ;
} )
. catch ( ( ) => {
ElMessage . info ( "已取消删除" ) ;
} )
} ;
const deleteGoods = async ( param ) => {
console . log ( "批量删除参数:" , param ) ;
try {
tableLoading . value = true ;
let res = await deleteInformation ( param ) ;
tableLoading . value = false ;
if ( res . code == 200 ) {
ElMessage . success ( "删除成功" ) ;
loadData ( ) ;
} else {
ElMessage . error ( res . msg ) ;
}
} catch ( error ) {
tableLoading . value = false ;
}
} ;
/ / 添 加 商 品
const handleAdd = ( ) => {
disabled . value = false ;
nextTick ( ( ) => {
if ( editorRef . value ) {
editorRef . value . enable ( ) ; / / 重 新 启 用 编 辑 器
}
} ) ;
resetDlg ( ) ;
dialogTitle . value = "添加品牌" ;
isADD . value = true ;
dialogFormVisible . value = true ;
/ / c o n s o l e . l o g ( f o r m I n l i n e ) ;
} ;
/ / 提 交 保 存
const onSaveCategory = async ( ) => {
console . log ( 'dialogForm' , dialogForm ) ;
dialogRef . value . validate ( async ( valid ) => {
if ( valid ) {
if ( isADD . value ) {
let response = await addConten ( dialogForm ) ;
if ( response . code === 200 ) {
dialogFormVisible . value = false ;
ElMessage . success ( "新增成功!" ) ;
dialogRef . value . resetFields ( ) ;
loadData ( ) ;
} else {
ElMessage . error ( response . message ) ;
}
} else {
let response = await updateInformation ( dialogForm ) ;
if ( response . code === 200 ) {
dialogFormVisible . value = false ;
ElMessage . success ( "编辑成功!" ) ;
dialogRef . value . resetFields ( ) ;
loadData ( ) ;
} else {
ElMessage . error ( response . message ) ;
}
}
}
} ) ;
} ;
/ / 启 用 停 用
const startStop = async ( row ) => {
let status = row . status == 1 ? 0 : 1 ;
let params = { id : row . id , status : status } ;
let response = await updateInformationEnable ( params ) ;
if ( response . code === 200 ) {
ElMessage . success ( "操作成功!" ) ;
loadData ( ) ;
} else {
ElMessage . error ( response . message ) ;
}
} ;
/ / 编 辑 操 作
const handleEdit = async ( row ) => {
disabled . value = false ;
nextTick ( ( ) => {
if ( editorRef . value ) {
editorRef . value . enable ( ) ; / / 重 新 启 用 编 辑 器
}
} ) ;
resetDlg ( ) ;
isADD . value = false ;
dialogFormVisible . value = true ;
let response = await getInfo ( row . id ) ;
if ( response . code === 200 ) {
Object . assign ( dialogForm , response . data ) ; / / 保 持 响 应 性
dialogTitle . value = "编辑品牌" ;
} else {
ElMessage . error ( response . message ) ;
}
} ;
/ / 查 看 操 作
const handleView = async ( row ) => {
disabled . value = true ;
resetDlg ( ) ;
isADD . value = false ;
dialogFormVisible . value = true ;
let response = await getInfo ( row . id ) ;
if ( response . code === 200 ) {
Object . assign ( dialogForm , response . data ) ; / / 保 持 响 应 性
dialogTitle . value = "查看品牌" ;
nextTick ( ( ) => {
if ( editorRef . value ) {
editorRef . value . disable ( ) ; / / 调 用 编 辑 器 禁 用 A P I
}
} ) ;
} else {
ElMessage . error ( response . message ) ;
}
} ;
/ / 删 除 操 作
const handleDelete = async ( row ) => {
/ / 提 示 一 下 是 否 确 定 删 除
ElMessageBox . confirm ( "确定要删除吗?" , "提示" , {
confirmButtonText : "确定" ,
cancelButtonText : "取消" ,
type : "warning" ,
} )
. then ( async ( ) => {
let response = await deleteInformation ( row . id ) ;
if ( response . code === 200 ) {
ElMessage . success ( "品牌删除成功!" ) ;
loadData ( ) ;
} else {
ElMessage . error ( response . message ) ;
}
} )
. catch ( ( ) => {
ElMessage . info ( "已取消删除" ) ;
} )
} ;
/ / 取 消 弹 框
const cancelDialog = ( ) => {
resetDlg ( ) ;
} ;
const resetDlg = ( ) => {
dialogRef . value ? . resetFields ( ) ; / / 重 置 表 单 验 证 状 态
Object . assign ( dialogForm , { / / 保 持 响 应 性 , 手 动 清 空 字 段
id : "" ,
title : "" ,
imgPath : "" ,
code : ""
} ) ;
dialogFormVisible . value = false ;
}
const titleRef = ref ( null ) ;
const searchBarRef = ref ( null ) ;
const tableViewportHeight = ref ( 0 ) ;
/ / 精 确 计 算 可 用 高 度
const calculateTableHeight = ( ) => {
/ / 获 取 窗 口 总 高 度
const windowHeight = window . innerHeight ;
/ / 获 取 各 组 件 高 度
const headerHeight = titleRef . value ? . $el ? . offsetHeight || 0 ;
const searchBarHeight = searchBarRef . value ? . offsetHeight || 0 ;
/ / 计 算 容 器 内 边 距 补 偿 ( 根 据 实 际 样 式 调 整 )
const paddingCompensation = 130 ;
/ / 最 终 计 算
tableViewportHeight . value =
windowHeight - headerHeight - searchBarHeight - paddingCompensation ;
/ / c o n s o l e . l o g ( t a b l e V i e w p o r t H e i g h t . v a l u e ) ;
} ;
/ / 组 件 挂 载 时 加 载 数 据
onMounted ( ( ) => {
loadData ( ) ;
calculateTableHeight ( ) ;
/ / 添 加 响 应 式 监 听
window . addEventListener ( "resize" , calculateTableHeight ) ;
/ / 监 听 D O M 变 化 ( 适 用 于 动 态 变 化 的 h e a d e r / s e a r c h b a r )
const observer = new ResizeObserver ( calculateTableHeight ) ;
if ( titleRef . value ? . $el ) observer . observe ( titleRef . value . $el ) ;
if ( searchBarRef . value ) observer . observe ( searchBarRef . value ) ;
} ) ;
onBeforeUnmount ( ( ) => {
window . removeEventListener ( "resize" , calculateTableHeight ) ;
} ) ;
< / script >
< style lang = "scss" scoped >
. table - toolbar {
width : 300 px ;
height : 50 px ;
position : absolute ;
right : 0 ;
top : 0 ;
display : flex ;
justify - content : end ;
padding : 14 px 16 px 0 0 ;
}
< / style >