You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
751 lines
22 KiB
751 lines
22 KiB
<template>
|
|
<div class="app-container">
|
|
<el-card class="box-card">
|
|
<el-row :gutter="20">
|
|
<!--部门数据-->
|
|
<el-col :span="3" :xs="24">
|
|
<div class="head-container">
|
|
<el-input
|
|
v-model="deptName"
|
|
placeholder="请输入分类名称"
|
|
clearable
|
|
size="small"
|
|
prefix-icon="el-icon-search"
|
|
style="margin-bottom: 20px"
|
|
:default-expand-all="false"
|
|
/>
|
|
</div>
|
|
<div class="head-container">
|
|
<el-tree
|
|
ref="tree"
|
|
:data="categoryOptions"
|
|
highlight-current
|
|
:props="defaultProps"
|
|
:expand-on-click-node="false"
|
|
:filter-node-method="filterNode"
|
|
@node-click="handleNodeClick"
|
|
/>
|
|
</div>
|
|
</el-col>
|
|
<!--用户数据-->
|
|
<el-col :span="20" :xs="24">
|
|
<el-form
|
|
ref="queryForm"
|
|
:model="listQuery"
|
|
:inline="true"
|
|
label-width="68px"
|
|
>
|
|
<el-form-item label="文章标题" prop="title">
|
|
<el-input
|
|
v-model="listQuery.title"
|
|
placeholder="请输入文章标题"
|
|
clearable
|
|
size="small"
|
|
style="width: 160px"
|
|
@keyup.enter.native="getList"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="文章标签" prop="label_name">
|
|
<el-input
|
|
v-model="listQuery.label_name"
|
|
placeholder="请输入文章标签"
|
|
clearable
|
|
size="small"
|
|
style="width: 160px"
|
|
@keyup.enter.native="getList"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="状态" prop="is_offline">
|
|
<el-select
|
|
v-model="listQuery.is_offline"
|
|
placeholder="文章状态"
|
|
clearable
|
|
size="small"
|
|
style="width: 160px"
|
|
>
|
|
<el-option
|
|
v-for="dict in statusOptions"
|
|
:key="dict.value"
|
|
:label="dict.label"
|
|
:value="dict.value"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button
|
|
type="primary"
|
|
icon="el-icon-search"
|
|
size="mini"
|
|
@click="getList"
|
|
>搜索</el-button
|
|
>
|
|
</el-form-item>
|
|
</el-form>
|
|
<el-row :gutter="10" class="mb8">
|
|
<el-col :span="1.5">
|
|
<el-button
|
|
type="primary"
|
|
icon="el-icon-plus"
|
|
size="mini"
|
|
@click="handleCreate"
|
|
>新增</el-button
|
|
>
|
|
</el-col>
|
|
</el-row>
|
|
<el-table
|
|
v-loading="listLoading"
|
|
:data="list"
|
|
border
|
|
fit
|
|
highlight-current-row
|
|
style="width: 100%"
|
|
>
|
|
<el-table-column label="ID" prop="id" align="center">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.article_id }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="分类" align="center">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.category_id | getCateName(categoriesJson) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="标题" align="center">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.title }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="封面图" align="center">
|
|
<template slot-scope="{ row }">
|
|
<img :src="row.img" height="100" />
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="外链" align="center">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.url }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="文章状态" align="center">
|
|
<template slot-scope="{ row }">
|
|
<div>
|
|
<el-switch
|
|
style="display: block"
|
|
v-model="row.is_offline"
|
|
active-color="#409EFF"
|
|
inactive-color="#ff4949"
|
|
:active-value="2"
|
|
:inactive-value="1"
|
|
@change="changeSwitch($event, row)"
|
|
>
|
|
</el-switch>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="标签详情">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.label_name | getTagDetail }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="创建时间" align="center">
|
|
<template slot-scope="{ row }">
|
|
<span>{{ row.create_time }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label="操作"
|
|
align="center"
|
|
class-name="small-padding fixed-width"
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
size="mini"
|
|
type="text"
|
|
icon="el-icon-edit"
|
|
@click="handleUpdate(scope.row)"
|
|
>修改</el-button
|
|
>
|
|
<el-button
|
|
size="mini"
|
|
type="text"
|
|
icon="el-icon-delete"
|
|
@click="handleDelete(scope.row)"
|
|
>删除</el-button
|
|
>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<pagination
|
|
v-show="total > 0"
|
|
:total="total"
|
|
:page.sync="listQuery.page"
|
|
:limit.sync="listQuery.limit"
|
|
@pagination="getList"
|
|
/>
|
|
</el-col>
|
|
</el-row>
|
|
</el-card>
|
|
|
|
<!-- 添加或修改分类对话框 -->
|
|
<el-drawer
|
|
ref="drawer"
|
|
:title="textMap[dialogStatus]"
|
|
:visible.sync="dialogFormVisible"
|
|
direction="rtl"
|
|
custom-class="demo-drawer"
|
|
size="950px"
|
|
>
|
|
<div class="demo-drawer__content" v-if="dialogFormVisible">
|
|
<el-form
|
|
ref="dataForm"
|
|
:model="temp"
|
|
label-position="left"
|
|
label-width="70px"
|
|
style
|
|
>
|
|
<el-form-item label="类型">
|
|
<treeselect
|
|
v-model="temp.category_id"
|
|
:options="categoryOptions"
|
|
:normalizer="normalizer"
|
|
:show-count="true"
|
|
:disabled="dialogStatus == 'create'"
|
|
placeholder="选择分类"
|
|
/>
|
|
</el-form-item>
|
|
<template v-if="tagData.length">
|
|
<el-form-item
|
|
:label="item.label"
|
|
v-for="(item, index) in tagData"
|
|
:key="index"
|
|
>
|
|
<el-select
|
|
v-model="chooseTagData[index]"
|
|
multiple
|
|
placeholder="请选择"
|
|
style="width: 100%"
|
|
>
|
|
<el-option
|
|
v-for="(sItem, sIndex) in item.value"
|
|
:key="sIndex"
|
|
:label="sItem"
|
|
:value="sItem"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
</template>
|
|
<el-form-item label="标题" prop="title">
|
|
<el-input v-model="temp.title" />
|
|
</el-form-item>
|
|
<el-form-item label="作者" prop="title">
|
|
<el-input
|
|
v-model="temp.author"
|
|
placeholder="请上传视频时填写作者"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="日期" prop="time">
|
|
<el-date-picker
|
|
v-model="temp.time"
|
|
value-format="yyyy-MM-dd HH:mm:ss"
|
|
type="date"
|
|
placeholder="选择日期"
|
|
></el-date-picker>
|
|
</el-form-item>
|
|
<el-form-item label="外链" prop="url">
|
|
<el-input v-model="temp.url" />
|
|
</el-form-item>
|
|
<el-form-item label="描述" prop="description">
|
|
<el-input type="textarea" v-model="temp.description" />
|
|
</el-form-item>
|
|
<el-form-item label="状态">
|
|
<el-radio-group v-model="temp.is_offline" @change="changeRadio">
|
|
<el-radio :label="2">上线</el-radio>
|
|
<el-radio :label="1">下线</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<el-form-item label="封面" prop="img" required>
|
|
<img
|
|
v-if="temp.img"
|
|
:src="temp.img"
|
|
class="el-upload el-upload--picture-card"
|
|
style="float: left; width: auto"
|
|
/>
|
|
<el-upload
|
|
ref="sys_app_logo"
|
|
:on-success="uploadSuccess"
|
|
:on-error="uploadError"
|
|
:action="uploadAction"
|
|
style="float: left"
|
|
list-type="picture-card"
|
|
:show-file-list="false"
|
|
:before-upload="validationImages"
|
|
>
|
|
<i class="el-icon-plus" />
|
|
</el-upload>
|
|
<div
|
|
v-if="validation === false"
|
|
style="padding-left: 10px; color: red"
|
|
>
|
|
提示:宽高{{ dislabelSize.width }}x{{ dislabelSize.height }}
|
|
</div>
|
|
</el-form-item>
|
|
<el-form-item prop="file" label="上传脚本">
|
|
<el-upload
|
|
class="upload-demo"
|
|
:action="uploadAction"
|
|
:limit="1"
|
|
:on-exceed="handleFileExceed"
|
|
:onSuccess="uploadFileSuccess"
|
|
:file-list="temp.script_url ? [JSON.parse(temp.script_url)] : []"
|
|
>
|
|
<el-button size="small" type="primary">点击上传</el-button>
|
|
<!-- <div slot="tip" class="el-upload__tip">
|
|
只能上传jpg/png文件,且不超过500kb
|
|
</div>-->
|
|
</el-upload>
|
|
</el-form-item>
|
|
<el-form-item label="视频时长" prop="video_time">
|
|
<el-time-picker
|
|
v-model="temp.video_time"
|
|
value-format="HH:mm:ss"
|
|
type="time"
|
|
placeholder="选择时间"
|
|
></el-time-picker>
|
|
</el-form-item>
|
|
<el-form-item label="内容" class="editor-box">
|
|
<vue-ueditor-wrap
|
|
v-model="temp.content"
|
|
:config="ueditorConfig"
|
|
:destroy="true"
|
|
v-if="dialogFormVisible"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<div class="demo-drawer__footer">
|
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
|
</div>
|
|
</div>
|
|
</el-drawer>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { validPhone, isEmpty } from "@/utils/validate";
|
|
import {
|
|
fetchList,
|
|
createArticle,
|
|
updateArticle,
|
|
delArticle,
|
|
fetchArticleDetails,
|
|
} from "@/api/article";
|
|
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
|
import VueUeditorWrap from "vue-ueditor-wrap";
|
|
import { listCategory } from "@/api/category";
|
|
import Treeselect from "@riophae/vue-treeselect";
|
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
|
import { log } from "console";
|
|
|
|
export default {
|
|
name: "articleIndex",
|
|
components: { Pagination, Treeselect, VueUeditorWrap },
|
|
data() {
|
|
return {
|
|
deptName: "",
|
|
defaultProps: {
|
|
children: "children",
|
|
label: "category_name",
|
|
},
|
|
// 状态数据字典
|
|
statusOptions: [
|
|
{ value: "", label: "全部" },
|
|
{ value: 2, label: "上线" },
|
|
{ value: 1, label: "下线" },
|
|
],
|
|
categoryOptionsLeft: undefined,
|
|
tableKey: 0,
|
|
list: null,
|
|
total: 0,
|
|
listLoading: true,
|
|
listQuery: {
|
|
page: 1,
|
|
limit: 20,
|
|
is_offline: "",
|
|
title: "",
|
|
label_name: "",
|
|
category_id: undefined,
|
|
author: "", //作者
|
|
},
|
|
// accountRules: {
|
|
// phone: [{ required: true, trigger: 'blur', validator: RulePhone }],
|
|
// wam_name: [{ required: true, trigger: 'blur', validator: RuleEmpty }]
|
|
// },
|
|
ueditorConfig: {
|
|
UEDITOR_HOME_URL: "/UEditor/",
|
|
serverUrl: process.env.VUE_APP_BASE_API + "/files/baiduUp",
|
|
initialFrameHeight: 300,
|
|
scaleEnabled: true,
|
|
},
|
|
uploadAction: process.env.VUE_APP_BASE_API + "/files/uploadFile",
|
|
temp: {
|
|
id: undefined,
|
|
category_id: undefined,
|
|
title: "",
|
|
time: "",
|
|
img: "",
|
|
script_url: "",
|
|
content: "",
|
|
description: "",
|
|
video_time: "",
|
|
is_offline: 2,
|
|
},
|
|
dialogFullscreen: true,
|
|
dialogFormVisible: false,
|
|
dialogStatus: "",
|
|
textMap: {
|
|
update: "编辑",
|
|
create: "添加",
|
|
},
|
|
rules: {
|
|
title: [
|
|
{ required: true, message: "title is required", trigger: "blur" },
|
|
],
|
|
},
|
|
categoryOptions: [],
|
|
// categoriesJson:[],
|
|
downloadLoading: false,
|
|
// tagData:[],
|
|
chooseTagData: [],
|
|
// 是否允许上传
|
|
validation: true,
|
|
// 正确的图片宽高
|
|
dislabelSize: {},
|
|
};
|
|
},
|
|
mounted() {
|
|
this.getList();
|
|
this.getTreeselect();
|
|
},
|
|
computed: {
|
|
categoriesJson() {
|
|
var res = this.handleCategory(this.categoryOptions);
|
|
return res;
|
|
},
|
|
tagData() {
|
|
let matchData = null;
|
|
this.categoriesJson.forEach((item) => {
|
|
if (item.id == this.temp.category_id) {
|
|
matchData = item.label_name;
|
|
}
|
|
});
|
|
return matchData ? JSON.parse(matchData) : [];
|
|
},
|
|
},
|
|
watch: {
|
|
dialogFormVisible(newVal) {
|
|
if (newVal === false) {
|
|
this.validation = true;
|
|
}
|
|
},
|
|
tagData(newVal) {
|
|
console.log("tagDAta");
|
|
console.log(newVal);
|
|
if (!newVal.length) {
|
|
this.chooseTagData = [];
|
|
}
|
|
},
|
|
chooseTagData(newVal) {
|
|
console.log("chooseTagData");
|
|
console.log(newVal);
|
|
},
|
|
// 根据名称筛选部门树
|
|
deptName(val) {
|
|
this.$refs.tree.filter(val);
|
|
},
|
|
},
|
|
filters: {
|
|
getCateName(id, categoriesJson) {
|
|
for (var i = 0; i < categoriesJson.length; i++) {
|
|
if (id == categoriesJson[i].id) {
|
|
return categoriesJson[i].name;
|
|
}
|
|
}
|
|
},
|
|
getTagDetail(data) {
|
|
if (!data) {
|
|
return;
|
|
}
|
|
let str = "";
|
|
data = JSON.parse(data);
|
|
data.forEach((item) => {
|
|
if (item.value.length) {
|
|
str += `${item.label}:${item.value.join("、")};`;
|
|
}
|
|
});
|
|
return str;
|
|
},
|
|
},
|
|
methods: {
|
|
changeRadio(e) {
|
|
this.temp.is_offline = Number(e);
|
|
},
|
|
// 文章开关发生变化
|
|
changeSwitch(e, item) {
|
|
item.is_offline = Number(e);
|
|
updateArticle(item).then((r) => {
|
|
this.$message({
|
|
type: "success",
|
|
message: `${e == 2 ? "通知:文章上线成功" : "通知:文章下线成功"}`,
|
|
});
|
|
});
|
|
},
|
|
// 验证图片宽高
|
|
async validationImages(file) {
|
|
let res = await this.$getImgWidth(file, this.temp.category_id);
|
|
this.validation = res.validation;
|
|
this.dislabelSize = res;
|
|
return res.validation;
|
|
},
|
|
// 节点单击事件
|
|
handleNodeClick(data) {
|
|
this.listQuery.category_id = data.id;
|
|
this.getList();
|
|
},
|
|
handleCategory(array) {
|
|
var res = [];
|
|
array.forEach((item, index) => {
|
|
let obj = {};
|
|
obj.id = item.category_id;
|
|
obj.name = item.category_name;
|
|
obj.label_name = item.label_name;
|
|
res.push(obj);
|
|
if (item.children) {
|
|
res.push(...this.handleCategory(item.children));
|
|
}
|
|
});
|
|
return res;
|
|
},
|
|
// 筛选节点
|
|
filterNode(value, data) {
|
|
if (!value) return true;
|
|
return data.category_name.indexOf(value) !== -1;
|
|
},
|
|
getList() {
|
|
this.listLoading = true;
|
|
fetchList(this.listQuery).then((response) => {
|
|
console.log(response);
|
|
this.list = response.data.list;
|
|
this.total = response.data.count;
|
|
// Just to simulate the time of the request
|
|
setTimeout(() => {
|
|
this.listLoading = false;
|
|
}, 1.5 * 1000);
|
|
});
|
|
},
|
|
handleFilter() {
|
|
this.listQuery.page = 1;
|
|
this.getList();
|
|
},
|
|
handleModifyStatus(row, status) {
|
|
this.$message({
|
|
message: "操作Success",
|
|
type: "success",
|
|
});
|
|
row.status = status;
|
|
},
|
|
resetTemp() {
|
|
this.temp = {
|
|
id: undefined,
|
|
category_id: undefined,
|
|
title: "",
|
|
time: "",
|
|
img: "",
|
|
is_offline: 2,
|
|
script_url: "",
|
|
content: "",
|
|
description: "",
|
|
video_time: "",
|
|
};
|
|
},
|
|
submitForm() {
|
|
let matchData = [...this.tagData];
|
|
this.chooseTagData.forEach((item, index) => {
|
|
matchData[index]["value"] = item;
|
|
});
|
|
this.temp.label_name = JSON.stringify(matchData);
|
|
if (this.dialogStatus == "create") {
|
|
this.createData();
|
|
} else if (this.dialogStatus == "update") {
|
|
this.updateData();
|
|
}
|
|
},
|
|
handleCreate() {
|
|
this.resetTemp();
|
|
this.temp.category_id = this.listQuery.category_id;
|
|
this.dialogStatus = "create";
|
|
this.dialogFormVisible = true;
|
|
this.$nextTick(() => {
|
|
this.$refs["dataForm"].clearValidate();
|
|
});
|
|
},
|
|
createData() {
|
|
// this.$refs['dataForm'].validate((valid) => {
|
|
// if (valid) {
|
|
createArticle(this.temp).then(() => {
|
|
this.dialogFormVisible = false;
|
|
this.$message({
|
|
message: "添加成功",
|
|
type: "success",
|
|
duration: 2 * 1000,
|
|
});
|
|
this.getList();
|
|
});
|
|
// }
|
|
// })
|
|
},
|
|
handleUpdate(row) {
|
|
let article_id = row.article_id;
|
|
this.dialogStatus = "update";
|
|
this.resetTemp();
|
|
this.dialogFormVisible = true;
|
|
fetchArticleDetails({ article_id }).then((res) => {
|
|
if (!res.data.is_offline) {
|
|
res.data.is_offline = 2;
|
|
}
|
|
this.temp = res.data;
|
|
if (this.temp.label_name) {
|
|
let data = JSON.parse(this.temp.label_name);
|
|
data.forEach((item, index) => {
|
|
this.chooseTagData[index] = item.value;
|
|
});
|
|
}
|
|
|
|
this.$nextTick(() => {
|
|
this.$refs["dataForm"].clearValidate();
|
|
});
|
|
});
|
|
},
|
|
updateData() {
|
|
// this.$refs['dataForm'].validate((valid) => {
|
|
// if (valid) {
|
|
updateArticle(this.temp).then(() => {
|
|
this.dialogFormVisible = false;
|
|
this.$message({
|
|
message: "更新成功",
|
|
type: "success",
|
|
duration: 2 * 1000,
|
|
});
|
|
|
|
this.getList();
|
|
});
|
|
// }
|
|
// })
|
|
},
|
|
handleDelete({ title, article_id }) {
|
|
this.$confirm('是否确认删除名称为"' + title + '"的数据项?', "警告", {
|
|
confirmButtonText: "确定",
|
|
cancelButtonText: "取消",
|
|
type: "warning",
|
|
})
|
|
.then(function () {
|
|
console.log("del");
|
|
return delArticle({ article_id });
|
|
})
|
|
.then((response) => {
|
|
if (response.code === 200) {
|
|
this.$message({
|
|
message: "删除分类成功",
|
|
type: "success",
|
|
duration: 2 * 1000,
|
|
});
|
|
this.open = false;
|
|
this.getList();
|
|
} else {
|
|
this.$message({
|
|
message: "删除分类失败",
|
|
type: "error",
|
|
duration: 2 * 1000,
|
|
});
|
|
}
|
|
})
|
|
.catch(function () {});
|
|
},
|
|
uploadSuccess(response, file) {
|
|
if (response.state == "SUCCESS" && this.validation) {
|
|
this.temp.img = response.url;
|
|
}
|
|
// const uid = file.uid;
|
|
// const objKeyArr = Object.keys(this.listObj);
|
|
// for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
|
// if (this.listObj[objKeyArr[i]].uid === uid) {
|
|
// this.listObj[objKeyArr[i]].url = this.config.qiniuHost + response.key;
|
|
// this.listObj[objKeyArr[i]].hasSuccess = true;
|
|
// return;
|
|
// }
|
|
// }
|
|
},
|
|
uploadFileSuccess(response, file) {
|
|
let obj = {};
|
|
obj.name = response.original;
|
|
obj.url = response.url;
|
|
this.temp.script_url = JSON.stringify(obj);
|
|
},
|
|
handleFileExceed(files, fileList) {
|
|
this.$message.warning("只允许上传一个脚本");
|
|
},
|
|
uploadRemove(file) {
|
|
const uid = file.uid;
|
|
const objKeyArr = Object.keys(this.listObj);
|
|
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
|
if (this.listObj[objKeyArr[i]].uid === uid) {
|
|
delete this.listObj[objKeyArr[i]];
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
uploadError(err) {
|
|
this.$alert(err, "发生错误", {
|
|
confirmButtonText: "确定",
|
|
callback: (action) => {},
|
|
});
|
|
},
|
|
/** 查询分类下拉树结构 */
|
|
getTreeselect() {
|
|
listCategory().then((response) => {
|
|
this.categoryOptions = [];
|
|
this.categoryOptions.push(...response.data);
|
|
});
|
|
},
|
|
/** 转换分类数据结构 */
|
|
normalizer(node) {
|
|
if (node.children && !node.children.length) {
|
|
delete node.children;
|
|
}
|
|
return {
|
|
id: node.category_id,
|
|
label: node.category_name,
|
|
children: node.children,
|
|
};
|
|
},
|
|
// 选择类别,获取对应的标签数据
|
|
chooseCategory(node) {
|
|
this.tagData = node.label_name ? JSON.parse(node.label_name) : [];
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.app-container {
|
|
.filter-container {
|
|
margin-left: 5px;
|
|
margin-bottom: 6px;
|
|
}
|
|
::v-deep .el-drawer__body {
|
|
padding: 20px;
|
|
}
|
|
.editor-box {
|
|
::v-deep .el-form-item__content {
|
|
line-height: 20px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|