7a320b0f by chenyunhao

更新常见问题答疑

1 parent 940afc33
......@@ -22,7 +22,9 @@
"nprogress": "0.2.0",
"vue": "2.5.17",
"vue-router": "3.0.1",
"vuex": "3.0.1"
"vuex": "3.0.1",
"@wangeditor/editor": "^5.1.1",
"@wangeditor/editor-for-vue": "^1.0.2"
},
"devDependencies": {
"autoprefixer": "8.5.0",
......
module.exports = {
testListGet: '/xxx/xxx/list',
getArticleClassify: '/admin/articleApi/classify/list',
setArticleClassify: '/admin/articleApi/classify',
getArticleList: '/admin/articleApi/article/list',
setArticleList: '/admin/articleApi/article',
getArticleDetail: '/admin/articleApi/article',
setArticle: '/admin/articleApi/article/save',
getArticleDashboard: '/admin/articleApi/stat/dashboard',
getArticleViewRank: '/admin/articleApi/stat/viewRank',
exportArticleViewRank: '/admin/articleApi/stat/viewRank/export',
getArticleClassifyRank: '/admin/articleApi/stat/classifyRank',
exportArticleClassifyRank: '/admin/articleApi/stat/classifyRank/export',
getArticleKeywordList: '/admin/articleApi/keyword/list',
setArticleKeywordList: '/admin/articleApi/keyword',
getArticleKeywordStat: '/admin/articleApi/keyword/stat',
upload: "/common/upload",
exportTable: exportTable,
}
......
import axios from 'axios';
// import router from './../router'
import router from '@/router/index'
import {
Message
} from 'element-ui'
import {
getToken,
setToken,
removeToken
} from '@/utils/auth'
// 可以使用
import {
MessageBox
} from 'element-ui'
/**
* 提示方法,自行处理
* 可以使用 MessageBox
*
* @param {*} data
*/
let alreadyToast = false
function Toast(data) {
if (alreadyToast) {
return;
}
alreadyToast = true;
MessageBox.alert(data.message, '警告', {
confirmButtonText: '确定',
callback: action => {
alreadyToast = false;
// this.$message({
// type: 'info',
// message: `action: ${action}`
// })
}
})
}
// axios的默认url
// axios.defaults.baseURL = ""
let base = 'https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi';
// 默认超时
axios.defaults.timeout = 60000;
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
if (response.config.responseType == 'blob') {
return Promise.resolve(response)
} else if (response.data.code === 200) {
return Promise.resolve(response);
} else if (response.data.code == 404) {
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
removeToken();
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
} else {
Message({
showClose: true,
message: response.data.errMsg,
type: 'error',
duration: 3000
})
return Promise.reject(response);
}
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
break;
case 404:
// Toast({
// message: '登录过期,请重新登录',
// duration: 1000,
// forbidClick: true
// });
// removeToken();
// setTimeout(() => {
// router.replace({
// path: '/login',
// query: {
// redirect: router.currentRoute.fullPath
// }
// });
// }, 1000);
break;
// 405请求不存在
case 405:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: error.response.data.errMsg,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
);
/**
* 分解参数
*/
function analysisParams(params) {
let {
url,
data,
mode,
opt = Object.assign({}, params.opt),
sid = true,
config,
method
} = params;
if (opt.dec) {
data = makerypt(data);
}
let reqUrl = `${base}${url}`;
if (mode == "custom") {
reqUrl = `${url}`
}
let headers = {}
if (sid) {
// headers.sessionId = getToken();
headers.adminSessionId = getAdminToken();
}
// console.log({
// reqUrl,
// data,
// headers,
// opt,
// method,
// config
// });
return {
reqUrl,
data,
headers,
opt,
method,
config
}
}
/**
* 封装get方法
* @param {*} params
*/
export const httpGet = params => {
params.method = 'get';
let {
reqUrl,
data,
headers,
opt,
method
} = analysisParams(params);
return axios.get(reqUrl, {
params: data,
headers,
opt
}).then(res => res.data.content);
}
/**
* 封装post方法
* mode为custom时,忽略baseUrl
* @param {*} params
*/
export const httpPost = params => {
params.method = 'post';
let {
reqUrl,
data,
headers,
opt,
method
} = analysisParams(params);
return axios.post(reqUrl, data, {
headers,
opt
}).then(res => res.data.content);
}
export const httpDelete = params => {
params.method = 'delete';
let {
reqUrl,
data,
headers,
opt,
method
} = analysisParams(params);
// headers["Content-Type"] = "application/json"
return axios.delete(reqUrl, {
data,
headers,
opt
}).then(res => res.data.content);
}
/**
* 请求封装
* 默认 post 可通过 method设置为get
*
* @param {*} params
* @returns
*/
export const request = params => {
let {
reqUrl,
data,
headers,
opt,
method
} = analysisParams(params);
if (method.toLowerCase() == "post") {
return axios.post(reqUrl, data, {
headers,
opt
}).then(res => res.data.content);
} else {
return axios.get(reqUrl, {
params: data,
headers,
opt
}).then(res => res.data.content);
}
}
/**
* 封装post方法
* @param {*} params
* data数据是 formdata格式
* 例如:
* this.file = file
let data = new FormData() //使用formData对象
data.append('path', '/pro/mzczcradmin/')
data.append('file', file.file)
*/
export const httpFormdata = params => {
let {
reqUrl,
data,
headers,
opt,
method
} = analysisParams(params);
headers["Content-Type"] = "multipart/form-data";
return axios.post(reqUrl, data, {
headers
}).then(res => res.data.content);
}
export const downloadExcel = (params, fileName) => {
let {
reqUrl,
data,
headers,
config
} = analysisParams(params);
return axios({
method: 'get',
url: reqUrl,
params: data,
headers: headers,
responseType: 'blob',
...config
}).then(res => {
let blob = new Blob([res.data], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
})
let downloadElement = document.createElement('a')
let href = window.URL.createObjectURL(blob)
downloadElement.style.display = 'none'
downloadElement.href = href
downloadElement.download = fileName //下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() //点击下载
document.body.removeChild(downloadElement) //下载完成移除元素
window.URL.revokeObjectURL(href) //释放掉blob对象
}).catch(err => {
console.log('err', err)
Toast({
message: '下载失败,请重新下载'
})
})
}
function getAdminToken() {
try {
let token = getToken();
if (token != null && token != undefined) {
return token.adminSessionId;
}
return "";
} catch (e) {
console.error(e);
return "";
}
}
export function getHeaders() {
return {
'adminSessionId': getAdminToken(),
}
}
// 导出表格
export const buildExcelHeader = params => {
let {
reqUrl,
data,
headers
} = analysisParams(params);
let {
filename
} = params;
return axios({
method: 'get',
url: reqUrl,
params: data,
headers: headers,
responseType: 'blob'
// onDownloadProgress:?config.onDownloadProgress
}).then(res => {
let blob = new Blob([res.data], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
})
let downloadElement = document.createElement('a')
let href = window.URL.createObjectURL(blob)
downloadElement.style.display = 'none'
downloadElement.href = href
downloadElement.download = filename //下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() //点击下载
document.body.removeChild(downloadElement) //下载完成移除元素
window.URL.revokeObjectURL(href) //释放掉blob对象
}).catch(err => {
console.log("err", err)
Toast({
message: '下载失败,请重新下载'
})
})
}
import request from '@/utils/request'
// import request from '@/utils/request'
export function login(username, password) {
return request({
......
import request from '@/utils/request'
// import request from '@/utils/request'
export function getList(params) {
return request({
......
<template>
<div :class="{'hide' : hideUpload}">
<el-upload
:file-list="fileList"
:action="reqUrl"
:headers="headers"
:onSuccess="onSuccess"
:accept="isImg ? 'image/*' : ''"
list-type="picture-card"
:onPreview="onPreview"
:onRemove="onRemove"
:beforeUpload="beforeUpload"
:limit="limit || 1"
:data="extraData"
:disabled="disabled"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">{{tips}}</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
<p v-if="sizeTips" class="tips">{{sizeTips}}</p>
</div>
</template>
<script>
/*
* value:当前上传的图片链接 String多图逗号隔开
* limit:当前最大上传数,默认为1
* isImg:true=限制上传类型为png或jpg,fales=不限制上传类型,默认为false
* maxFileSize:限制文件上传最大值
* subPath:图片上传目录
* disabled: 是否禁用上传F
*/
export default {
name: "UploadImg",
props: [
"value",
"limit",
"isImg",
"maxFileSize",
"subPath",
"tip",
"disabled",
"sizeTips"
],
data() {
return {
reqUrl: 'https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/' + app.api.upload,
headers: app.headers(),
dialogVisible: false,
hideUpload: false,
dialogImageUrl: "",
tips: "",
maxSize: 10 * 1024 * 1024,
fileList: [],
extraData: {} //上传额外参数
};
},
watch: {
value(newVal) {
this.initData();
}
},
created() {
this.initData();
},
methods: {
initData() {
if (this.value) {
this.fileList = [];
let _value = this.value.split(",");
for (let i = 0; i < _value.length; i++) {
let obj = {
url: _value[i],
uid: i
};
this.fileList.push(obj);
}
}
this.tips = this.tip;
if (this.subPath) {
this.extraData.subPath = this.subPath;
}
this.isMaxNumber();
// if (this.isImg && this.maxFileSize) {
// this.tips =
// "只能上传jpg/png文件,且文件不超过" + this.maxFileSize + "K";
// } else if (this.isImg) {
// this.tips = "只能上传jpg/png文件";
// } else if (this.maxFileSize > 0) {
// this.tips = "文件不超过" + this.maxFileSize + "K";
// }
},
onSuccess(res, file) {
let nowFileList = [];
if (res.code == 200) {
this.fileList.push({
url: res.content
});
this.isMaxNumber();
for (let i = 0; i < this.fileList.length; i++) {
nowFileList.push(this.fileList[i].url);
}
this.$emit("input", nowFileList.join(","));
} else {
this.$notify.error({
title: "错误",
message: res.errMsg
});
}
},
onPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
beforeUpload(file) {
if (this.maxFileSize) {
const isSize = file.size / 1024 < this.maxFileSize;
if (!isSize) {
this.$message.error(
"上传图片大小不能超过 " + this.maxFileSize + "K!"
);
return false;
}
}
return true;
},
onRemove(file, fileList) {
let nowFileList = [];
for (let i = 0; i < this.fileList.length; i++) {
if (this.fileList[i].uid == file.uid) {
this.fileList.splice(i, 1);
for (let i = 0; i < this.fileList.length; i++) {
nowFileList.push(this.fileList[i].url);
}
this.isMaxNumber();
break;
}
}
this.$emit("input", nowFileList.join(","));
},
isMaxNumber() {
if (this.limit) {
this.hideUpload = this.limit <= this.fileList.length;
} else {
this.hideUpload = this.fileList.length > 0;
}
}
}
};
</script>
<style lang="scss" scoped>
.el-upload__tip {
// margin-top: -15px;
}
.hide /deep/.el-upload--picture-card {
display: none;
}
.tips {
margin: 0;
font-size: 12px;
line-height: 12px;
}
</style>
<template>
<div class="page" style="border: 1px solid #ccc;">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editor"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden;"
v-model="html"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="onCreated"
/>
</div>
</template><script>
import Vue from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
export default Vue.extend({
props: ["value", "subPath"],
components: { Editor, Toolbar },
data() {
return {
editor: null,
html: "<p><br></p>",
toolbarConfig: {
excludeKeys: [
"insertLink",
"todo",
"fullScreen",
"fontFamily",
"lineHeight",
"insertTable",
"codeBlock"
]
},
editorConfig: {
placeholder: "请输入内容...",
// autoFocus: false,
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
uploadImage: {
fieldName: "file",
server:
"https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/" +
app.api.upload,
meta: {
subPath: this.subPath
},
customInsert(res, insertFn) {
console.log(res);
// res 即服务端的返回结果
// 从 res 中找到 url alt href ,然后插图图片
insertFn(res.content, "", "");
}
},
uploadVideo: {
fieldName: "file",
server:
"https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/" +
app.api.upload,
meta: {
subPath: this.subPath
},
customInsert(res, insertFn) {
console.log(res);
// res 即服务端的返回结果
// 从 res 中找到 url alt href ,然后插图图片
insertFn(res.content, "", "");
}
}
}
},
mode: "default" // or 'simple'
};
},
watch: {
html(newVal, oldVal) {
this.$emit("input", newVal);
}
},
methods: {
onCreated(editor) {
this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
},
onCreated(editor) {
this.editor = Object.seal(editor); // 【注意】一定要用 Object.seal() 否则会报错
editor.on("modalOrPanelShow", modalOrPanel => {});
// 可监听 `modalOrPanelShow` 和 `modalOrPanelHide` 自定义事件来设置样式、蒙层
// this.editor.on("modalOrPanelShow", modalOrPanel => {
// modalOrPanel.isShow = false;
// // modalOrPanel.$elem[0].style.display = "none";
// // if (modalOrPanel.type !== "modal") return;
// // const { $elem } = modalOrPanel; // modal element
// // 设置 modal 样式(定位、z-index)
// // 显示蒙层
// });
this.editor.on("modalOrPanelHide", () => {
// 隐藏蒙层
});
},
onOk() {
this.editor.restoreSelection();
SlateTransforms.setNodes(
this.editor,
{ alt: this.alt, href: this.href },
{ match: n => SlateElement.isElement(n) }
);
},
onChange(editor) {
console.log("onChange", editor.getHtml()); // onChange 时获取编辑器最新内容
// console.log(this.editor.getFragment());
}
},
mounted() {
setTimeout(() => {
this.html = this.value;
}, 500);
},
beforeDestroy() {
const editor = this.editor;
if (editor == null) return;
editor.destroy(); // 组件销毁时,及时销毁编辑器
}
});
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style lang="scss" scoped>
</style>
\ No newline at end of file
......@@ -4,7 +4,6 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import '@/styles/index.scss' // global css
......@@ -13,7 +12,17 @@ import store from './store'
import router from './router'
import '@/icons' // icon
import '@/permission' // permission control
// import '@/permission' // permission control
import {
httpGet,
httpPost,
httpDelete,
httpFormdata,
getHeaders,
downloadExcel
} from '@/api/fetch-api-new.js'
/**
......@@ -24,12 +33,26 @@ import '@/permission' // permission control
* it will intercept your request, so you won't see the request in the network.
* If you remove `../mock` it will automatically request easy-mock data.
*/
import '../mock' // simulation data
// import '../mock' // simulation data
Vue.use(ElementUI, { locale })
Vue.use(ElementUI)
Vue.config.productionTip = false
// 配置api
let api = require('@/api/api');
// 挂载全局app
app.api = api;
app.get = httpGet;
app.post = httpPost;
app.delete = httpDelete;
app.form = httpFormdata;
app.headers = getHeaders;
app.downloadExcel = downloadExcel;
app.router = router;
window.app = app;
new Vue({
el: '#app',
router,
......
......@@ -114,8 +114,7 @@ export const constantRouterMap = [{
title: '天宝计算器',
icon: 'nested'
},
children: [
{
children: [{
path: '/calculator/pvpage',
name: 'pvpage',
component: () => import('@/views/calculator/pvpage'),
......@@ -159,8 +158,7 @@ export const constantRouterMap = [{
title: '教育教学',
icon: 'nested'
},
children: [
{
children: [{
path: '/edu/live',
name: 'live',
component: () => import('@/views/live/index'),
......@@ -253,6 +251,104 @@ export const constantRouterMap = [{
]
},
{
path: '/artice',
component: Layout,
redirect: '/artice/list',
name: 'artice',
meta: {
title: '常见问题答疑',
icon: 'nested'
},
children: [{
path: '/artice/list',
name: 'articleList',
component: () => import('@/views/Q&A/article/list'),
meta: {
title: '文章列表',
icon: ''
}
},
{
path: '/artice/detail',
name: 'articleDetail',
component: () => import('@/views/Q&A/article/detail'),
meta: {
title: '设置文章',
icon: ''
},
hidden: true
},
{
path: '/report/article',
name: 'reportArticle',
component: () => import('@/views/Q&A/report/article'),
meta: {
title: '文章统计',
icon: ''
}
},
{
path: '/artice/classify',
name: 'articeClassify',
component: () => import('@/views/Q&A/classify/list'),
meta: {
title: '文章分类',
icon: ''
}
},
{
path: '/artice/classify/detail',
name: 'articeClassifyDetail',
component: () => import('@/views/Q&A/classify/detail'),
meta: {
title: '设置分类',
icon: ''
},
hidden: true
},
{
path: '/report/classify',
name: 'reportClassify',
component: () => import('@/views/Q&A/report/classify'),
meta: {
title: '分类统计',
icon: ''
}
},
{
path: '/keyword/list',
name: 'keywordList',
component: () => import('@/views/Q&A/keyword/list'),
meta: {
title: '关键词',
icon: ''
}
},
{
path: '/keyword/detail',
name: 'keywordDetail',
component: () => import('@/views/Q&A/keyword/detail'),
meta: {
title: '设置关键词',
icon: ''
},
hidden: true
},
{
path: '/report/keyword',
name: 'reportKeyword',
component: () => import('@/views/Q&A/report/keyword'),
meta: {
title: '关键词统计',
icon: ''
}
},
]
},
// {
// path: '/live',
// component: Layout,
......
......@@ -4,6 +4,6 @@ const getters = {
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
roles: state => state.user.roles
// roles: state => state.user.roles
}
export default getters
......
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
// import user from './modules/user'
import getters from './getters'
Vue.use(Vuex)
......@@ -9,7 +9,7 @@ Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app,
user
// user
},
getters
})
......
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import {
login,
logout,
getInfo
} from '@/api/login'
import {
getToken,
setToken,
removeToken
} from '@/utils/auth'
const user = {
state: {
......@@ -26,22 +34,22 @@ const user = {
actions: {
// 登录
Login({ commit }, userInfo) {
Login({
commit
}, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
login(username, userInfo.password).then(response => {
const data = response.content
setToken(data.token)
commit('SET_TOKEN', data.token)
setToken('admin-token')
commit('SET_TOKEN', 'admin-token')
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
GetInfo({
commit,
state
}) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const data = response.content
......@@ -60,7 +68,10 @@ const user = {
},
// 登出
LogOut({ commit, state }) {
LogOut({
commit,
state
}) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
......@@ -74,7 +85,9 @@ const user = {
},
// 前端 登出
FedLogOut({ commit }) {
FedLogOut({
commit
}) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
removeToken()
......
......@@ -9,6 +9,11 @@
display: none;
}
.dialog-footer{
display: flex;
justify-content: flex-end;
}
//暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
......
......@@ -76,3 +76,29 @@ a:hover {
.app-container {
padding: 20px;
}
.tablePage {
padding: 30px;
}
.fixed-bottom {
background-color: #fefefe;
text-align: center;
padding: 15px !important;
text-align: right;
}
.editPage {
margin: 30px 20%;
padding: 30px;
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1);
}
.pointer {
cursor: pointer;
}
.el-date-editor .el-range-separator {
padding: 0;
}
......
import Cookies from 'js-cookie'
const TokenKey = 'kd_admin_token'
const TokenKey = 'tianbao_admin_token'
export function getToken() {
return Cookies.get(TokenKey)
......
......@@ -25,50 +25,25 @@ service.interceptors.request.use(
)
// response 拦截器
service.interceptors.response.use(
response => {
/**
* code为非20000是抛错 可结合自己业务进行修改
*/
// 业务数据
const res = response.data
if (res.code !== 200) {
Message({
message: res.message,
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
MessageBox.confirm(
'你已被登出,可以取消继续留在该页面,或者重新登录',
'确定登出',
{
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return response.data
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
// service.interceptors.response.use(
// response => {
// /**
// * code为非20000是抛错 可结合自己业务进行修改
// */
// // 业务数据
// const res = response.data
// console.log(response.data)
// return response.data
// },
// error => {
// console.log('err' + error) // for debug
// Message({
// message: error.message,
// type: 'error',
// duration: 5 * 1000
// })
// return Promise.reject(error)
// }
// )
export default service
......
import app from "@/store/modules/app";
// 正在表达式
export const REGEXPS = {
"mobile": /^1\d{10}$/,
"email": /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/,
"password": /^[a-zA-Z0-9]{8,16}$/,
}
export function isExist(superAdmin, arr, val) {
if (superAdmin == 1) {
return true;
} else {
arr = arr ? arr : [];
if (arr.indexOf(val) != -1) {
return true;
} else {
return false;
}
}
}
// 验证手机
export function checkMobile(str) {
return REGEXPS.mobile.test(str);
}
// 验证邮箱
export function checkEmail(str) {
return REGEXPS.email.test(str);
}
// 检查密码 密码格式8-16位数字,字母校验
export function checkPassword(str) {
return REGEXPS.password.test(str);
}
// 获取图片内src
export function getImgSrc(str) {
let imgReg = /<img.*?(?:>|\/>)/gi; //获取img的正则表达式
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/gi; //获取所有src的正则表达式
let imgList = str.match(imgReg); //imgList 为包含所有img标签的数组
let srcList = str.match(srcReg); //srcList 为包含所有src标签的数组
return srcList;
}
/**
* 时间戳格式化(yyyy-MM-dd hh:mm:ss)
* @param {*} timestamp 时间戳
* @param {*} format 格式 yyyy-MM-dd hh:mm:ss
*/
export const timestampFormat = (timestamp, format) => {
Date.prototype.Format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
return fmt;
}
if (timestamp && timestamp.length == 10) timestamp += "000";
var date = new Date();
if (timestamp) date.setTime(timestamp);
if (format == null || format == "") {
format = "yyyy-MM-dd hh:mm:ss";
}
return date.Format(format);
};
/**
* 复制内容到剪切板
* @param val 复制文本内容
* @param tips 复制成功提示,为空不提示
*/
export function copyVal(val, tips) {
let oInput = document.createElement('input');
oInput.value = val;
document.body.appendChild(oInput);
oInput.select();
document.execCommand("Copy");
if (tips) {
this.$message({
message: tips,
type: 'success'
});
}
oInput.remove()
}
/**
* 链接参数转换为obj
* 入参 完整链接
* @param {*} url
*/
export function param2Obj(url) {
const search = url.split("?")[1];
if (!search) {
return {};
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"') +
'"}'
);
}
/**
* 获取环境信息
* @return {Object} 环境信息对象
*/
export function getEnv() {
var nav = window.navigator;
var env = {
iphone: false,
ipad: false,
android: false,
pc: false,
ios: false,
ver: "0"
};
var ua = nav.userAgent;
var android = ua.match(/(Android)\s+([\d.]+)/);
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
if (ipad) {
env.ipad = (ipad[1] && true) || false;
env.ver = (ipad[2] && ipad[2].replace(/-/g, ".")) || "";
env.ios = true;
} else if (iphone) {
env.iphone = (iphone[1] && true) || false;
env.ver = (iphone[2] && iphone[2].replace(/-/g, ".")) || "";
env.ios = true;
} else if (android) {
env.android = (android[1] && true) || false;
env.ver = android[2];
} else {
env.pc = true;
}
return env;
}
/**
* 生成uuid
* @param {*} unix_stamp
*/
export function uuid() {
let s = [];
let hexDigits = "0123456789abcdef";
for (let i = 0; i < 32; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
// s[8] = s[13] = s[18] = s[23] = "-";
let uuid = s.join("");
return uuid;
}
/**
* 设定页面 title
* @param {[type]} title [description]
*/
export function setTitle(title) {
if (!title) {
return;
}
document.title = title;
// if (ENV.ios && navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1) {
// 修复微信端IOS无法修改document.title的情况
if (
getEnv().ios &&
(navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1 ||
navigator.userAgent.toLowerCase().indexOf("alipay") !== -1)
) {
//修复IOS微信端和支付宝无法修改document.title的情况
var $iframe = document.createElement("iframe");
$iframe.className = "C-hiddenIframe";
$iframe.src = "/" + location.pathname.split("/")[1] + "/favicon.ico";
$iframe.style.visibility = "hidden";
$iframe.style.width = "1px";
$iframe.style.height = "1px";
$iframe.onload = function onIframeLoad() {
setTimeout(function () {
$iframe.onload = null;
onIframeLoad = null;
document.body.removeChild($iframe);
$iframe = null;
}, 0);
};
document.body.appendChild($iframe);
}
}
// 为链接添加参数
export function addQuery(url, query) {
query = query || {};
query = (function (query) {
var q = [];
Object.keys(query).forEach(function (_q) {
q.push(_q + "=" + query[_q]);
});
return q.join("&");
})(query);
if (url.indexOf("?") !== -1) {
url += "&" + query;
} else {
url += "?" + query;
}
return url;
}
/**
* 获得当前页面的path
* @return {String} 页面path
*/
export function getPath() {
var path = window.location.hash;
path = path || "#/";
path = path === "#/" ? "#/index" : path;
path = path.split("?");
return path[0];
}
// 获取 url 参数
export function getQuery(name) {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
location.href
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
/**
* 升序排列
* @param name 主要参数
* @param minor 次要参数 主要参数相同时,比较次要参数
*/
export function ascSort(name, minor) {
return function (o, p) {
var a, b;
if (o && p && typeof o === "object" && typeof p === "object") {
a = o[name];
b = p[name];
if (a === b) {
return typeof minor === "function" ? minor(o, p) : 0;
}
if (typeof a === typeof b) {
return a < b ? -1 : 1;
}
return typeof a < typeof b ? -1 : 1;
} else {
// throw ("error");
return null;
}
};
}
/**
* 升序排列
* @param name 主要参数
* @param minor 次要参数 主要参数相同时,比较次要参数
*/
export function descSort(name, minor) {
return function (o, p) {
var a, b;
if (o && p && typeof o === "object" && typeof p === "object") {
a = o[name];
b = p[name];
if (a === b) {
return typeof minor === "function" ? minor(o, p) : 0;
}
if (typeof a === typeof b) {
return a > b ? -1 : 1;
}
return typeof a > typeof b ? -1 : 1;
} else {
// throw ("error");
return null;
}
};
}
/**
* 从数组中获取 key未value的对象
* @param {*} value
* @param {*} key
* @param {*} list
*/
export function getObjByListKeyValue(value, key, list) {
let result = null;
list.forEach(element => {
if (element[key + ""] == value) {
result = element;
}
});
return result;
}
/**
* 把 \n换行符转换成<br>
* 转换后需要用 v-html渲染
* 用{{}}会当成字符串把 html渲染出来
*/
export function formatBr(str) {
str = str.replace(/\n/g, "<br/>");
return str;
}
// dd-MM-yyyy转yyyy-MM-dd
export function ddMMyyyy2yyyyMMdd(str) {
return str.replace(/-/g, "").replace(/^(\d{2})(\d{2})(\d{4})$/, "$3-$2-$1");
}
/**
* 获取数字的小数位数
* @param {*} num
*/
export function getDot(num) {
var numStr = num + "";
var index = numStr.indexOf(".");
if (index == -1) {
return 0;
} else {
var t = numStr.slice(index + 1) || '';
return t.length;
}
}
/**
* 深复制
* @param {*} source
* @returns
*/
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
export function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
}
};
}
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
* 时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
*/
export function throttle(func, wait, type) {
if (type === 1) {
var previous = 0;
} else if (type === 2) {
var timeout;
}
return function () {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
}
};
}
export function timestampToTime(row) {
if (row === 0 || row === '' || row == undefined) {
return ''
}
var date = new Date(Number(row))
// var Y = date.getFullYear() + '-'
// var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
// var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
// var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
// var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':'
// var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
// return Y + M + D + h + m + s
var Y = date.getFullYear() + '.'
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '.'
var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes())
return Y + M + D + h + m
}
<template>
<div class="editPage">
<el-form
:model="editForm"
:loading="loading"
ref="editForm"
label-position="right"
label-width="auto"
style="padding-right: 30px"
v-loading="loading"
element-loading-text="操作中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.9)"
>
<el-form-item
label="所属分类"
prop="classifyCode"
:rules="{ required: true, message: '所属分类不能为空', trigger: 'change' }"
>
<el-select class="maxItem" v-model="editForm.classifyCode" placeholder="请选择所属分类">
<el-option
v-for="item in classifyList"
:key="item.classifyCode"
:label="item.classifyName"
:value="item.classifyCode"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label="标题"
prop="articleTitle"
:rules="{ required: true, message: '标题不能为空', trigger: 'blur' }"
>
<el-input v-model="editForm.articleTitle" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item
label="内容"
prop="content"
:rules="{ required: true, message: '内容不能为空', trigger: 'blur' }"
>
<WangEditor v-model="editForm.content" :subPath="subPath" />
</el-form-item>
<el-form-item label="附件">
<el-upload
class="upload-demo"
:onSuccess="successFile"
:onRemove="removeFile"
:file-list="editForm.attachments"
drag
action="https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/common/upload"
multiple
:data="extraData"
accept="application/pdf"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或
<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">*只能上传pdf文件</div>
</el-upload>
</el-form-item>
<el-form-item label="排序值">
<el-input-number v-model="editForm.orderId" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="是否在线" prop="onlineStatus">
<el-switch
v-model="editForm.onlineStatus"
inactive-color="rgb(234,236,240)"
></el-switch>
</el-form-item>
<el-form-item label="是否置顶" prop="inTop">
<el-switch
v-model="editForm.inTop"
inactive-color="rgb(234,236,240)"
></el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="padding-right:30px">
<el-button @click="componentClose">取 消</el-button>
<el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button>
</div>
</div>
</template>
<script>
import UploadImg from "@/components/UploadImg/index.vue";
import WangEditor from "@/components/WangEditor/index.vue";
export default {
props: [],
components: {
UploadImg,
WangEditor
},
data() {
return {
loading: false,
subPath: "article",
editForm: {
articleCode: null,
classifyCode: null,
articleTitle: null,
articleThumb: 0,
author: null,
content: "",
createTime: 0,
orderId: 0,
onlineStatus: true,
inTop: false,
attachments: []
},
classifyList: [],
extraData: {
subPath: "articleFile"
}
};
},
mounted() {
this.initData();
},
methods: {
async initData() {
this.editForm.articleCode = this.$route.query.articleCode;
if (this.editForm.articleCode != null) {
this.getDetail();
}
this.getClassifyList();
},
getDetail() {
app
.get({
url: app.api.getArticleDetail,
data: {
articleCode: this.editForm.articleCode
}
})
.then(res => {
res.inTop = res.inTop == 1 ? true : false;
res.onlineStatus = res.onlineStatus == 1 ? true : false;
if (res.attachments) {
res.attachments = JSON.parse(res.attachments);
} else {
res.attachments = [];
}
this.editForm = res;
});
},
getClassifyList() {
app
.get({ url: app.api.getArticleClassify, data: null })
.then(res => {
this.classifyList = res.list;
})
.catch(e => {});
},
componentSubmit() {
this.$refs["editForm"].validate(valid => {
if (valid) {
if (this.loading) {
return;
}
this.loading = true;
let editForm = JSON.parse(JSON.stringify(this.editForm));
editForm.inTop = this.editForm.inTop ? 1 : 0;
editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0;
editForm.createTime = new Date(this.editForm.createTime).getTime();
if (this.editForm.attachments.length > 0) {
editForm.attachments = JSON.stringify(this.editForm.attachments);
} else {
editForm.attachments = "";
}
console.log("this.editForm", editForm);
app
.post({ url: app.api.setArticle, data: editForm })
.then(res => {
this.loading = false;
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
this.$router.go(-1);
})
.catch(e => {
this.loading = false;
});
}
});
},
componentClose() {
this.$router.go(-1);
},
successFile(res, file) {
if (res.code == 200) {
this.editForm.attachments.push({
name: file.name,
path: res.content
});
} else {
this.$notify.error({
title: "错误",
message: res.errMsg
});
}
},
removeFile(file, fileList) {
this.editForm.attachments.forEach((item, index) => {
if (item.name == file.name) {
this.attachments.attachments.splice(index, 1);
}
});
}
}
};
</script>
<style lang="scss" scoped>
.tablePage {
margin: 0 auto;
}
.el-upload__tip {
color: rgb(190, 190, 190);
}
</style>
\ No newline at end of file
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1">
<el-input @change="getList" v-model="queryForm.query" placeholder="请输入标题名称"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button>
</el-form-item>
</el-form>
</el-header>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column type="index" min-width="50"></el-table-column>
<el-table-column
:show-overflow-tooltip="true"
label="标题"
prop="articleTitle"
min-width="200"
></el-table-column>
<el-table-column label="排序值" prop="orderId" min-width="100"></el-table-column>
<el-table-column :show-overflow-tooltip="false" label="浏览次数" prop="viewNumber" width="130"></el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
<el-tag
v-if="scope.row.onlineStatus==1"
type="success"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)"
>在线</el-tag>
<el-tag
v-else
type="info"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)"
>下线</el-tag>
</template>
</el-table-column>
<el-table-column label="是否置顶" min-width="100">
<template slot-scope="scope">
<el-switch
@change="setList(scope.row)"
v-model="scope.row.inTop"
active-color="rgb(102,177,255)"
inactive-color="rgb(234,236,240)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" min-width="100">
<template slot-scope="scope">
<el-button type="text" @click="handleShowEdit(scope.row.articleCode)">编辑</el-button>
<el-button type="text" @click="handleDelete(scope.row.articleCode)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="queryForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="queryForm.size"
:total="total"
></el-pagination>
</el-footer>
</div>
</template>
<script>
import { timestampFormat } from "@/utils/utils";
const getListApi = app.api.getArticleList;
const setListApi = app.api.setArticleList;
export default {
props: [],
components: {},
data() {
return {
queryForm: {
page: 1,
size: 10,
query: "",
onlineStatus: null,
messageType: null,
vipMark: null
}, //列表默认传参
list: [], //列表数据
total: 0, //列表总数
loading: true, //表格加载状态
keyword: "accountCode",
pojo: null,
showEdit: false,
showChangePwd: false
};
},
created() {
this.initData();
},
methods: {
timestampFormat,
// 初始化数据
async initData() {
this.getList();
},
// 获取列表
getList(resize) {
if (resize && resize != undefined) {
this.queryForm.page = 1;
}
this.loading = true;
app
.get({
url: getListApi,
data: this.queryForm
})
.then(res => {
this.loading = false;
res.list.forEach(item => {
item.onlineStatus = item.onlineStatus == 1 ? true : false;
item.inTop = item.inTop == 1 ? true : false;
});
this.list = res.list;
this.total = res.total;
})
.catch(err => {
this.loading = false;
});
},
// 更新内容
setList(item) {
let editForm = JSON.parse(JSON.stringify(item));
editForm.inTop = item.inTop ? 1 : 0;
editForm.onlineStatus = item.onlineStatus ? 1 : 0;
app
.post({
url: setListApi,
data: editForm
})
.then(res => {
this.$message({
message: "更新成功",
type: "success"
});
// this.getList();
})
.catch(err => {});
},
setOrderType(val) {
if (!val.order) {
this.queryForm.orderType = "";
this.getList(true);
return;
}
switch (val.prop) {
case "createAt":
if (val.order == "descending") {
this.queryForm.orderType = "id:desc";
} else {
this.queryForm.orderType = "id:asc";
}
this.getList(true);
break;
case "viewNumber":
if (val.order == "descending") {
this.queryForm.orderType = "viewNumber:desc";
} else {
this.queryForm.orderType = "viewNumber:asc";
}
this.getList(true);
break;
default:
break;
}
},
// 上下架
setOnlineStatus(item) {
item.onlineStatus = item.onlineStatus == 0 ? 1 : 0;
this.setList(item);
},
// 置顶
setOrderId(item) {
item.inTop = item.inTop == 1 ? 0 : 1;
this.setList(item);
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
handleShowEdit(articleCode) {
this.$router.push({
name: "articleDetail",
query: {
articleCode: articleCode
}
});
},
handleChangePwd(pojo) {
this.pojo = pojo;
this.showChangePwd = true;
},
handleDelete(articleCode) {
this.$confirm("删除后,不可恢复 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app
.delete({
url: setListApi,
data: { articleCode }
})
.then(res => {
this.$message({
message: "更新成功",
type: "success"
});
this.getList();
})
.catch(err => {});
})
.catch(() => {
this.loading = true;
});
},
handleChangeStatue(row, status) {
let msg = status == 1 ? "是否上线当前文章?" : "是否下线当前文章?";
let data = JSON.parse(JSON.stringify(row));
data.onlineStatus = status;
data.inTop = data.inTop ? 1 : 0;
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app.post({ url: setListApi, data }).then(res => {
this.getList();
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
}
}
};
</script>
<style lang="scss" scoped>
/deep/ .el-dialog__wrapper {
overflow: hidden;
}
</style>
<template>
<div class="editPage">
<el-form
:model="editForm"
:loading="loading"
ref="editForm"
label-position="right"
label-width="auto"
style="padding-right:50px;"
v-loading="loading"
element-loading-text="操作中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.9)"
>
<el-form-item
label="名称"
prop="classifyName"
:rules="{ required: true, message: '名称不能为空', trigger: 'blur' }"
>
<el-input v-model="editForm.classifyName" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="排序值">
<el-input-number v-model="editForm.orderId" :min="0"></el-input-number>
</el-form-item>
<el-form-item
label="是否在线"
prop="onlineStatus"
:rules="{ required: true, message: '请选择状态', trigger: 'blur' }"
>
<el-switch
v-model="editForm.onlineStatus"
inactive-color="rgb(234,236,240)"
></el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="padding-right:30px">
<el-button @click="componentClose">取 消</el-button>
<el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button>
</div>
</div>
</template>
<script>
import UploadImg from "@/components/UploadImg/index.vue";
export default {
props: [],
components: { UploadImg },
data() {
return {
isLinkDialog: false,
searchLoading: false,
title: "轮播图",
submitUrl: "",
loading: false,
dialogVisiable: false,
editForm: {
classifyCode: "",
classifyIcon: "",
classifyHomePic: "",
classifyName: "",
onlineStatus: true,
onShow: false,
orderId: 0
},
// 连接值的候选项
valueCandidates: [],
getForm: {
query: null,
page: 0,
size: 10
},
candidatesEnd: false,
fetchUrl: "",
labelKey: "",
valueKey: ""
};
},
mounted() {
this.initData();
},
methods: {
async initData() {
this.submitUrl = app.api.setArticleClassify;
if (this.$route.query.pojo != "null") {
this.editForm = JSON.parse(this.$route.query.pojo);
this.editForm.onlineStatus = this.editForm.onlineStatus ? true : false;
this.editForm.onShow = this.editForm.onShow ? true : false;
}
this.dialogVisiable = true;
},
componentClose() {
this.$router.go(-1);
},
componentClosed() {
this.$emit("closed");
},
componentSubmit() {
this.$refs["editForm"].validate(valid => {
if (valid) {
if (this.loading) {
return;
}
this.loading = true;
let editForm = JSON.parse(JSON.stringify(this.editForm));
editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0;
editForm.onShow = this.editForm.onShow ? 1 : 0;
app
.post({
url: this.submitUrl,
data: editForm
})
.then(res => {
this.loading = false;
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
this.$router.go(-1);
})
.catch(e => {
this.loading = false;
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.commoditySelect {
width: 100%;
max-width: auto;
}
.tablePage {
margin: 0 auto;
}
</style>
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1"></el-form-item>
<el-form-item>
<el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button>
</el-form-item>
</el-form>
</el-header>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column label="名称" prop="classifyName"></el-table-column>
<!-- <el-table-column label="图标" min-width="100">
<template slot-scope="scope">
<el-image style="width: 50px; height: 50px" :src="scope.row.classifyIcon"></el-image>
</template>
</el-table-column>
<el-table-column label="主分类图标" min-width="100">
<template slot-scope="scope">
<el-image style="width: 50px; height: 50px" :src="scope.row.classifyHomePic"></el-image>
</template>
</el-table-column>-->
<el-table-column label="状态">
<template slot-scope="scope">
<el-tag
v-if="scope.row.onlineStatus==1"
type="success"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)"
>在线</el-tag>
<el-tag
v-else
type="info"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)"
>下线</el-tag>
</template>
</el-table-column>
<el-table-column label="排序" prop="orderId"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleShowEdit(scope.row)">编辑</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
:disabled="scope.row.sysList ? true : false"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="queryForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="queryForm.size"
:total="total"
></el-pagination>
</el-footer>
</div>
</template>
<script>
// 列表路径
const listUrl = app.api.getArticleClassify;
// 提交路径
const postUrl = app.api.setArticleClassify;
// 唯一标识
const primaryCodeName = "classifyCode";
export default {
components: {},
data() {
return {
postUrl,
queryForm: {
page: 1,
size: 10
}, //列表默认传参
list: [], //列表数据
total: 0, //列表总数
loading: true, //表格加载状态
classifyCode: "",
relationsArticleCodes: [],
isShowRelations: false,
articlesList: [],
transferProps: {
key: "memberCode",
label: "name"
}
};
},
created() {
this.initData();
},
methods: {
// 初始化数据
initData(resize) {
if (resize && resize != undefined) {
this.queryForm.page = 1;
}
this.getList();
},
// 获取列表
getList() {
this.loading = true;
app
.get({
url: listUrl,
data: this.queryForm
})
.then(res => {
this.loading = false;
this.list = res.list;
this.total = res.total;
})
.catch(err => {
this.loading = false;
});
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
handleShowEdit(pojo) {
this.$router.push({
name: "articeClassifyDetail",
query: {
pojo: JSON.stringify(pojo)
}
});
},
handleShowRelation(classifyCode) {
this.relationsArticleCodes = [];
this.classifyCode = classifyCode;
this.getArticleRelativeArticles(classifyCode);
},
handleDelete(pojo) {
this.$confirm("删除后,不可恢复 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
let data = {};
data[primaryCodeName] = pojo[primaryCodeName];
this.loading = true;
app
.delete({
url: postUrl,
data
})
.then(res => {
this.getList();
this.$notify({
title: "成功",
message: "删除成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
},
handleChangeStatue(row, status) {
let msg = status == 1 ? "是否上线当前分类?" : "是否下线当前分类?";
let data = JSON.parse(JSON.stringify(row));
data.onlineStatus = status;
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app.post({ url: postUrl, data }).then(res => {
this.getList();
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
},
handleChangeShow(row, status) {
let msg = status == 1 ? "是否显示当前分类?" : "是否隐藏当前分类?";
let data = JSON.parse(JSON.stringify(row));
data.onShow = status;
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app.post({ url: postUrl, data }).then(res => {
this.getList();
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
}
}
};
</script>
<style scoped>
.transfer {
margin: 0 auto;
}
.not-allowed {
cursor: not-allowed;
}
</style>
<template>
<div class="editPage">
<el-form
:model="editForm"
:loading="loading"
ref="editForm"
label-position="right"
label-width="auto"
style="padding-right:50px;"
v-loading="loading"
element-loading-text="操作中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.9)"
>
<el-form-item
label="关键词"
prop="keyword"
:rules="{ required: true, message: '关键词不能为空', trigger: 'blur' }"
>
<el-input v-model="editForm.keyword" placeholder="请输入关键词"></el-input>
</el-form-item>
<el-form-item label="排序值">
<el-input-number v-model="editForm.orderId" :min="0"></el-input-number>
</el-form-item>
<el-form-item
label="是否在线"
prop="onlineStatus"
:rules="{ required: true, message: '请选择状态', trigger: 'blur' }"
>
<el-switch
v-model="editForm.onlineStatus"
inactive-color="rgb(234,236,240)"
></el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="padding-right:30px">
<el-button @click="componentClose">取 消</el-button>
<el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button>
</div>
</div>
</template>
<script>
import UploadImg from "@/components/UploadImg/index.vue";
export default {
props: [],
components: { UploadImg },
data() {
return {
isLinkDialog: false,
searchLoading: false,
title: "轮播图",
submitUrl: "",
loading: false,
dialogVisiable: false,
editForm: {
primaryCode: "",
keyword: "",
onlineStatus: true,
orderId: 0
},
// 连接值的候选项
valueCandidates: [],
getForm: {
query: null,
page: 0,
size: 10
},
candidatesEnd: false,
fetchUrl: "",
labelKey: "",
valueKey: ""
};
},
mounted() {
this.initData();
},
methods: {
async initData() {
this.submitUrl = app.api.setArticleKeywordList;
if (this.$route.query.pojo != "null") {
this.editForm = JSON.parse(this.$route.query.pojo);
this.editForm.onlineStatus = this.editForm.onlineStatus ? true : false;
this.editForm.onShow = this.editForm.onShow ? true : false;
}
this.dialogVisiable = true;
},
componentClose() {
this.$router.go(-1);
},
componentClosed() {
this.$emit("closed");
},
componentSubmit() {
this.$refs["editForm"].validate(valid => {
if (valid) {
if (this.loading) {
return;
}
this.loading = true;
let editForm = JSON.parse(JSON.stringify(this.editForm));
editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0;
editForm.onShow = this.editForm.onShow ? 1 : 0;
app
.post({
url: this.submitUrl,
data: editForm
})
.then(res => {
this.loading = false;
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
this.$router.go(-1);
})
.catch(e => {
this.loading = false;
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.commoditySelect {
width: 100%;
max-width: auto;
}
.tablePage {
margin: 0 auto;
}
</style>
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1"></el-form-item>
<el-form-item>
<el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button>
</el-form-item>
</el-form>
</el-header>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column label="关键词" prop="keyword"></el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
<el-tag
v-if="scope.row.onlineStatus==1"
type="success"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)"
>在线</el-tag>
<el-tag
v-else
type="info"
class="pointer"
:class="{'not-allowed' : scope.row.sysList}"
@click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)"
>下线</el-tag>
</template>
</el-table-column>
<el-table-column label="排序" prop="orderId"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleShowEdit(scope.row)">编辑</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
:disabled="scope.row.sysList ? true : false"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="queryForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="queryForm.size"
:total="total"
></el-pagination>
</el-footer>
</div>
</template>
<script>
// 列表路径
const listUrl = app.api.getArticleKeywordList;
// 提交路径
const postUrl = app.api.setArticleKeywordList;
// 唯一标识
const primaryCodeName = "primaryCode";
export default {
components: {},
data() {
return {
postUrl,
queryForm: {
page: 1,
size: 10
}, //列表默认传参
list: [], //列表数据
total: 0, //列表总数
loading: true, //表格加载状态
classifyCode: "",
relationsArticleCodes: [],
isShowRelations: false,
articlesList: [],
transferProps: {
key: "memberCode",
label: "name"
}
};
},
created() {
this.initData();
},
methods: {
// 初始化数据
initData(resize) {
if (resize && resize != undefined) {
this.queryForm.page = 1;
}
this.getList();
},
// 获取列表
getList() {
this.loading = true;
app
.get({
url: listUrl,
data: this.queryForm
})
.then(res => {
this.loading = false;
this.list = res.list;
this.total = res.total;
})
.catch(err => {
this.loading = false;
});
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
handleShowEdit(pojo) {
this.$router.push({
name: "keywordDetail",
query: {
pojo: JSON.stringify(pojo)
}
});
},
handleShowRelation(classifyCode) {
this.relationsArticleCodes = [];
this.classifyCode = classifyCode;
this.getArticleRelativeArticles(classifyCode);
},
handleDelete(pojo) {
this.$confirm("删除后,不可恢复 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
let data = {};
data[primaryCodeName] = pojo[primaryCodeName];
this.loading = true;
app
.delete({
url: postUrl,
data
})
.then(res => {
this.getList();
this.$notify({
title: "成功",
message: "删除成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
},
handleChangeStatue(row, status) {
let msg = status == 1 ? "是否上线当前分类?" : "是否下线当前分类?";
let data = JSON.parse(JSON.stringify(row));
data.onlineStatus = status;
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app.post({ url: postUrl, data }).then(res => {
this.getList();
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
},
handleChangeShow(row, status) {
let msg = status == 1 ? "是否显示当前分类?" : "是否隐藏当前分类?";
let data = JSON.parse(JSON.stringify(row));
data.onShow = status;
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.loading = true;
app.post({ url: postUrl, data }).then(res => {
this.getList();
this.$notify({
title: "成功",
message: "操作成功",
type: "success"
});
});
})
.catch(() => {
this.loading = true;
});
}
}
};
</script>
<style scoped>
.transfer {
margin: 0 auto;
}
.not-allowed {
cursor: not-allowed;
}
</style>
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1">
<el-date-picker
v-model="date"
@change="setData"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="exportList()" type="primary">
<i class="el-icon-download"></i>导出明细
</el-button>
</el-form-item>
</el-form>
</el-header>
<div class="dataBoxList">
<div class="dataBox">
<h5 class="tit">整体报告</h5>
<div class="dataList">
<div class="item">
<label>浏览次数</label>
<h5>{{dashboardInfo.viewNumber}}</h5>
</div>
<div class="item">
<label>浏览人数</label>
<h5>{{dashboardInfo.viewPerson}}</h5>
</div>
<div class="item">
<label>分享次数</label>
<h5>{{dashboardInfo.shareNumber}}</h5>
</div>
</div>
</div>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column
label="标题"
prop="articleTitle"
min-width="300"
:show-overflow-tooltip="true"
></el-table-column>
<el-table-column label="分类" prop="classifyName"></el-table-column>
<el-table-column label="标签" prop="tagName"></el-table-column>
<el-table-column label="浏览次数" prop="viewNumber"></el-table-column>
<el-table-column label="浏览人数" prop="viewPerson"></el-table-column>
<el-table-column label="分享次数" prop="shareNumber"></el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<!-- <el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="dashboardForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="dashboardForm.size"
:total="total"
></el-pagination>
</el-footer>-->
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { timestampFormat } from "@/utils/utils";
import { buildExcelHeader } from "@/api/fetch-api-new.js";
export default {
name: "Dashboard",
data() {
return {
date: [],
pickerOptions: {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
}
}
]
},
dashboardForm: {
dateRange: "",
page: 1,
size: 9999
},
dashboardInfo: { viewNumber: 0, shareNumber: 0, viewPerson: 0 },
list: [], //列表数据
total: 0, //列表总数
loading: true //表格加载状态
};
},
computed: {
startDate() {
let date = this.date;
let result = (date && date[0]) || "";
if (result) {
result = date[0].getTime();
}
return result;
},
endDate() {
let date = this.date;
let result = (date && date[1]) || "";
if (result) {
result = date[1].getTime();
}
return result;
}
},
methods: {
initData() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
this.date = [start, end];
this.setData();
},
getMemberDashboard(resize) {
app
.get({
url: app.api.getArticleDashboard,
data: this.dashboardForm
})
.then(res => {
this.dashboardInfo = res;
})
.catch(err => {});
},
getList(resize) {
if (resize && resize != undefined) {
this.dashboardForm.page = 1;
}
this.loading = true;
app
.get({
url: app.api.getArticleViewRank,
data: this.dashboardForm
})
.then(res => {
this.loading = false;
this.list = res;
})
.catch(err => {
this.loading = false;
});
},
setData() {
this.dashboardForm.dateRange =
timestampFormat(this.startDate, "yyyy-MM-dd") +
"," +
timestampFormat(this.endDate, "yyyy-MM-dd");
this.getMemberDashboard();
this.getList();
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
//导出,下载表格
exportList() {
let fileName =
"资料库明细" + timestampFormat(new Date().getTime()) + ".xlsx";
buildExcelHeader({
url: app.api.exportArticleViewRank,
data: this.dashboardForm,
filename: fileName
});
}
},
mounted() {},
created() {
this.initData();
}
};
</script>
<style lang="scss" scoped>
.stat-container {
color: #1a1b1c;
font-weight: 400;
position: relative;
max-width: 1100px;
margin: 0 auto;
padding: 30px;
margin-top: 5px;
background-color: white;
.userInfo {
display: flex;
align-items: center;
span {
font-size: 40px;
margin-left: 30px;
}
}
.btn {
margin-top: 30px;
}
.formBox {
width: 500px;
background-color: white;
padding: 20px;
border-radius: 10px;
margin-top: 30px;
.footerBtn {
text-align: right;
}
}
}
h5 {
margin: 0;
}
.dataBoxList {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.dataBox {
width: 100%;
min-height: 240px;
background-color: rgb(242, 242, 242);
overflow: hidden;
margin-bottom: 30px;
.tit {
font-size: 22px;
margin: 30px;
}
.dataList {
display: flex;
justify-content: center;
margin-top: 60px;
.item {
width: 250px;
text-align: center;
label {
font-size: 16px;
}
h5 {
font-size: 40px;
margin: 20px 0;
}
}
}
.chartList {
width: 98%;
display: flex;
margin: 30px 0;
margin-left: 1%;
.chare {
width: 100%;
height: 400px;
}
}
}
.fixed-bottom {
width: 100%;
text-align: right;
}
.el-header {
padding: 0;
}
</style>
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1">
<el-date-picker
v-model="date"
@change="setData"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="exportList()" type="primary">
<i class="el-icon-download"></i>导出明细
</el-button>
</el-form-item>
</el-form>
</el-header>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column label="分类名称" prop="classifyName"></el-table-column>
<el-table-column label="浏览次数" prop="viewNumber"></el-table-column>
<el-table-column label="浏览人数" prop="viewPerson"></el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<!-- <el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="dashboardForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="dashboardForm.size"
:total="total"
></el-pagination>
</el-footer>-->
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { timestampFormat } from "@/utils/utils";
import { buildExcelHeader } from "@/api/fetch-api-new.js";
export default {
name: "Dashboard",
data() {
return {
date: [],
pickerOptions: {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
}
}
]
},
dashboardForm: {
dateRange: "",
page: 1,
size: 9999
},
dashboardInfo: {},
list: [], //列表数据
total: 0, //列表总数
loading: true //表格加载状态
};
},
computed: {
startDate() {
let date = this.date;
let result = (date && date[0]) || "";
if (result) {
result = date[0].getTime();
}
return result;
},
endDate() {
let date = this.date;
let result = (date && date[1]) || "";
if (result) {
result = date[1].getTime();
}
return result;
}
},
methods: {
initData() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
this.date = [start, end];
this.setData();
},
getList(resize) {
if (resize && resize != undefined) {
this.dashboardForm.page = 1;
}
this.loading = true;
app
.get({
url: app.api.getArticleClassifyRank,
data: this.dashboardForm
})
.then(res => {
this.loading = false;
this.list = res;
})
.catch(err => {
this.loading = false;
});
},
setData() {
this.dashboardForm.dateRange =
timestampFormat(this.startDate, "yyyy-MM-dd") +
"," +
timestampFormat(this.endDate, "yyyy-MM-dd");
this.getList();
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
//导出,下载表格
exportList() {
let fileName =
"分类明细" + timestampFormat(new Date().getTime()) + ".xlsx";
buildExcelHeader({
url: app.api.exportArticleClassifyRank,
data: this.dashboardForm,
filename: fileName
});
}
},
mounted() {},
created() {
this.initData();
}
};
</script>
<style lang="scss" scoped>
.stat-container {
color: #1a1b1c;
font-weight: 400;
position: relative;
max-width: 1100px;
margin: 0 auto;
padding: 30px;
margin-top: 5px;
background-color: white;
.userInfo {
display: flex;
align-items: center;
span {
font-size: 40px;
margin-left: 30px;
}
}
.btn {
margin-top: 30px;
}
.formBox {
width: 500px;
background-color: white;
padding: 20px;
border-radius: 10px;
margin-top: 30px;
.footerBtn {
text-align: right;
}
}
}
h5 {
margin: 0;
}
.dataBoxList {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.dataBox {
width: 100%;
min-height: 240px;
background-color: rgb(242, 242, 242);
overflow: hidden;
margin-bottom: 30px;
.tit {
font-size: 22px;
margin: 30px;
}
.dataList {
display: flex;
justify-content: center;
margin-top: 60px;
.item {
width: 250px;
text-align: center;
label {
font-size: 16px;
}
h5 {
font-size: 40px;
margin: 20px 0;
}
}
}
.chartList {
width: 98%;
display: flex;
margin: 30px 0;
margin-left: 1%;
.chare {
width: 100%;
height: 400px;
}
}
}
.fixed-bottom {
width: 100%;
text-align: right;
}
.el-header {
padding: 0;
}
</style>
<template>
<div class="tablePage">
<!-- 筛选参数 -->
<el-header>
<el-form :inline="true" style="display:flex">
<el-form-item style="flex-grow: 1">
<el-date-picker
v-model="date"
@change="setData"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
></el-date-picker>
</el-form-item>
<!-- <el-form-item>
<el-button @click="exportList()" type="primary">
<i class="el-icon-download"></i>导出明细
</el-button>
</el-form-item> -->
</el-form>
</el-header>
<!-- 表格 -->
<el-container>
<el-table :data="list" :loading="loading">
<el-table-column label="关键词" prop="word"></el-table-column>
<el-table-column label="搜索次数" prop="times"></el-table-column>
<el-table-column label="搜索匹配文章数" prop="match"></el-table-column>
</el-table>
</el-container>
<!-- 分页 -->
<!-- <el-footer class="fixed-bottom">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
:current-page="dashboardForm.page"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10,20,30,50]"
:page-size="dashboardForm.size"
:total="total"
></el-pagination>
</el-footer>-->
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { timestampFormat } from "@/utils/utils";
import { buildExcelHeader } from "@/api/fetch-api-new.js";
export default {
name: "Dashboard",
data() {
return {
date: [],
pickerOptions: {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
}
}
]
},
dashboardForm: {
dateRange: "",
page: 1,
size: 9999
},
dashboardInfo: {},
list: [], //列表数据
total: 0, //列表总数
loading: true //表格加载状态
};
},
computed: {
startDate() {
let date = this.date;
let result = (date && date[0]) || "";
if (result) {
result = date[0].getTime();
}
return result;
},
endDate() {
let date = this.date;
let result = (date && date[1]) || "";
if (result) {
result = date[1].getTime();
}
return result;
}
},
methods: {
initData() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
this.date = [start, end];
this.setData();
},
getList(resize) {
if (resize && resize != undefined) {
this.dashboardForm.page = 1;
}
this.loading = true;
app
.get({
url: app.api.getArticleKeywordStat,
data: this.dashboardForm
})
.then(res => {
this.loading = false;
this.list = res;
})
.catch(err => {
this.loading = false;
});
},
setData() {
this.dashboardForm.dateRange =
timestampFormat(this.startDate, "yyyy-MM-dd") +
"," +
timestampFormat(this.endDate, "yyyy-MM-dd");
this.getList();
},
// 切换页码大小
handleSizeChange(val) {
this.queryForm.size = val;
this.queryForm.page = 1;
this.initData();
},
// 切换页码
handleCurrentChange(val) {
this.queryForm.page = val;
this.initData();
},
//导出,下载表格
exportList() {
let fileName =
"分类明细" + timestampFormat(new Date().getTime()) + ".xlsx";
buildExcelHeader({
url: app.api.exportArticleClassifyRank,
data: this.dashboardForm,
filename: fileName
});
}
},
mounted() {},
created() {
this.initData();
}
};
</script>
<style lang="scss" scoped>
.stat-container {
color: #1a1b1c;
font-weight: 400;
position: relative;
max-width: 1100px;
margin: 0 auto;
padding: 30px;
margin-top: 5px;
background-color: white;
.userInfo {
display: flex;
align-items: center;
span {
font-size: 40px;
margin-left: 30px;
}
}
.btn {
margin-top: 30px;
}
.formBox {
width: 500px;
background-color: white;
padding: 20px;
border-radius: 10px;
margin-top: 30px;
.footerBtn {
text-align: right;
}
}
}
h5 {
margin: 0;
}
.dataBoxList {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.dataBox {
width: 100%;
min-height: 240px;
background-color: rgb(242, 242, 242);
overflow: hidden;
margin-bottom: 30px;
.tit {
font-size: 22px;
margin: 30px;
}
.dataList {
display: flex;
justify-content: center;
margin-top: 60px;
.item {
width: 250px;
text-align: center;
label {
font-size: 16px;
}
h5 {
font-size: 40px;
margin: 20px 0;
}
}
}
.chartList {
width: 98%;
display: flex;
margin: 30px 0;
margin-left: 1%;
.chare {
width: 100%;
height: 400px;
}
}
}
.fixed-bottom {
width: 100%;
text-align: right;
}
.el-header {
padding: 0;
}
</style>
<template>
<div class="navbar">
<hamburger :toggle-click="toggleSideBar" :is-active="sidebar.opened" class="hamburger-container"/>
<hamburger
:toggle-click="toggleSideBar"
:is-active="sidebar.opened"
class="hamburger-container"
/>
<breadcrumb />
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
<i class="el-icon-caret-bottom"/>
<img :src="require('@/assets/user/user.jpg')" class="user-avatar" />
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<router-link class="inlineBlock" to="/">
<el-dropdown-item>
Home
</el-dropdown-item>
<el-dropdown-item>Home</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">LogOut</span>
......@@ -22,9 +24,9 @@
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
import { mapGetters } from "vuex";
import Breadcrumb from "@/components/Breadcrumb";
import Hamburger from "@/components/Hamburger";
export default {
components: {
......@@ -32,29 +34,27 @@ export default {
Hamburger
},
computed: {
...mapGetters([
'sidebar',
'avatar'
])
...mapGetters(["sidebar", "avatar"])
},
methods: {
toggleSideBar() {
this.$store.dispatch('ToggleSideBar')
this.$store.dispatch("ToggleSideBar");
},
logout() {
this.$store.dispatch('LogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
// this.$store.dispatch('LogOut').then(() => {
// location.reload() // 为了重新实例化vue-router对象 避免bug
// })
this.$router.push({ path: "/login" });
}
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.navbar {
height: 50px;
line-height: 50px;
box-shadow: 0 1px 3px 0 rgba(0,0,0,.12), 0 0 3px 0 rgba(0,0,0,.04);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
.hamburger-container {
line-height: 58px;
height: 50px;
......
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
auto-complete="on"
label-position="left"
>
<h3 class="title">Trimble Geospatial</h3>
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input v-model="loginForm.username" name="username" type="text" auto-complete="on" placeholder="username" />
<el-input
v-model="loginForm.username"
name="username"
type="text"
auto-complete="on"
placeholder="username"
/>
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input :type="pwdType" v-model="loginForm.password" name="password" auto-complete="on" placeholder="password" @keyup.enter.native="handleLogin" />
<el-input
:type="pwdType"
v-model="loginForm.password"
name="password"
auto-complete="on"
placeholder="password"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="pwdType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-form-item>
<el-button :loading="loading" type="primary" style="width:100%;" @click.native.prevent="handleLogin">
Sign in
</el-button>
<el-button
:loading="loading"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>Sign in</el-button>
</el-form-item>
<!--<div class="tips">
<span style="margin-right:20px;">username: admin</span>
......@@ -31,85 +54,87 @@
</template>
<script>
import { isvalidUsername } from '@/utils/validate'
import { isvalidUsername } from "@/utils/validate";
import { setToken } from "@/utils/auth";
export default {
name: 'Login',
name: "Login",
data() {
const validateUsername = (rule, value, callback) => {
if (!isvalidUsername(value)) {
callback(new Error('请输入正确的用户名'))
callback(new Error("请输入正确的用户名"));
} else {
callback()
}
callback();
}
};
const validatePass = (rule, value, callback) => {
if (value.length < 5) {
callback(new Error('密码不能小于5位'))
callback(new Error("密码不能小于5位"));
} else {
callback()
}
callback();
}
};
return {
loginForm: {
username: 'admin',
password: 'admin'
username: "admin",
password: "admin"
},
loginRules: {
username: [
{
required: true,
trigger: 'blur',
trigger: "blur",
validator: validateUsername
}
],
password: [
{ required: true, trigger: 'blur', validator: validatePass }
]
password: [{ required: true, trigger: "blur", validator: validatePass }]
},
loading: false,
pwdType: 'password',
pwdType: "password",
redirect: undefined
}
};
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
methods: {
showPwd() {
if (this.pwdType === 'password') {
this.pwdType = ''
if (this.pwdType === "password") {
this.pwdType = "";
} else {
this.pwdType = 'password'
this.pwdType = "password";
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store
.dispatch('Login', this.loginForm)
.then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
// this.$router.push({ path: '/dictionary/pv' })
})
.catch(() => {
this.loading = false
})
this.loading = true;
setToken('admin-token')
this.$router.push({ path: this.redirect || "/" });
// setToken;
// this.$store
// .dispatch('Login', this.loginForm)
// .then(() => {
// this.loading = false
// this.$router.push({ path: this.redirect || '/' })
// // this.$router.push({ path: '/dictionary/pv' })
// })
// .catch(() => {
// this.loading = false
// })
} else {
console.log('error submit!!')
return false
console.log("error submit!!");
return false;
}
})
});
}
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss">
......