Commit 7aef0de6 by 李君

等待时长统计,报警规则优化

1 parent 07305494
......@@ -96,7 +96,7 @@ const queueManagementApi = {
return req('POST', `/d-cashier-alarm-rule`, params, config)
},
updateAlarmRules(params, config) {
return req('PUT', `/d-cashier-alarm-rule/${params.id}`, params, config)
return req('PUT', `/d-cashier-alarm-rule`, params, config)
},
// 排队详情
getqueueDetailList(params, config) {
......@@ -106,6 +106,9 @@ const queueManagementApi = {
getExitClosedList(params, config) {
return req('get', `/queuing/counters/exit/closed`, params, config)
},
getDistributeList(params, config) {
return req('get', `/queuing/waitTime/distribute`, params, config)
},
}
......
......@@ -105,6 +105,13 @@ const queueManagementRouterMap = {
permissionPath: 'exitFormClosedCounters'
},
component: () => import('@/views/queueManagement/exitFormClosedCounters/'),
},{
name: 'waitingTimeStatistics',
path: '/queueManagement/waitingTimeStatistics',
meta: {
permissionPath: 'waitingTimeStatistics'
},
component: () => import('@/views/queueManagement/waitingTimeStatistics/'),
},
]
......
......@@ -2,22 +2,24 @@
<div>
<el-dialog :title="$t('button.alarmRules')" class="manage-dialog dialog_lj" :visible.sync="addDialogVisible"
:close-on-click-modal="false" v-if="addDialogVisible" @close="addDialogClose()">
<el-form :model="addForm" label-width="120px" status-icon :rules="rules" ref="addForm">
<!-- 区域名称 -->
<!-- <p class="itemTitle">{{$t('button.alarmRules')}}</p> -->
<!-- <el-form-item >
<el-checkbox v-model="addForm.queueLengthSwitch">{{$t('table.queueLengthAlert')}}</el-checkbox>
<el-checkbox v-model="addForm.waitTimeSwitch">{{$t('table.waitTimeAlert')}}</el-checkbox>
</el-form-item> -->
<el-form-item :label="$t('table.alarmPensonNum')" prop="queueLengthThreshold">
<el-input-number v-model="addForm.queueLengthThreshold" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.perNum')}}
</el-form-item>
<el-form-item :label="$t('table.waitingTime')" prop="waitTimeThreshold">
<el-input-number v-model="addForm.waitTimeThreshold" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.minute')}}
</el-form-item>
<el-form-item :label="$t('table.alarmCycle')" prop="alarmInterval">
<el-input-number v-model="addForm.alarmInterval" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.minute')}}
</el-form-item>
<el-form :model="addForm" label-width="100px" status-icon :rules="rules" ref="addForm">
<div class="inlineBlock" v-for="item in counterTypeData" :key="item.id">
<template v-if="item.key != '4'">
<p class="itemTitle" style="font-weight: 900">{{item.text}}</p>
<el-form-item :label="$t('table.alarmPensonNum')" prop="queueLengthThreshold">
<el-input-number v-model="item.queueLengthThreshold" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.perNum')}}
</el-form-item>
<el-form-item :label="$t('table.waitingTime')" prop="waitTimeThreshold">
<el-input-number v-model="item.waitTimeThreshold" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.minute')}}
</el-form-item>
<el-form-item label="Trolle No." prop="trolleyThreshold">
<el-input-number v-model="item.trolleyThreshold" :min="0" :controls = 'false' :precision = '0'></el-input-number>
</el-form-item>
<el-form-item :label="$t('table.alarmCycle')" prop="alarmInterval">
<el-input-number v-model="item.alarmInterval" :min="0" :controls = 'false' :precision = '0'></el-input-number> {{$t('format.minute')}}
</el-form-item>
</template>
</div>
<p class="info">{{$t('message.alarmInfo')}}</p>
<p class="itemTitle">{{$t('table.alarmReceiver')}}</p>
<div v-for="(item,index) in alarmReceiverList" :key='index' style="margin-top: 10px;">
......@@ -43,46 +45,44 @@ export default {
addDialogVisible: false,
addForm: {
},
counterTypeData: [],
alarmReceiverList:[{
email:''
}],
isAdd:true,
rules: {
queueLengthThreshold: [{
required: true,
message: this.$t('pholder.input'),
trigger: 'blur'
}],
waitTimeThreshold:[{
required: true,
message: this.$t('pholder.input'),
trigger: 'blur'
}],
alarmInterval:[{
required: true,
message: this.$t('pholder.input'),
trigger: 'blur'
}],
// queueLengthThreshold: [{
// required: true,
// message: this.$t('pholder.input'),
// trigger: 'blur'
// }],
// waitTimeThreshold: [{
// required: true,
// message: this.$t('pholder.input'),
// trigger: 'blur'
// }],
// alarmInterval:[{
// required: true,
// message: this.$t('pholder.input'),
// trigger: 'blur'
// }],
}
}
},
mounted() {
this.getCounterType()
},
methods: {
dialogInit(data,mallId,areaId) {
this.addForm = {
mallId: '',
areaId:"",
// queueLengthSwitch:false,
queueLengthThreshold:'',
// waitTimeSwitch:false,
waitTimeThreshold:'',
alarmInterval:'',
sendEmail:'',
channelRules:[]
};
if(data && data.length>0){
this.isAdd = false;
this.addForm = Object.assign({},data[0]);
// this.addForm.queueLengthSwitch = data[0].queueLengthSwitch==1?true:false;
// this.addForm.waitTimeSwitch = data[0].waitTimeSwitch==1?true:false;
let arr = data[0].sendEmail.split(";")
this.alarmReceiverList = []
for (var i = 0; i < arr.length; i++) {
......@@ -90,6 +90,18 @@ export default {
email:arr[i]
})
}
data[0].channelRules.forEach(itemR=>{
this.counterTypeData.forEach(item=>{
if(itemR.counterType == item.key){
item.alarmInterval = itemR.alarmInterval;
item.queueLengthThreshold = itemR.queueLengthThreshold;
item.trolleyThreshold = itemR.trolleyThreshold;
item.waitTimeThreshold = itemR.waitTimeThreshold;
item.counterTypeId = itemR.id;
}
})
})
this.$forceUpdate()
}else{
this.addForm.mallId = mallId;
......@@ -97,6 +109,20 @@ export default {
}
this.addDialogVisible = true;
},
// 通道类型
getCounterType() {
this.$api.base.dataDic({
type: 'counterType'
}).then(res => {
this.counterTypeData = res.data.data.map(item => {
if (localStorage.getItem('lang') == 'en_US') {
item.value = item.valueEn;
}
item.text = item.value
return item;
});
})
},
addEmail(){
this.alarmReceiverList.push({
email:''
......@@ -112,10 +138,31 @@ export default {
}
this.addForm.sendEmail = arr.join(';')
this.$refs[formName].validate((valid) => {
console.log(valid)
if (valid) {
this.addForm.queueLengthSwitch = 1
this.addForm.waitTimeSwitch = 1
let channelRules = []
for (let item of this.counterTypeData) {
if(item.key != 4){
if(item.queueLengthThreshold&&item.queueLengthThreshold&&item.queueLengthThreshold&&item.trolleyThreshold){
channelRules.push({
queueLengthThreshold:item.queueLengthThreshold,
waitTimeThreshold:item.waitTimeThreshold,
alarmInterval:item.alarmInterval,
trolleyThreshold:item.trolleyThreshold,
counterType:item.key,
id: item.counterTypeId||null
})
}else{
this.$message({
message: this.$t('pholder.input') + item.text + this.$t('button.alarmRules'),
type: 'warning'
});
return false
}
}
}
// this.addForm.queueLengthSwitch = 1
// this.addForm.waitTimeSwitch = 1
this.addForm.channelRules = channelRules
if(this.isAdd){
this.$api.queueManagementApi.addAlarmRules(this.addForm)
.then((res) => {
......@@ -171,7 +218,7 @@ export default {
<style scoped lang="less">
.dialog_lj{
/deep/.el-dialog{
width: 1000px !important;
width: 1300px !important;
}
/deep/.el-form{
......@@ -188,6 +235,18 @@ export default {
.receiverEmail{
width: 500px !important;
}
.inlineBlock{
/deep/.el-form-item{
display: inline-block;
}
/deep/.el-form-item__content{
width: 180px !important;
min-width: 180px !important;
}
/deep/.el-input-number{
width: 100px;
}
}
/deep/.el-form-item__label{
line-height: 30px;
height: 30px;
......
......@@ -59,13 +59,18 @@
</el-table-column> -->
<el-table-column :label="$t('table.laneName')" width="160" align="center" prop="cashierChannelId" :formatter="landFormat"></el-table-column>
<el-table-column :label="$t('table.messageContent')" align="center" prop="messageContent" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('table.sentDate')" align="center" prop="createTime" width="160"></el-table-column>
<el-table-column :label="$t('table.sentDate')" align="center" prop="sendTime" width="160"></el-table-column>
<el-table-column :label="$t('table.state')" align="center" prop="status" width="100">
<template slot-scope="scope">
<span>{{scope.row.status==1?$t('table.sendSuccess'):$t('table.sendFail')}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.recipient')" align="center" prop="sendEmail">
<el-table-column :label="$t('table.recipient')" align="center" prop="sendEmail" show-overflow-tooltip>
</el-table-column>
<el-table-column :label="$t('table.operate')" align="center" width="120">
<template slot-scope="scope">
<el-button type="text" class="tab-btn" @click="getDetail(scope.row)">{{$t('button.look')}}</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
......@@ -86,6 +91,15 @@
</div>
</div>
<add-dialog ref="addModel"></add-dialog>
<el-dialog :title="$t('allPages.Image')" class="manage-dialog dialog_lj imgDialog" :visible.sync="imgDialogVisible"
:close-on-click-modal="false" v-if="imgDialogVisible" @close="imgDialogVisible = false">
<div style="height: 600px;">
<el-image v-for="(item,index) in imgArr" :key="index" :src='picUrl+item'></el-image>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="imgDialogVisible = false" class="dialog-btn">{{ $t('dialog.close') }}</el-button>
</div>
</el-dialog>
</div>
</template>
......@@ -95,6 +109,9 @@
export default {
data() {
return {
picUrl:'',
imgArr:[],
imgDialogVisible:false,
mallListForTerm:[],
channelListData:[],
areaListData:[],
......@@ -124,6 +141,7 @@
addDialog,
},
mounted() {
this.picUrl = window._vionConfig.picUrl
this.getMallListForTerm()
},
computed: {
......@@ -133,6 +151,17 @@
},
},
methods: {
getDetail(row){
if(row.screenshotPath){
this.imgArr = row.screenshotPath.split(";")
this.imgDialogVisible = true
}else{
this.$message({
message: this.$t('echartsTitle.noData'),
type: 'warning'
});
}
},
// 广场
getMallListForTerm() {
this.mallListForTerm = [];
......@@ -263,6 +292,11 @@
</script>
<style scoped="scoped" lang="less">
.imgDialog{
/deep/.el-dialog{
width: 1000px !important;
}
}
/deep/.el-select{
width: 180px;
}
......@@ -273,4 +307,7 @@
/deep/.el-date-editor{
width: 250px !important;
}
/deep/.el-table .cell{
text-overflow: ellipsis !important;
}
</style>
<template>
<div class="clerk-wrapper queueManagementContainer">
<div class="header manage-head-wrapper">
<el-form ref="form" class="boxShadow searchFormSocial" label-width="100px" inline>
<el-form-item :label="$t('table.mall')">
<el-select v-model="searchForm.mallId" filterable :placeholder="$t('pholder.select')" @change="mallChange">
<el-option v-for="item in mallListForTerm" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('table.areaName')">
<el-select v-model="searchForm.cashierAreaId" :placeholder="$t('pholder.areaSelect')" @change="areaChange">
<el-option v-for="item in areaListData" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('Lane Type')">
<el-select v-model="searchForm.counterType" class="laneType" clearable :placeholder="$t('pholder.selectLane')" @change="counterTypeChange">
<el-option :label="$t('pholder.all')" value="" />
<el-option v-for="item in counterTypeData" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-form-item>
<el-form-item :label="$t('table.laneName')">
<ul class="condition-box">
<li class="condition-item">
<div class="condition-item-option">
<el-select v-model="searchForm.cashierChannelId" clearable :placeholder="$t('pholder.selectLane')">
<el-option :label="$t('pholder.all')" value="" />
<el-option v-for="item in channelListData" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<!-- <el-select v-model="searchForm.cashierChannelIds" filterable :placeholder="$t('pholder.select')" class="mall-sel-box" multiple :reserve-keyword="true" collapse-tags @change="channelChangeHandle">
<div :class="isMallSelAll ? 'sel-all-box selected' : 'sel-all-box'" @click="selAllHandle('Mall', channelListData)">
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{$t('allPages.all')}}</span>
</div>
<el-option v-for="item in channelListData" :key="item.id" :label="item.name" :value="item.id">
<span class="custom-checkbox__input">
<span class="custom-checkbox__inner"></span>
</span>
<span style="padding-left: 5px;">{{ item.name }}</span>
</el-option>
</el-select> -->
</div>
</li>
</ul>
</el-form-item>
<el-form-item :label="$t('table.date')">
<el-date-picker type="date" :placeholder="$t('pholder.date')" v-model="searchForm.countDate" style="width: 100%;"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" class="search-btn" size="mini" plain @click="searchFun">{{$t('button.search')}}</el-button>
</el-form-item>
</el-form>
</div>
<div class="manage-content contentSocial boxShadow">
<h3 class="asis-table-header single-report-header tf-table-header socialHeader">
<span class="asis-table-download" @click="downloadData('Waiting Time Statistics' + '-' + Time())">{{$t('allPages.load')}}</span>
<span class="report-type-box">
<span :class="isTabChart ? 'report-item line-report' : 'report-item line-report report-item-line'" @click="selReport('bar')"></span>
<span :class="isTabChart ? 'report-item report-item-tab' : 'report-item'" @click="selReport('table')"></span>
</span>
</h3>
<div class="asis-table-content " v-loading="loading">
<el-table v-show="isTabChart" class="asis-table baseasis-table" id="domBaseTrafficFlow" :data="tabOps" header-row-class-name="asis-table-head" style="width: 100%" :max-height="tableHeight">
<el-table-column v-if="tabOps.length" type="index" :label="$t('table.order')" align="center" width="80">
<template slot-scope="scope">
<span>{{ indexFormatter(scope) }}</span>
</template>
</el-table-column>
<el-table-column :prop="item.prop" :label="item.label" align="center" v-for="(item,index) in tabHeadData" :key="index" min-width="100">
</el-table-column>
</el-table>
<div v-show="!isTabChart">
<div id="bdBarChart" class="area-line-chart" :style="{ height: tableHeight + 'px' }"></div>
</div>
</div>
</div>
<export-data-dialog ref="exportDialog"></export-data-dialog>
</div>
</template>
<script>
import moment from 'moment'
import echarts from "echarts";
import exportData from "../../public/exportData";
import {
columnComputed,
rowComputed,
curryAvgAndSum,
combineHeadAndBody
} from '@/utils'
export default {
data() {
return {
counterTypeData: [],
mallListForTerm: [],
areaListData: [],
channelListData: [],
trafficFlow_title: "regionalStatistics", //报表
loading: false,
searchForm: {
mallId: '',
cashierAreaId: '',
counterType: '',
cashierChannelId: '',
countDate: new Date()
},
isMallSelAll: false,
isTabChart: false,
tabHeadData: [],
tabOps: [],
chart: '',
option: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: '{b}:{c}%'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
name:'%',
type: 'value',
show:false
},
yAxis: {
name: 'Wating Time',
type: 'category',
// axisLine:{
// show:false
// },
axisTick:{
show:false // 不显示坐标轴刻度线
},
data: []
},
series: [{
type: 'bar',
label: {
show: true,
formatter: function(params) {
return params.value + '%'
}
},
itemStyle: {
normal: {
color: function(params) {
let colorList = ['#3BB8FF', '#FFC62E', '#97c05c', '#d83965', '#9036aa'];
return colorList[params.dataIndex]
}
}
},
data: []
}]
}
}
},
components: {
"export-data-dialog": exportData,
},
mounted() {
this.getCounterType()
this.chart = echarts.init(document.getElementById('bdBarChart'));
this.getMallListForTerm();
},
computed: {
tableHeight() {
const windowInnerHeight = window.innerHeight;
return windowInnerHeight - windowInnerHeight * 0.24;
},
},
methods: {
// 通道类型
getCounterType() {
this.$api.base.dataDic({
type: 'counterType'
}).then(res => {
this.counterTypeData = res.data.data.map(item => {
if (localStorage.getItem('lang') == 'en_US') {
item.value = item.valueEn;
}
item.text = item.value
return item;
});
})
},
indexFormatter({
$index,
row
}) {
const {
createRow,
tabOps
} = this
const realDataLen = tabOps.length
return $index + 1
},
// 广场
getMallListForTerm() {
this.mallListForTerm = [];
this.searchForm.mallId = "";
this.$api.base.mall({
accountId: this.$cookie.get('accountId'),
status_arr: "1,3"
}).then(data => {
let result = data.data;
if (result.data.length) {
if (this.getSessionLocal("mallId")) {
this.searchForm.mallId = Number(this.getSessionLocal("mallId"));
} else {
this.searchForm.mallId = result.data[0].id;
this.setSessionLocal("mallId", this.searchForm.mallId);
}
this.mallListForTerm = result.data;
}
this.getAreaList(this.searchForm.mallId);
})
},
mallChange(val) {
this.setSessionLocal("mallId", val);
this.searchForm.cashierAreaId = ''
this.searchForm.cashierChannelId = ''
this.areaListData = [];
this.channelListData = [];
this.getAreaList(val)
},
// 区域
getAreaList(val) {
this.areaListData = [];
this.$api.queueManagementApi.getAreaList({
mallId: val,
pageNum: 1,
pageSize: 999999
}).then(res => {
let result = res.data;
if (result.code == 200) {
if (result.data.list && result.data.list.length > 0) {
this.searchForm.cashierAreaId = result.data.list[0].id
this.areaListData = result.data.list;
this.getData()
this.getChannelList()
}
}
})
},
areaChange() {
this.searchForm.cashierChannelId = ''
this.getChannelList()
},
counterTypeChange() {
this.isMallSelAll = false
this.searchForm.cashierChannelId = ''
this.getChannelList()
},
// 通道
getChannelList() {
this.channelListData = [];
this.$api.queueManagementApi.getChannelList({
areaId: this.searchForm.cashierAreaId,
counterType: this.searchForm.counterType,
pageNum: 1,
pageSize: 999999
}).then(res => {
let result = res.data;
if (result.code == 200) {
if (result.data.list && result.data.list.length > 0) {
this.channelListData = result.data.list;
}
}
})
},
channelChangeHandle() {
this.isMallSelAll = this.changeHandle(this.searchForm.cashierChannelIds, this.channelListData)
},
selAllHandle(selType, option) {
let selectAll = 'is' + selType + 'SelAll';
let selectVal = 'cashierChannelIds';
if (this[selectAll]) {
this[selectAll] = false;
this.searchForm.cashierChannelIds = [];
} else {
this[selectAll] = true;
this.searchForm.cashierChannelIds = [];
option.forEach(item => {
this.searchForm.cashierChannelIds.push(item.id);
})
}
},
searchFun() {
this.getData()
},
getData() {
this.tabHeadData = [];
this.tabOps = [];
this.loading = true;
this.searchForm.countDate = moment(this.searchForm.countDate).format('YYYY-MM-DD')
this.searchForm.chartType = this.isTabChart ? "table" : "bar"
let parmas = {
mallId: this.searchForm.mallId,
areaId: this.searchForm.cashierAreaId,
countDate: moment(this.searchForm.countDate).format('YYYY-MM-DD'),
chartType: this.isTabChart ? "table" : "bar",
counterId: this.searchForm.cashierChannelId
}
this.$api.queueManagementApi.getDistributeList(parmas).then(res => {
this.loading = false;
if (res.data.code == 200) {
let resData = res.data.data;
if (this.isTabChart) { // 表格
this.getTableData(resData)
} else { // 图
this.getEcartsData(resData)
}
}
})
},
getEcartsData(resData) {
this.option.yAxis.data = resData.xaxis.data;
this.option.series[0].data = resData.series[0].data;
this.chart.setOption(this.option, true)
},
getTableData(resData) {
let originData = JSON.parse(JSON.stringify(resData.series))
let flowHeadData = JSON.parse(JSON.stringify(resData.xaxis && resData.xaxis.data || []));
this.tabHeadData = flowHeadData.reduce((arr, curr, index) => {
arr.push({
prop: `defaultOrg${index}`,
label: curr
})
return arr
}, [])
const tbodyData = originData.reduce((arr, curr) => {
arr.push(curr.data)
return arr
}, [])
this.tabOps = combineHeadAndBody(this.tabHeadData, tbodyData)
},
selReport(iconType) {
if (iconType === "bar") {
this.isTabChart = false;
this.getData();
} else {
this.isTabChart = true;
this.getData();
}
},
downloadData(title) {
if (this.isTabChart) {
this.dealExport("domBaseTrafficFlow", title);
} else {
this.exportDataHandle(title);
}
},
exportDataHandle(title) {
const {
queuingUrl
} = window._vionConfig;
let params =
`areaId=${this.searchForm.cashierAreaId}&counterId=${this.searchForm.cashierChannelId}&countDate=${moment(this.searchForm.countDate).format('YYYY-MM-DD')}&chartType=${this.searchForm.chartType}&mallId=${this.searchForm.mallId}`
const downloadUrl = `${queuingUrl}/queuing/waitTime/distribute/export?${params}&localLanguage=${localStorage.getItem("lang")}&authorization=${this.$cookie.get("atoken")}&title=${encodeURI(title)}`;
window.open(downloadUrl)
}
}
}
</script>
<style scoped="scoped" lang="less">
/deep/.el-select {
width: 170px !important;
}
/deep/.el-date-editor {
width: 170px !important;
}
/deep/.granularity.el-select {
width: 120px !important;
}
/deep/.el-form-item__label {
width: auto !important;
min-width: 60px;
}
</style>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!