统计分析
This commit is contained in:
parent
4a64f8f492
commit
c751f26122
@ -8,6 +8,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.22.0",
|
||||
"echarts": "^5.2.1",
|
||||
"element-plus": "^1.1.0-beta.19",
|
||||
"hyperdown": "^2.4.29",
|
||||
"moment": "^2.29.1",
|
||||
|
||||
@ -7,6 +7,7 @@ import SystemUser from './views/system/SystemUser.vue'
|
||||
import SystemRole from './views/system/SystemRole.vue'
|
||||
import SystemConfig from './views/system/SystemConfig.vue'
|
||||
import Article from './views/system/Article.vue'
|
||||
import Statistics from './views/system/Statistics.vue'
|
||||
|
||||
import Music from './views/api/Music.vue'
|
||||
import Hitokoto from './views/api/Hitokoto.vue'
|
||||
@ -20,6 +21,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/system/role', name: 'SystemRole', component: SystemRole },
|
||||
{ path: '/system/config', name: 'SystemConfig', component: SystemConfig },
|
||||
{ path: '/system/article', name: 'Article', component: Article },
|
||||
{ path: '/system/statistics', name: 'Statistics', component: Statistics },
|
||||
|
||||
{ path: '/api/music', name: 'Music', component: Music },
|
||||
{ path: '/api/hitokoto', name: 'Hitokoto', component: Hitokoto },
|
||||
|
||||
8
src/types.ts
Normal file
8
src/types.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Vue } from 'vue-class-component'
|
||||
|
||||
export type VForm = Vue & {
|
||||
validate: (callback: (valid: boolean) => void) => void
|
||||
resetValidation: () => boolean
|
||||
reset: () => void
|
||||
clearValidate: () => void
|
||||
}
|
||||
@ -19,16 +19,15 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Options, Vue } from 'vue-class-component'
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage, ElButton, ElForm, ElFormItem, ElInput, ElTooltip } from 'element-plus'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { VForm } from "../types"
|
||||
|
||||
@Options({
|
||||
name: 'Login',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTooltip }
|
||||
})
|
||||
export default class Login extends Vue {
|
||||
private readonly loginForm: any = ref('loginForm')
|
||||
userInfo: UserInfo = {
|
||||
username: null,
|
||||
password: null
|
||||
@ -45,7 +44,7 @@ export default class Login extends Vue {
|
||||
* 登录
|
||||
*/
|
||||
async login() {
|
||||
this.loginForm.validate(async (valid: boolean) => {
|
||||
(this.$refs.loginForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
const { data } = await this.$http.post<UserInfo, AxiosResponse<any>>('/api/common/login', this.userInfo)
|
||||
if(data.token) {
|
||||
|
||||
@ -67,13 +67,13 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import HitokotoAdd from './HitokotoAdd.vue'
|
||||
import { Options } from 'vue-class-component'
|
||||
import { Options, Vue } from 'vue-class-component'
|
||||
import BaseList from '../../model/baselist'
|
||||
import { Page } from '../../model/common.dto'
|
||||
import HitokotoModel from '../../model/api/hitokoto'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption, ElDatePicker, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import { VForm } from '../../types'
|
||||
|
||||
let selectedData: string[] = []
|
||||
@Options({
|
||||
@ -81,7 +81,6 @@ let selectedData: string[] = []
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption, ElDatePicker, HitokotoAdd }
|
||||
})
|
||||
export default class Hitokoto extends BaseList<HitokotoPage> {
|
||||
private readonly addForm: any = ref('addForm')
|
||||
search = new HitokotoPage()
|
||||
typeList: {label: string, value: string}[] = []
|
||||
hitokotoData: HitokotoModel[] = []
|
||||
@ -97,7 +96,7 @@ export default class Hitokoto extends BaseList<HitokotoPage> {
|
||||
this.hitokotoData = data.data
|
||||
}
|
||||
async save() {
|
||||
this.addForm.$refs.hitokotoForm.validate(async (valid: boolean) => {
|
||||
((this.$refs.addForm as Vue).$refs.hitokotoForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
this.modalLoading = true
|
||||
const { data } = await this.$http.post<any, AxiosResponse<any>>('/api/hitokoto/save', this.formData)
|
||||
|
||||
@ -117,10 +117,9 @@ import BaseList from '../../model/baselist'
|
||||
import { Page } from '../../model/common.dto'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption, ElRadioGroup, ElRadio, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { MusicModel, MusicLibModel, MusicLyricModel, MusicPlayerItem } from '../../model/api/music'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { VForm } from '../../types'
|
||||
|
||||
let selectedIds: string[] = []
|
||||
@Options({
|
||||
@ -128,8 +127,6 @@ let selectedIds: string[] = []
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption, ElRadioGroup, ElRadio }
|
||||
})
|
||||
export default class Music extends BaseList<MusicPage> {
|
||||
// @Ref('player') private readonly player!: APlayerComponent
|
||||
private readonly lyricForm: any = ref('lyricForm')
|
||||
search = new MusicPage()
|
||||
currentRow: MusicModel | null = null
|
||||
exts: string[] = []
|
||||
@ -226,7 +223,7 @@ export default class Music extends BaseList<MusicPage> {
|
||||
}
|
||||
}
|
||||
async saveLyric() {
|
||||
this.lyricForm.validate(async (valid: boolean) => {
|
||||
(this.$refs.lyricForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
this.modalLoading = true
|
||||
const { data } = await this.$http.post<MusicLyricModel, AxiosResponse<any>>(`/api/music/lyric/save?musicId=${this.currentRow ? this.currentRow._id : ''}`, this.lyricFormData)
|
||||
|
||||
@ -34,14 +34,19 @@
|
||||
<div class="btn-container">
|
||||
<el-button type="primary" @click="splitWord" size="small" >分词处理</el-button>
|
||||
<el-button @click="pullArticles" size="small" >拉取文章</el-button>
|
||||
<!-- <Upload :action="($http.defaults.baseURL || '') + '/api/system/deployBlog'"
|
||||
name="blogZip" :show-upload-list="false"
|
||||
:format="allowUploadExt" :headers="uploadHeaders" :max-size="102400"
|
||||
:before-upload="beforeUpload" :on-success="uploadSuccess" @on-error="uploadError"
|
||||
:on-format-error="uploadFormatError" :on-exceeded-size="uploadFileSizeError"
|
||||
style="display: inline-block;">
|
||||
<Button type="primary" icon="ios-cloud-upload-outline">发布博客</Button>
|
||||
</Upload> -->
|
||||
<el-upload
|
||||
action="/api/system/deployBlog"
|
||||
accept=".zip"
|
||||
name="blogZip"
|
||||
:headers="uploadHeaders"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadError"
|
||||
auto-upload
|
||||
:show-file-list="false"
|
||||
style="display: inline-block;margin-left: 10px;">
|
||||
<el-button size="small" type="primary" icon="el-icon-upload" :loading="isUploading">发布博客</el-button>
|
||||
</el-upload>
|
||||
<div class="search-btn">
|
||||
<el-button type="primary" @click="loadDataBase(true)" size="small" icon="el-icon-search">搜索</el-button>
|
||||
<el-button @click="reset" size="small" icon="el-icon-refresh-right">重置</el-button>
|
||||
@ -62,12 +67,12 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="categories" label="分类" width="150" >
|
||||
<template #default="scope">
|
||||
{{ typeof scope.row.categories === 'string' ? scope.row.categories : scope.row.categories.join(',') }}
|
||||
{{ typeof scope.row.categories === 'string' ? scope.row.categories : scope.row.categories?.join(',') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="tags" label="标签" width="180" >
|
||||
<template #default="scope">
|
||||
{{ typeof scope.row.tags === 'string' ? scope.row.tags : scope.row.tags.join(',') }}
|
||||
{{ typeof scope.row.tags === 'string' ? scope.row.tags : scope.row.tags?.join(',') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="content_len" label="正文长度" width="100" />
|
||||
@ -84,18 +89,6 @@
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- <Row :gutter="16">
|
||||
<Col span="4" style="height:520px;overflow:auto;">
|
||||
<Tree :data="articleTree" :load-data="loadTreeData" @on-select-change="articlePreview"></Tree>
|
||||
</Col>
|
||||
<Col span="20" >
|
||||
<div class="table-container">
|
||||
<Table border :loading="loading" :columns="articleColumns" :data="articleData" height="520" @on-selection-change="dataSelect"></Table>
|
||||
</div>
|
||||
</Col>
|
||||
</Row> -->
|
||||
|
||||
|
||||
<div class="page-container">
|
||||
<el-pagination background
|
||||
:page-sizes="$store.state.pageSizeOpts"
|
||||
@ -115,42 +108,38 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// import moment from 'moment'
|
||||
import hyperdown from 'hyperdown'
|
||||
import prismjs from 'prismjs'
|
||||
import 'prismjs/themes/prism.css'
|
||||
import { ArticleModel, TreeNodeData, TreeNodeSource } from '../../model/system/article'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElSelect, ElOption, ElDatePicker, ElRow, ElCol, ElTree, ElDrawer, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElSelect, ElOption, ElDatePicker, ElRow, ElCol, ElTree, ElDrawer, ElUpload, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import Node from 'element-plus/lib/components/tree/src/model/node'
|
||||
import { Options } from 'vue-class-component'
|
||||
import BaseList from '../../model/baselist'
|
||||
import { Page } from '../../model/common.dto'
|
||||
import { Page, MsgResult } from '../../model/common.dto'
|
||||
import { AxiosResponse } from 'axios'
|
||||
|
||||
let selectedData: string[] = []
|
||||
let closeUploadTip: Function | void | null
|
||||
|
||||
@Options({
|
||||
name: 'Article',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElSelect, ElOption, ElDatePicker, ElRow, ElCol, ElTree, ElDrawer }
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElSelect, ElOption, ElDatePicker, ElRow, ElCol, ElTree, ElDrawer, ElUpload }
|
||||
})
|
||||
export default class Article extends BaseList<ArticlePage> {
|
||||
search = new ArticlePage()
|
||||
allowUploadExt = ['zip']
|
||||
uploadHeaders = {token: localStorage.getItem('login_token')}
|
||||
articleData: ArticleModel[] = []
|
||||
tags: string[] = [] // 所有标签
|
||||
categories: string[] = [] // 所有分类
|
||||
markdownPreview :{ // markdown内容预览
|
||||
show?: boolean,
|
||||
title?: string | null,
|
||||
content?: string | null
|
||||
show: boolean,
|
||||
title: string | null,
|
||||
content: string | null
|
||||
} = {
|
||||
show: false,
|
||||
title: null,
|
||||
content: null
|
||||
}
|
||||
|
||||
isUploading: boolean = false
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
const { data } = await this.$http.get<ArticlePage, AxiosResponse<any>>('/api/article/list', {params:this.search})
|
||||
@ -187,43 +176,22 @@ export default class Article extends BaseList<ArticlePage> {
|
||||
dataSelect(selection: ArticleModel[]) {
|
||||
selectedData = selection.map(item => item._id)
|
||||
}
|
||||
// beforeUpload(file: File) {
|
||||
// let filenameCut = undefined
|
||||
// if(file.name.length > 15) {
|
||||
// filenameCut = file.name.substr(0, 15) + '...'
|
||||
// }
|
||||
// closeUploadTip = ElMessage.loading({
|
||||
// content: (filenameCut || file.name) + ' 正在上传,请稍候...',
|
||||
// duration: 0
|
||||
// })
|
||||
// return true
|
||||
// }
|
||||
// uploadFormatError() {
|
||||
// this.closeUploadTip()
|
||||
// ElMessage.error(`只能上传 ${this.allowUploadExt.join('、')} 格式的文件`)
|
||||
// }
|
||||
// uploadFileSizeError() {
|
||||
// this.closeUploadTip()
|
||||
// ElMessage.error(`只能上传不超过100MB的文件`)
|
||||
// }
|
||||
// uploadSuccess(response: MsgResult) {
|
||||
// this.closeUploadTip()
|
||||
// if(response.status) {
|
||||
// ElMessage.success(response.message)
|
||||
// } else {
|
||||
// ElMessage.warning(response.message)
|
||||
// }
|
||||
// }
|
||||
// uploadError() {
|
||||
// this.closeUploadTip()
|
||||
// ElMessage.error('上传失败')
|
||||
// }
|
||||
// closeUploadTip() {
|
||||
// if(typeof closeUploadTip === 'function') {
|
||||
// closeUploadTip.call(this)
|
||||
// closeUploadTip = null
|
||||
// }
|
||||
// }
|
||||
beforeUpload(file: File) {
|
||||
this.isUploading = true
|
||||
return true
|
||||
}
|
||||
uploadSuccess(response: MsgResult) {
|
||||
if(response.status) {
|
||||
ElMessage.success(response.message)
|
||||
} else {
|
||||
ElMessage.warning(response.message)
|
||||
}
|
||||
this.isUploading = false
|
||||
}
|
||||
uploadError() {
|
||||
this.isUploading = false
|
||||
ElMessage.error('上传失败')
|
||||
}
|
||||
readonly treeProps = {
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
|
||||
210
src/views/system/Statistics.vue
Normal file
210
src/views/system/Statistics.vue
Normal file
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="echarts-container">
|
||||
<div ref="categoriesChart" v-loading="categoriesChartLoading"></div>
|
||||
<div ref="publishDatesChart" v-loading="publishDatesChartLoading"></div>
|
||||
<div class="timeline-chart" ref="timelineWordsChart" v-loading="timelineWordsChartLoading"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import * as echarts from 'echarts'
|
||||
import { Options, Vue } from 'vue-class-component'
|
||||
import { AxiosResponse } from 'axios'
|
||||
|
||||
@Options({
|
||||
name: 'Statistics'
|
||||
})
|
||||
export default class Statistics extends Vue {
|
||||
categoriesChartLoading: boolean = false
|
||||
publishDatesChartLoading: boolean = false
|
||||
timelineWordsChartLoading: boolean = false
|
||||
async mounted() {
|
||||
this.categoriesChartLoading = true
|
||||
this.publishDatesChartLoading = true
|
||||
this.timelineWordsChartLoading = true
|
||||
|
||||
const articleData = (await this.$http.get<{params:{type:string}}, AxiosResponse<any>>('/api/article/statistics', {params:{type:'normal'}})).data
|
||||
this.categoriesChartOption.legend.data = articleData.categories.map((item: any) => item._id)
|
||||
this.categoriesChartOption.series.data = articleData.categories.map((item: any) => {
|
||||
return {name: item._id, value: item.cnt}
|
||||
})
|
||||
this.publishDatesChartOption.xAxis.data = articleData.publishDates.map((item: any) => item._id)
|
||||
this.publishDatesChartOption.series.data = articleData.publishDates.map((item: any) => item.cnt)
|
||||
|
||||
const categoriesChart = echarts.init(this.$refs.categoriesChart as HTMLElement)
|
||||
categoriesChart.setOption(this.categoriesChartOption)
|
||||
const publishDatesChart = echarts.init(this.$refs.publishDatesChart as HTMLElement)
|
||||
publishDatesChart.setOption(this.publishDatesChartOption)
|
||||
this.categoriesChartLoading = false
|
||||
this.publishDatesChartLoading = false
|
||||
|
||||
const timelineData = (await this.$http.get<{params:{type:string}}, AxiosResponse<any>>('/api/article/statistics', {params:{type:'timelineWords'}})).data
|
||||
this.timelineWordsChartOption.timeline.data = timelineData.timelineWords.map((item: any) => item._id)
|
||||
timelineData.timelineWords.forEach((item: any) => {
|
||||
this.timelineWordsChartOption.options.push({
|
||||
title: { text: `${item._id}年发布的文章` },
|
||||
xAxis: { data: item.keys.map((keyItem: any) => keyItem.key) },
|
||||
series: { data: item.keys.map((keyItem: any) => keyItem.total) }
|
||||
})
|
||||
})
|
||||
const timelineWordsChart = echarts.init(this.$refs.timelineWordsChart as HTMLElement)
|
||||
timelineWordsChart.setOption(this.timelineWordsChartOption)
|
||||
this.timelineWordsChartLoading = false
|
||||
}
|
||||
|
||||
categoriesChartOption = {
|
||||
title : {
|
||||
text: '文章分类',
|
||||
x: 'center',
|
||||
top: 10
|
||||
},
|
||||
tooltip : {
|
||||
trigger: 'item',
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 50,
|
||||
bottom: 20,
|
||||
data: [],
|
||||
},
|
||||
series: {
|
||||
name: '类别',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
center: ['40%', '50%'],
|
||||
itemStyle: {
|
||||
borderRadius: 5,
|
||||
borderColor: '#FFF',
|
||||
borderWidth: 1
|
||||
},
|
||||
data: []
|
||||
}
|
||||
}
|
||||
publishDatesChartOption = {
|
||||
title: {
|
||||
left: 'center',
|
||||
text: '文章发布时间',
|
||||
top: 10
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
animation: false,
|
||||
label: {
|
||||
backgroundColor: '#ccc',
|
||||
borderColor: '#aaa',
|
||||
borderWidth: 1,
|
||||
shadowBlur: 0,
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 0,
|
||||
color: '#222'
|
||||
}
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
name: '发布时间',
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
name: '文章数量',
|
||||
type: 'value',
|
||||
max: function(value: {max: number}) {
|
||||
return value.max + 10
|
||||
}
|
||||
},
|
||||
dataZoom: [{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100
|
||||
},{
|
||||
start: 0,
|
||||
end: 10
|
||||
}],
|
||||
series: {
|
||||
name: '文章数量',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
sampling: 'average',
|
||||
itemStyle: {
|
||||
color: 'rgb(255, 70, 131)'
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgb(255, 158, 68)'
|
||||
},{
|
||||
offset: 1,
|
||||
color: 'rgb(255, 70, 131)'
|
||||
}
|
||||
])
|
||||
},
|
||||
data: []
|
||||
}
|
||||
}
|
||||
timelineWordsChartOption: any = {
|
||||
options: [],
|
||||
timeline: {
|
||||
axisType: 'category',
|
||||
autoPlay: false,
|
||||
playInterval: 1000,
|
||||
data: [],
|
||||
},
|
||||
title: {
|
||||
left: 'center',
|
||||
subtext: '数据来自文章分词结果'
|
||||
},
|
||||
calculable : true,
|
||||
grid: {
|
||||
top: 80,
|
||||
bottom: 80
|
||||
},
|
||||
xAxis: {
|
||||
name: '高频词汇',
|
||||
type: 'category',
|
||||
splitLine: {show: false}
|
||||
},
|
||||
yAxis: {
|
||||
name: '词汇出现次数',
|
||||
type: 'value'
|
||||
},
|
||||
tooltip : {
|
||||
trigger: 'axis',
|
||||
axisPointer : { // 坐标轴指示器,坐标轴触发有效
|
||||
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
},
|
||||
series: {
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
borderRadius: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.echarts-container {
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-template-rows: 50% 50%;
|
||||
height: 100%;
|
||||
> .echarts {
|
||||
border: 1px solid #ccc;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.timeline-chart {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 3;
|
||||
}
|
||||
</style>
|
||||
@ -59,17 +59,16 @@
|
||||
import { Options, Vue } from 'vue-class-component'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElDialog, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import moment from 'moment'
|
||||
import SystemConfigAdd from './SystemConfigAdd.vue'
|
||||
import { SystemConfigModel } from '../../model/system/system-config'
|
||||
import { VForm } from '../../types'
|
||||
|
||||
@Options({
|
||||
name: 'SystemConfig',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElDialog, SystemConfigAdd }
|
||||
})
|
||||
export default class SystemConfig extends Vue {
|
||||
private readonly addForm: any = ref('addForm')
|
||||
modalLoading: boolean = false
|
||||
loading: boolean = false
|
||||
search: {name?:string} = {}
|
||||
@ -111,7 +110,7 @@ export default class SystemConfig extends Vue {
|
||||
this.addModal = true
|
||||
}
|
||||
async save() {
|
||||
this.addForm.$refs.configForm.validate(async (valid: boolean) => {
|
||||
((this.$refs.addForm as Vue).$refs.configForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
this.modalLoading = true
|
||||
const { data } = await this.$http.post<SystemConfigModel, AxiosResponse<any>>('/api/system/config/save', this.formData)
|
||||
@ -137,7 +136,7 @@ export default class SystemConfig extends Vue {
|
||||
}
|
||||
clearValidate() {
|
||||
this.$nextTick(() => {
|
||||
this.addForm.$refs.configForm.clearValidate()
|
||||
((this.$refs.addForm as Vue).$refs.configForm as VForm).clearValidate()
|
||||
})
|
||||
}
|
||||
/**
|
||||
|
||||
@ -97,14 +97,13 @@ import { Page } from '../../model/common.dto'
|
||||
import { SystemRoleModel } from '../../model/system/system-role'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElTag, ElPagination, ElDialog, ElSelect, ElOption, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import { VForm } from '../../types'
|
||||
|
||||
@Options({
|
||||
name: 'SystemRole',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElTag, ElPagination, ElDialog, ElSelect, ElOption }
|
||||
})
|
||||
export default class SystemRole extends BaseList<SystemRolePage> {
|
||||
private readonly roleForm: any = ref('roleForm')
|
||||
ruleValidate = {
|
||||
name: [
|
||||
{ required: true, message: '请输入角色名称', trigger: 'blur' }
|
||||
@ -192,7 +191,7 @@ export default class SystemRole extends BaseList<SystemRolePage> {
|
||||
}).catch(() => {})
|
||||
}
|
||||
async save() {
|
||||
this.roleForm.validate(async (valid: boolean) => {
|
||||
(this.$refs.roleForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
this.modalLoading = true
|
||||
const { data } = await this.$http.post<SystemRoleModel, AxiosResponse<any>>('/api/system/role/save', this.formData)
|
||||
@ -204,7 +203,7 @@ export default class SystemRole extends BaseList<SystemRolePage> {
|
||||
}
|
||||
clearValidate() {
|
||||
this.$nextTick(() => {
|
||||
this.roleForm.clearValidate()
|
||||
(this.$refs.roleForm as VForm).clearValidate()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,14 +77,13 @@ import { SystemUserModel } from '../../model/system/system-user'
|
||||
import { SystemRoleModel } from '../../model/system/system-role'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import { VForm } from '../../types'
|
||||
|
||||
@Options({
|
||||
name: 'SystemUser',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElDialog, ElSelect, ElOption }
|
||||
})
|
||||
export default class SystemUser extends BaseList<SystemUserPage> {
|
||||
private readonly userForm: any = ref('userForm')
|
||||
get ruleValidate() {
|
||||
return {
|
||||
username: [
|
||||
@ -148,8 +147,7 @@ export default class SystemUser extends BaseList<SystemUserPage> {
|
||||
this.clearValidate()
|
||||
}
|
||||
async save() {
|
||||
console.log(this.userForm)
|
||||
this.userForm.validate(async (valid: boolean) => {
|
||||
(this.$refs.userForm as VForm).validate(async (valid: boolean) => {
|
||||
if(!valid) return
|
||||
this.modalLoading = true
|
||||
const { data } = await this.$http.post<SystemUserModel, AxiosResponse<any>>('/api/system/user/save', this.formData)
|
||||
@ -178,7 +176,7 @@ export default class SystemUser extends BaseList<SystemUserPage> {
|
||||
}
|
||||
clearValidate() {
|
||||
this.$nextTick(() => {
|
||||
this.userForm.clearValidate()
|
||||
(this.$refs.userForm as VForm).clearValidate()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,14 +23,12 @@
|
||||
<script lang="ts">
|
||||
import { Options, Vue } from 'vue-class-component'
|
||||
import { ElForm, ElFormItem, ElInput, ElButtonGroup, ElButton, ElMessage } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@Options({
|
||||
name: 'SqlReplace',
|
||||
components: { ElForm, ElFormItem, ElInput, ElButtonGroup, ElButton }
|
||||
})
|
||||
export default class SqlReplace extends Vue {
|
||||
private readonly inputInstance: any = ref('resultInput')
|
||||
sql: string = ''
|
||||
params: string = ''
|
||||
replaceResult: string = ''
|
||||
@ -57,7 +55,7 @@ export default class SqlReplace extends Vue {
|
||||
}
|
||||
this.replaceResult = sql
|
||||
Promise.resolve('已复制到剪贴板').then(message => {
|
||||
this.inputInstance.select()
|
||||
(this.$refs.resultInput as HTMLInputElement).select()
|
||||
if (document.execCommand('copy')) {
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
|
||||
@ -27,6 +27,8 @@ export default defineConfig({
|
||||
manualChunks(id) {
|
||||
if (id.includes('element-plus')) {
|
||||
return 'element-plus'
|
||||
} else if(id.includes('echarts')) {
|
||||
return 'echarts'
|
||||
} else if(id.includes('node_modules')) {
|
||||
return 'vendor'
|
||||
}
|
||||
|
||||
20
yarn.lock
20
yarn.lock
@ -342,6 +342,14 @@ domutils@^2.5.2:
|
||||
domelementtype "^2.2.0"
|
||||
domhandler "^4.2.0"
|
||||
|
||||
echarts@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.2.1.tgz#bd58ec011cd82def4a714e4038ef4b73b8417bc3"
|
||||
integrity sha512-OJ79b22eqRfbSV8vYmDKmA+XWfNbr0Uk/OafWcFNIGDWti2Uw9A6eVCiJLmqPa9Sk+EWL+t5v26aak0z3gxiZw==
|
||||
dependencies:
|
||||
tslib "2.3.0"
|
||||
zrender "5.2.1"
|
||||
|
||||
element-plus@^1.1.0-beta.19:
|
||||
version "1.1.0-beta.19"
|
||||
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.1.0-beta.19.tgz#234f3bc3f1d822a7102045e7ee1239b675f27acc"
|
||||
@ -938,6 +946,11 @@ token-stream@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4"
|
||||
integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=
|
||||
|
||||
tslib@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||
|
||||
tslib@^1.10.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
@ -1182,3 +1195,10 @@ yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
zrender@5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.2.1.tgz#5f4bbda915ba6d412b0b19dc2431beaad05417bb"
|
||||
integrity sha512-M3bPGZuyLTNBC6LiNKXJwSCtglMp8XUEqEBG+2MdICDI3d1s500Y4P0CzldQGsqpRVB7fkvf3BKQQRxsEaTlsw==
|
||||
dependencies:
|
||||
tslib "2.3.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user