no message

This commit is contained in:
小陌 2023-06-26 19:06:05 +08:00
parent 968393aff6
commit 890e54792a
8 changed files with 205 additions and 261 deletions

View File

@ -48,6 +48,10 @@
<template v-else-if="item.component=='upload'">
<sc-upload v-model="form[item.name]" :cropper="item.options.cropper || false" :compress="1" :aspectRatio="item.options.aspectRatio || 1/1" :width="item.options.width || 148" :height="item.options.height || 148"></sc-upload>
</template>
<!-- updatemultiple -->
<template v-else-if="item.component=='updatemultiple'">
<sc-upload-multiple v-model="form[item.name]" draggable :width="item.options.width || 120" :height="item.options.height || 90" :limit="item.options.limit || 20" :tip="item.options.tip ||''"></sc-upload-multiple>
</template>
<!-- switch -->
<template v-else-if="item.component=='switch'">
<el-switch v-model="form[item.name]" :active-value="item.options.activevalue || 1" :inactive-value="item.options.inactivevalue || 0" />
@ -97,7 +101,11 @@
<sc-editor v-model="form[item.name]" placeholder="请输入" :height="400"></sc-editor>
</template>
<template v-else-if="item.component=='text'">
<el-link type="info">{{ form[item.name] }}</el-link>
<el-link type="info" :underline="false">{{ form[item.name] }}</el-link>
</template>
<template v-else-if="item.component=='avatar'">
<el-avatar :src="form[item.name]" size="small"></el-avatar>
<el-link v-if="item.options.subfield" type="info" style="padding: 0 10px;" :underline="false">{{ form[item.options.subfield] }}</el-link>
</template>
<template v-else-if="item.component=='formtable'">
<sc-form-table drag-sort="" placeholder="暂无数据" ref="videostable" :addTemplate="item.options.addTemplate || {}" :column="item.options.column || []" v-model="form[item.name]" :hideAdd="item.options.hideAdd || true" :hideDelete="item.options.hideDelete || true">

View File

@ -6,8 +6,15 @@
<template v-for="(item, index) in column" :key="index">
<el-table-column v-if="!item.hide && item.name" :column-key="item.name" :label="item.label" :prop="item.name" :width="item.width || 150" :sortable="item.sortable" :fixed="item.fixed" :filters="item.filters" :filter-method="remoteFilter||!item.filters?null:filterHandler" :show-overflow-tooltip="item.showOverflowTooltip">
<template #default="scope">
<el-avatar v-if="item.columntype=='avatar'" :src="scope.row[item.name]" size="small"></el-avatar>
<div style="display: flex;align-items: center;" v-if="item.columntype=='avatar'">
<el-avatar :src="scope.row[item.name]" size="small"></el-avatar>
<label v-if="item.options.subfield" style="display: inline-block;margin-left:5px;font-size: 12px;cursor:pointer;">
{{ scope.row[item.options.subfield] }}
</label>
</div>
<el-badge v-else-if="item.columntype=='badge'" :value="scope.row[item.name]" :type="item.options.type || 'warning'"></el-badge>
<el-badge v-else-if="item.columntype=='imagegroup'" :value="scope.row[item.name].length" :type="item.options.type || 'warning'"></el-badge>
<el-image v-else-if="item.columntype=='image'" hide-on-click-modal="true" lazy="true" style="width: 30px; height: 30px" fit="cover" :src="getImg(scope.row[item.name])">
<template #error>
<div class="image-slot">
@ -90,6 +97,7 @@
size: { type: String, default: "default" },
border: { type: Boolean, default: false },
stripe: { type: Boolean, default: false },
columnSetting: { type: Boolean, default: false },
pageSize: { type: Number, default: config.pageSize },
pageSizes: { type: Array, default: config.pageSizes },
rowKey: { type: String, default: "" },
@ -145,7 +153,6 @@
tableHeight:'100%',
tableParams: this.params,
column: [],
columnSetting: false,
customColumnShow: false,
summary: {},
config: {
@ -175,12 +182,10 @@
},
methods: {
getImg(o){
if (!o) {
return ;
}
return typeof o === 'string'?o: o.url;
return typeof o === 'string'? o : o.url;
},
//
async getData(){
@ -213,7 +218,7 @@
this.emptyText = response.message;
}else{
this.emptyText = "暂无数据";
this.tableData = (this.hidePagination? response.data:response.rows) || [];
this.tableData = (this.hidePagination? response.data : response.rows) || [];
this.total = response.total || 0;
this.summary = response.summary || {};
this.loading = false;

View File

@ -6,7 +6,7 @@
<div class="screen panel-item hidden-sm-and-down" @click="screen">
<el-icon><el-icon-full-screen /></el-icon>
</div>
<div class="tasks panel-item" @click="tasks">
<!-- <div class="tasks panel-item" @click="tasks">
<el-icon><el-icon-sort /></el-icon>
</div>
<div class="msg panel-item" @click="showMsg">
@ -44,7 +44,7 @@
</el-footer>
</el-container>
</el-drawer>
</div>
</div> -->
<el-dropdown class="user panel-item" trigger="click" @command="handleUser">
<div class="user-avatar">
<el-avatar :size="30" :src="avatar">{{ username }}</el-avatar>

View File

@ -83,9 +83,9 @@ var http = {
get: function(url, params = {}, config = {}) {
return new Promise((resolve, reject) => {
// 缓存存在, 优先使用缓存
const cacheKey = '';
var cacheKey = '';
if (typeof config.cache !== 'undefined' && !isNaN(config.cache) && config.cache > 0) {
let cacheKey = tool.crypto.MD5(url);
cacheKey = tool.crypto.MD5(url + (new URLSearchParams(params)).toString());
const cachedData = tool.data.get(cacheKey);
if (cachedData) {
return resolve(cachedData);
@ -97,7 +97,7 @@ var http = {
params: params,
...config
}).then((response) => {
if (cacheKey) {
if (cacheKey && typeof config.cache !== 'undefined' && !isNaN(config.cache) && config.cache > 0) {
tool.data.set(cacheKey, response.data, config.cache);
}
resolve(response.data);

View File

@ -55,9 +55,12 @@
<el-form-item label="整页路由" prop="fullpage">
<el-switch v-model="form.meta.fullpage" />
</el-form-item>
<el-form-item label="表单名称" prop="fullpage">
<el-form-item label="表单名称" prop="tablename">
<el-input v-model="form.meta.tablename" clearable placeholder="表单名称,读取配置及表头"></el-input>
</el-form-item>
<el-form-item label="表头缓存" prop="tablecache">
<el-input v-model="form.meta.tablecache" clearable placeholder="表头缓存时间,留空不缓存"></el-input>
</el-form-item>
<el-form-item label="标签" prop="tag">
<el-input v-model="form.meta.tag" clearable placeholder=""></el-input>
</el-form-item>

View File

@ -1,107 +1,32 @@
<template>
<el-container>
<el-header>
<el-header v-if="this.date || dateGroup.length>0">
<div class="left-panel">
<el-radio-group v-model="dateType" style="margin-right: 15px;">
<el-radio-button label="今天"></el-radio-button>
<el-radio-button label="昨天"></el-radio-button>
<el-radio-button label="最近7天"></el-radio-button>
<el-radio-button label="最近30天"></el-radio-button>
<el-radio-group v-model="dateType" v-if="dateGroup.length>0" @change="changedateGroup" style="margin-right: 15px;">
<el-radio-button v-for="item in dateGroup" :key="item.value" :label="item.text" :name="item.value"></el-radio-button>
</el-radio-group>
<el-date-picker v-model="date" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
<el-date-picker v-if="this.date" @change="changedate" format="YYYY-MM-DD HH:mm" v-model="date" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</div>
</el-header>
<el-main>
<el-card shadow="never">
<el-card shadow="never" v-if="statistic.length>0">
<div class="number-data">
<div class="item">
<h2>浏览量(PV)
<el-tooltip effect="light">
<template #content>
<div style="width: 200px;line-height: 2;">
即通常说的Page View(PV)用户每打开一个网站页面就被记录1次用户多次打开同一页面浏览量值累计
</div>
</template>
<el-icon><el-icon-question-filled /></el-icon>
</el-tooltip>
</h2>
<p>65,715</p>
</div>
<div class="item">
<h2>访客数(UV)
<el-tooltip effect="light">
<template #content>
<div style="width: 200px;line-height: 2;">
一天之内您网站的独立访客数(以Cookie为依据)一天内同一访客多次访问您网站只计算1个访客
</div>
</template>
<el-icon><el-icon-question-filled /></el-icon>
</el-tooltip>
</h2>
<p>8,936</p>
</div>
<div class="item">
<h2>IP数
<el-tooltip effect="light">
<template #content>
<div style="width: 200px;line-height: 2;">
一天之内您网站的独立访问ip数
</div>
</template>
<el-icon><el-icon-question-filled /></el-icon>
</el-tooltip>
</h2>
<p>10,279</p>
</div>
<div class="item">
<h2>跳出率
<el-tooltip effect="light">
<template #content>
<div style="width: 200px;line-height: 2;">
只浏览了一个页面便离开了网站的访问次数占总的访问次数的百分比
</div>
</template>
<el-icon><el-icon-question-filled /></el-icon>
</el-tooltip>
</h2>
<p>27.92%</p>
</div>
<div class="item">
<h2>平均访问时长
<el-tooltip effect="light">
<template #content>
<div style="width: 200px;line-height: 2;">
访客在一次访问中平均打开网站的时长即每次访问中打开第一个页面到关闭最后一个页面的平均值打开一个页面时计算打开关闭的时间差
</div>
</template>
<el-icon><el-icon-question-filled /></el-icon>
</el-tooltip>
</h2>
<p>00:19:05</p>
<div class="item" v-for="(s, index) in statistic" :key="index">
<sc-statistic :title="s.title" :value="s.value" :description="s.description" :tips="s.tips" groupSeparator>
<sc-trend v-model="s.trend" v-if="s.trend"></sc-trend>
</sc-statistic>
</div>
</div>
<div class="chart">
<div class="chart" v-if="chartList.length>0">
<el-row>
<el-col :span="8">
<scEcharts height="250px" :option="pie"></scEcharts>
</el-col>
<el-col :span="16">
<scEcharts height="250px" :option="option"></scEcharts>
<el-col :span="c.span || 12" v-for="(c,index) in chartList" :key="index">
<scEcharts :height=" c.height ? Number(c.height)?Number(c.height)+'px':c.height : '250px'" :option="c.option"></scEcharts>
</el-col>
</el-row>
</div>
</el-card>
<el-card shadow="never">
<scTable ref="table" :data="data" show-summary height="auto">
<el-table-column label="来源类型" prop="type"></el-table-column>
<el-table-column label="网站基础指标" align="center">
<el-table-column label="访客数(UV)" prop="uv" width="150"></el-table-column>
<el-table-column label="IP数" prop="ip" width="150"></el-table-column>
</el-table-column>
<el-table-column label="流量质量指标" align="center">
<el-table-column label="跳出率" prop="out" width="150"></el-table-column>
<el-table-column label="平均访问时长" prop="time" width="150"></el-table-column>
</el-table-column>
<el-card shadow="never" v-if="table && table.column.length>0">
<scTable ref="table" :data="table.data" :api="table.api" :tableColumn="table.column" :hideDo="table.hideDo || true" :hidePagination="table.hidePagination || true" show-summary :height="table.height || 'auto'">
</scTable>
</el-card>
</el-main>
@ -110,112 +35,92 @@
<script>
import scEcharts from '@/components/scEcharts';
import scStatistic from '@/components/scStatistic';
export default {
name: 'chartlist',
components: {
scEcharts
scEcharts,
scStatistic,
},
data(){
return {
dateType: "今天",
date: [new Date(2000, 10, 10, 10, 10), new Date(2000, 10, 11, 10, 10)],
data: [
{
type: "直接访问",
pv: "57,847",
uv: "7,129",
ip: "8,330",
out: "26.38%",
time: "00:20:35"
},
{
type: "搜索引擎",
pv: "5,942",
uv: "1,338",
ip: "1,449",
out: "33.49%",
time: "00:11:31"
},
{
type: "外部链接",
pv: "1,926",
uv: "469",
ip: "500",
out: "44.53%",
time: "00:08:49"
}
dateGroup: [
],
pie: {
tooltip: {
trigger: 'item'
chartList: [
],
statistic: [
],
table: {
api:null,
height:0,
data:[],
column:[],
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['55%', '70%'],
itemStyle: {
borderRadius: 5,
borderColor: '#fff',
borderWidth: 1
},
data: [
{value: 1048, name: '搜索引擎'},
{value: 235, name: '直接访问'},
{value: 180, name: '外部链接'}
]
dateType: '',
date: null,
}
]
},
option: {
legend: {
data: ['直接访问', '搜索引擎', '外部链接']
watch: {
//props
date(){
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00'],
boundaryGap: false,
mounted() {
const now = new Date();
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
lastDay.setHours(23, 59, 0, 0);
this.date = [new Date(now.getFullYear(), now.getMonth(), 1, 0, 0), lastDay];
this.loaddata();
},
yAxis: {
type: 'value'
methods: {
changedateGroup(){
this.dateGroup.forEach((item) => {
if (this.dateType === item.text) {
this.date = item.value;
this.loaddata();
}
})
},
series: [{
name: '直接访问',
data: [120, 210, 150, 80, 70, 110, 130],
type: 'line',
changedate(){
this.loaddata()
},
{
name: '搜索引擎',
data: [110, 180, 120, 120, 60, 90, 110],
type: 'line',
},
{
name: '外部链接',
data: [50, 90, 60, 60, 30, 40, 50],
type: 'line',
}]
loaddata(){
//
if(this.$route.meta.tablename) {
this.$http.get('system/stat/get', { name: this.$route.meta.tablename,date:this.date }, { cache:this.$route.meta.tablecache || 0 }).then((res) => {
if (res.code == 200) {
Object.assign(this.$data, res.data);
this.dateType = '';
this.dateGroup.forEach((item) => {
if (new Date(item.value[0]).getTime()==new Date(this.date[0]).getTime() && new Date(item.value[1]).getTime()==new Date(this.date[1]).getTime()) {
this.dateType = item.text;
}
})
}
});
}
}
}
}
</script>
<style scoped>
.el-card {margin-bottom: 15px;}
.number-data {display: flex;}
.number-data .item {flex:1;border-right: 1px solid #f0f0f0;padding:0 20px;}
.number-data .item:last-child {border: 0;}
.number-data .item h2 {font-size: 12px;color: #787a7d;font-weight: normal;display: flex;align-items: center;}
.number-data .item h2 i {margin-left: 5px;color: #8cc5ff;cursor: pointer;}
.number-data .item p {font-size: 20px;color: #121315;margin-top: 10px;}
.chart {border-top: 1px solid #f0f0f0;margin-top: 20px;padding-top: 20px;}
.dark .number-data .item {border-color: var(--el-border-color-light);}
.dark .number-data .item p {color: #d0d0d0;}
.dark .chart {border-color: var(--el-border-color-light);}

View File

@ -2,31 +2,31 @@
<el-container>
<el-header class="header-tabs" v-if="tabs.length>0">
<el-tabs type="card" v-model="search.status" @tab-change="tabChange">
<el-tab-pane v-for="item in tabs" :key="item.value" :label="item.label"> </el-tab-pane>
<el-tab-pane v-for="item in tabs" :key="item.value" :label="item.label" :name="item.value"> </el-tab-pane>
</el-tabs>
</el-header>
<el-header v-if="operation.plus || operation.batchdeletion || operation.search">
<div class="left-panel">
<el-button v-if="operation.plus" type="primary" icon="el-icon-plus" @click="add"></el-button>
<el-button v-if="operation.batchdeletion" type="danger" plain icon="el-icon-delete"></el-button>
<el-button v-if="operation.plus" type="primary" icon="el-icon-plus" @click="plus"></el-button>
<el-button v-if="operation.batchdeletion" type="danger" @click="batchdeletion" plain icon="el-icon-delete"></el-button>
</div>
<div class="right-panel" v-if="operation.search">
<div class="right-panel-search">
<el-input v-model="search.keyword" placeholder="关键词" clearable></el-input>
<el-input v-model="search.keyword" :placeholder="operation.search.placeholder || '请输入关键词'" clearable></el-input>
<el-button type="primary" icon="el-icon-search" @click="upsearch"></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :tableColumn="column" :api="api" row-key="id" @selection-change="selectionChange" :remoteSort="true" :remoteFilter="true" stripe>
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column min-width="1" label="操作" :width="(Object.keys(operation).length*50)+22" fixed="right" align="left" v-if="Object.keys(operation).length>0">
<scTable ref="table" :tableColumn="column" :params="search" :columnSetting="columnSetting" :api="api" :row-key="key" @selection-change="selectionChange" :remoteSort="true" :remoteFilter="true" stripe>
<el-table-column v-if="isselection" type="selection" width="50"></el-table-column>
<el-table-column :label="operation.label || '操作'" :width="operation.width || 120" :fixed="operation.fixed || 'right'" :align="operation.align || 'left'" v-if="operation.edit || operation.delete">
<template #default="scope">
<el-button-group>
<el-button v-if="operation.edit" type="primary" size="small" @click="table_edit(scope.row, scope.$index)">{{ operation.edit.name || '编辑' }}</el-button>
<el-popconfirm v-if="operation.delete" :title="operation.delete.title || '确定删除吗?'" @confirm="table_del(scope.row, scope.$index)">
<el-button v-if="operation.edit" :type="operation.edit.type || 'primary'" :size="operation.edit.size || 'small'" @click="operationEdit(scope.row, scope.$index)">{{ operation.edit.name || '编辑' }}</el-button>
<el-popconfirm v-if="operation.delete" :title="operation.delete.title || '确定删除吗?'" @confirm="operationDelete(scope.row, scope.$index)">
<template #reference>
<el-button type="info" size="small">{{ operation.delete.name || '删除' }}</el-button>
<el-button :type="operation.delete.type || 'info'" :size="operation.delete.size || 'small'">{{ operation.delete.name || '删除' }}</el-button>
</template>
</el-popconfirm>
</el-button-group>
@ -51,6 +51,8 @@
dialog: {
save: false,
},
columnSetting:false,
isselection:true,
selection: [],
column: [],
api: '',
@ -66,16 +68,14 @@
}
},
mounted() {
//
if(this.$route.meta.tablename) {
this.$http.get('system/table/get', { name: this.$route.meta.tablename }, { cache:0 }).then((res) => {
this.$http.get('system/table/get', { name: this.$route.meta.tablename }, { cache: this.$route.meta.tablecache || 0 }).then((res) => {
if (res.code == 200) {
Object.assign(this.$data, res.data);
}
});
}
},
methods: {
//
@ -87,58 +87,83 @@
this.$refs.table.reload(this.search)
},
//
add(){
plus(){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveDialog.open()
if (this.operation.plus.remoteurl) {
setTimeout(async ()=>{
var res = await this.$http.get(this.operation.plus.remoteurl)
if (res.code == 200 ) {
this.$refs.saveDialog.open('plus').setData(res.data);
return;
}
this.$alert(res.message, "提示", {type: 'error'});
}, 100)
return false;
}
this.$refs.saveDialog.open();
})
},
//
table_edit(row){
operationEdit(row,index){
this.dialog.save = true
this.$nextTick(() => {
if (this.operation.edit.remoteurl) {
setTimeout(async ()=>{
var res = await this.$http.get(this.operation.edit.remoteurl, {id: row[this.key]})
var res = await this.$http.get(this.operation.edit.remoteurl, {[this.key]: row[this.key], index: index})
if (res.code == 200 ) {
this.$refs.saveDialog.open('edit').setData(res.data);
return;
}
this.$alert(res.message, "提示", {type: 'error'});
}, 100)
}else{
this.$refs.saveDialog.open('edit').setData(row)
return false;
}
this.$refs.saveDialog.open('edit').setData(row)
})
},
//
async table_del(row, index){
var reqData = {id: row.id}
var res = await this.$api.demo.post.post(reqData);
if(res.code == 200){
// OR /
async operationDelete(row, index){
var res = await this.$http.post(this.operation.delete.url, {[this.key]: row[this.key], index: index})
if (res.code == 200 ) {
this.$refs.table.tableData.splice(index, 1);
this.$message.success("删除成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
return;
}
this.$alert(res.message, "提示", {type: 'error'});
},
//
async batch_del(){
async batchdeletion(){
if (this.selection.length==0) {
this.$alert('请勾选你要删除的项目', "提示", {type: 'error'});
return;
}
if (!this.operation.batchdeletion.url) {
this.$alert('没有批量删除相关配置', "提示", {type: 'error'});
return;
}
this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?`, '提示', {
type: 'warning'
}).then(() => {
const loading = this.$loading();
this.selection.forEach(item => {
const ids = this.selection.map(obj => obj[this.key]);
this.$http.post(this.operation.batchdeletion.url, {[this.key]: ids}).then((res) => {
if (res.code == 200 ) {
this.$refs.table.tableData.forEach((itemI, indexI) => {
if (item.id === itemI.id) {
if (ids.includes(itemI[this.key])) {
this.$refs.table.tableData.splice(indexI, 1)
}
})
})
this.$message.success(res.message || "操作成功")
return;
}
this.$alert(res.message, "提示", {type: 'error'});
loading.close();
this.$message.success("操作成功")
})
}).catch(() => {
})
@ -151,29 +176,38 @@
handleSuccess(data, mode){
// var res = await this.$api.demo.post.post(this.form);
// this.isSaveing = false;
// if(res.code == 200){
if (!this.operation.edit.url) {
this.$alert('没有编辑相关配置', "提示", {type: 'error'});
return;
}
// this.visible = false;
// this.$message.success("")
// }else{
// this.$alert(res.message, "", {type: 'error'})
// }
this.$http.post(this.operation.edit.url, {type:mode, info:data}).then((res) => {
if (res.code == 200 ) {
if(mode=='add'){
data.id = new Date().getTime()
this.$refs.table.tableData.unshift(data)
if(mode=='plus'){
if (res.data) {
this.$refs.table.tableData.unshift(res.data)
}else{
this.$refs.table.reload({})
}
}else if(mode=='edit'){
if (res.data) {
this.$refs.table.tableData.filter(item => item.id===data.id ).forEach(item => {
Object.assign(item, data, res.data)
})
}else{
this.$refs.table.refresh()
}
}
this.$refs.saveDialog.isSaveing = false;
this.$refs.saveDialog.visible = false;
this.$refs.table.tableData.filter(item => item.id===data.id ).forEach(item => {
Object.assign(item, data)
})
this.$message.success(res.message || "操作成功")
return;
}
this.$alert(res.message, "提示", {type: 'error'});
})
}
}
}

View File

@ -13,7 +13,7 @@
</template>
<style type="text/css">
/*.el-dialog__body{padding: 0px}*/
</style>
<script>
@ -25,20 +25,14 @@
data() {
return {
loading: false,
mode: "add",
mode: "plus",
titleMap: {
add: '新增',
plus: '新增',
edit: '编辑'
},
info: {},
visible: false,
isSaveing: false,
selectionFilters: [],
filtersAddTemplate: {
text: '',
value: ''
},
setFiltersVisible: false
}
},
watch: {
@ -65,7 +59,7 @@
submit(){
this.$refs.formref.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
// this.isSaveing = true;
this.$emit('success', this.info, this.mode);
}
})
@ -74,11 +68,6 @@
setData(info){
this.info = info;
},
//
setFilters(filters){
this.selectionFilters = filters
this.setFiltersVisible = true
}
}
}
</script>