临时提交
This commit is contained in:
parent
10f6e7351e
commit
1e2022d9f9
10
src/api/mch/bill.js
Normal file
10
src/api/mch/bill.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 商户查询充值记录统计
|
||||
export function mchCountBill(query) {
|
||||
return request({
|
||||
url: '/mch/bill/count',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
43
src/api/mch/device.js
Normal file
43
src/api/mch/device.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 商户查询设备列表
|
||||
export function mchListDevice(query) {
|
||||
return request({
|
||||
url: '/app/device/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询设备详细
|
||||
export function mchGetDevice(deviceId) {
|
||||
return request({
|
||||
url: '/app/device/' + deviceId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 商户解绑设备
|
||||
export function mchUnbindDevice(deviceId) {
|
||||
return request({
|
||||
url: `/app/device/mch/unbind/${deviceId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 商户修改设备
|
||||
export function mchUpdateDevice(data) {
|
||||
return request({
|
||||
url: `/app/device`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 商户刷新物联网设备信息
|
||||
export function mchRefreshIot(deviceId) {
|
||||
return request({
|
||||
url: `/app/device/${deviceId}/refreshIot`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
46
src/api/mch/store.js
Normal file
46
src/api/mch/store.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询本人店铺
|
||||
export function mchListStore(params) {
|
||||
return request({
|
||||
url: '/app/store/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询本人店铺详情
|
||||
export function mchGetStore(storeId) {
|
||||
return request({
|
||||
url: `/app/store/mch/${storeId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 新增店铺
|
||||
export function mchAddStore(data) {
|
||||
return request({
|
||||
url: '/app/store',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改店铺
|
||||
export function mchUpdateStore(data) {
|
||||
return request({
|
||||
url: '/app/store',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除店铺
|
||||
export function mchDelStore(data) {
|
||||
return request({
|
||||
url: '/app/store',
|
||||
method: 'delete',
|
||||
data
|
||||
})
|
||||
}
|
|
@ -69,7 +69,7 @@ export function logicDelDevice(deviceId) {
|
|||
}
|
||||
|
||||
|
||||
// 逻辑删除设备
|
||||
// 刷新物联网设备信息
|
||||
export function refreshIot(deviceId) {
|
||||
return request({
|
||||
url: `/system/device/${deviceId}/refreshIot`,
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
<base-link
|
||||
:id="id"
|
||||
:text="text"
|
||||
path="/smDevice/detail"
|
||||
:query="{deviceId: id}"
|
||||
:path="path"
|
||||
:query="query"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import BaseLink from '@/components/Business/BaseLink.vue'
|
||||
import { UserType } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
components: { BaseLink },
|
||||
|
@ -22,6 +23,22 @@ export default {
|
|||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
path() {
|
||||
if (this.$store.getters.userType === UserType.APP) {
|
||||
return `/device/${this.id}`
|
||||
} else {
|
||||
return '/smDevice/detail'
|
||||
}
|
||||
},
|
||||
query() {
|
||||
if (this.$store.getters.userType === UserType.APP) {
|
||||
return null;
|
||||
} else {
|
||||
return {deviceId: this.id}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { UserType } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
name: 'StoreLink',
|
||||
props: {
|
||||
|
@ -13,11 +15,15 @@ export default {
|
|||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$router.push({path: '/mch/storeDetail', query: {storeId: this.id}})
|
||||
if (this.$store.getters.userType === UserType.APP) {
|
||||
this.$router.push(`/business/store/${this.id}`)
|
||||
} else {
|
||||
this.$router.push({path: '/mch/storeDetail', query: {storeId: this.id}})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
149
src/router/mch.js
Normal file
149
src/router/mch.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
import Layout from '@/layout/index.vue'
|
||||
|
||||
/**
|
||||
* 商户中心路由
|
||||
*/
|
||||
export const mchRoutes = [
|
||||
{
|
||||
path: '/business',
|
||||
component: Layout,
|
||||
hidden: false,
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '经营管理'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'store',
|
||||
component: () => import('../views/mch/store'),
|
||||
hidden: false,
|
||||
name: "MyStore",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '我的店铺',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'store/:storeId',
|
||||
component: () => import('../views/mch/store/detail.vue'),
|
||||
hidden: true,
|
||||
name: "MyStoreDetail",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '店铺详情',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'suit',
|
||||
component: () => import('@/views/index.vue'),
|
||||
hidden: false,
|
||||
name: "MyStore",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '套餐管理',
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/device',
|
||||
component: Layout,
|
||||
hidden: false,
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '设备管理'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/mch/device'),
|
||||
hidden: false,
|
||||
name: "MyDevice",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '我的设备',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':deviceId',
|
||||
component: () => import('@/views/mch/device/detail.vue'),
|
||||
hidden: true,
|
||||
name: "MyDeviceDetail",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '设备详情',
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/bill',
|
||||
component: Layout,
|
||||
hidden: false,
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '订单管理'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/index.vue'),
|
||||
hidden: false,
|
||||
name: "MyBill",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '套餐订单',
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/money',
|
||||
component: Layout,
|
||||
hidden: false,
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '财务管理'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'recordBalance',
|
||||
component: () => import('@/views/index.vue'),
|
||||
hidden: false,
|
||||
name: "MyRecordBalance",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '收支明细',
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/dev',
|
||||
component: Layout,
|
||||
hidden: false,
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '开发管理'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'access',
|
||||
hidden: false,
|
||||
component: () => import('@/views/index.vue'),
|
||||
name: "MyAccess",
|
||||
meta: {
|
||||
noCache: false,
|
||||
title: '秘钥管理'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'https://www.baidu.com',
|
||||
hidden: false,
|
||||
meta: {
|
||||
title: '开发文档'
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
|
@ -4,6 +4,9 @@ import { getRouters } from '@/api/menu'
|
|||
import Layout from '@/layout/index'
|
||||
import ParentView from '@/components/ParentView'
|
||||
import InnerLink from '@/layout/components/InnerLink'
|
||||
import { mchRoutes } from '@/router/mch'
|
||||
import store from '@/store'
|
||||
import { UserType } from '@/utils/constants'
|
||||
|
||||
const permission = {
|
||||
state: {
|
||||
|
@ -32,26 +35,42 @@ const permission = {
|
|||
// 生成路由
|
||||
GenerateRoutes({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
// 向后端请求路由数据
|
||||
getRouters().then(res => {
|
||||
const sdata = JSON.parse(JSON.stringify(res.data))
|
||||
const rdata = JSON.parse(JSON.stringify(res.data))
|
||||
const sidebarRoutes = filterAsyncRouter(sdata)
|
||||
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
||||
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
|
||||
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
|
||||
router.addRoutes(asyncRoutes);
|
||||
commit('SET_ROUTES', rewriteRoutes)
|
||||
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
|
||||
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
|
||||
commit('SET_TOPBAR_ROUTES', sidebarRoutes)
|
||||
resolve(rewriteRoutes)
|
||||
})
|
||||
// 商户
|
||||
if (store.getters.userType === UserType.APP) {
|
||||
handleRoutes(mchRoutes, mchRoutes, resolve, commit);
|
||||
}
|
||||
// 管理员
|
||||
else {
|
||||
// 向后端请求路由数据
|
||||
getRouters().then(res => {
|
||||
const sdata = JSON.parse(JSON.stringify(res.data))
|
||||
const rdata = JSON.parse(JSON.stringify(res.data))
|
||||
const sidebarRoutes = filterAsyncRouter(sdata)
|
||||
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
||||
handleRoutes(rewriteRoutes, sidebarRoutes, resolve, commit);
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleRoutes(rewriteRoutes, sidebarRoutes, resolve, commit) {
|
||||
console.log(rewriteRoutes, sidebarRoutes);
|
||||
|
||||
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
|
||||
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
|
||||
router.addRoutes(asyncRoutes);
|
||||
|
||||
commit('SET_ROUTES', rewriteRoutes)
|
||||
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
|
||||
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
|
||||
commit('SET_TOPBAR_ROUTES', sidebarRoutes)
|
||||
|
||||
resolve(rewriteRoutes)
|
||||
}
|
||||
|
||||
// 遍历后台传来的路由字符串,转换为组件对象
|
||||
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
|
||||
return asyncRouterMap.filter(route => {
|
||||
|
|
71
src/views/mch/device/components/bindRecord.vue
Normal file
71
src/views/mch/device/components/bindRecord.vue
Normal file
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="recordList">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="时间" prop="createTime"></el-table-column>
|
||||
<el-table-column align="center" label="用户名称" prop="userName"></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getRecordList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listBindRecord} from "@/api/system/bindRecord";
|
||||
|
||||
export default {
|
||||
name: 'bindRecord',
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recordList: [], // 记录列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getRecordList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRecordList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取记录列表
|
||||
getRecordList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listBindRecord(this.queryParams).then(response => {
|
||||
this.recordList = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
153
src/views/mch/device/components/meterRecordReport.vue
Normal file
153
src/views/mch/device/components/meterRecordReport.vue
Normal file
|
@ -0,0 +1,153 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row type="flex">
|
||||
<el-tabs v-model="queryParams.groupBy" style="width: 100%" >
|
||||
<el-tab-pane label="日报表" name="create_date">
|
||||
<el-row type="flex">
|
||||
<el-col :span="16">
|
||||
<range-picker :end="new Date().getFullYear()" v-model="queryParams.year" @change="onChangeYear" suffix="年" />
|
||||
<range-picker :start='1' :end="reportMonthEnd" v-model="queryParams.month" @change="onChangeMonth" suffix="月"/>
|
||||
</el-col>
|
||||
<el-col :span="8" class="used">
|
||||
本月用电量(度)
|
||||
<span class="used-num">{{groupTotalUsed | money}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="月报表" name="create_month">
|
||||
<el-row type="flex">
|
||||
<el-col :span="16">
|
||||
<range-picker :end="new Date().getFullYear()" v-model="queryParams.year" @change="onChangeYear" suffix="年"/>
|
||||
</el-col>
|
||||
<el-col :span="8" class="used">
|
||||
本年用电量(度)
|
||||
<span class="used-num">{{groupTotalUsed | money}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-row>
|
||||
|
||||
<single-line-chart v-if="records && records.length > 0" v-loading="loading" :labels="labels" :chart-data="chartData" name="用电量" />
|
||||
<el-empty v-else description="暂无数据" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleLineChart from "@/components/SingleLineChart/index.vue";
|
||||
import {listCountRecord,} from "@/api/system/record";
|
||||
import RangePicker from "@/components/RangePicker/index.vue";
|
||||
|
||||
export default {
|
||||
name: 'meterRecordReport',
|
||||
components: {RangePicker, SingleLineChart},
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
records: [], // 记录列表
|
||||
queryParams: {
|
||||
year: new Date().getFullYear(),
|
||||
month: new Date().getMonth() + 1,
|
||||
groupBy: "create_date",
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getReportData(nv);
|
||||
},
|
||||
"queryParams.groupBy": {
|
||||
handler(nv, ov) {
|
||||
if (nv === 'create_month') { // 月报表
|
||||
this.queryParams.month = null;
|
||||
}
|
||||
if (nv === 'create_date') {// 日报表
|
||||
this.queryParams.month = new Date().getMonth() + 1;
|
||||
}
|
||||
this.getReportData(this.deviceId);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labels() {
|
||||
if (this.queryParams.groupBy === 'create_date') {
|
||||
return this.records.map(item => item.createDate);
|
||||
} else if (this.queryParams.groupBy === 'create_month') {
|
||||
return this.records.map(item => item.createMonth + '月');
|
||||
}
|
||||
return [];
|
||||
},
|
||||
chartData() {
|
||||
return this.records.map(item => item.groupUsedElectriQuantity);
|
||||
},
|
||||
// 每组的总用电量
|
||||
groupTotalUsed() {
|
||||
let sum = 0;
|
||||
this.records.forEach(item => sum += item.groupUsedElectriQuantity);
|
||||
return sum;
|
||||
},
|
||||
// 获取报表显示的月份
|
||||
reportMonthEnd() {
|
||||
let now = new Date();
|
||||
let nowYear = new Date().getFullYear()
|
||||
let paramYear = this.queryParams.year;
|
||||
if (paramYear < nowYear) {
|
||||
return 12;
|
||||
}
|
||||
if (paramYear === nowYear) {
|
||||
return now.getMonth() + 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getReportData(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 切换月份
|
||||
onChangeMonth(month) {
|
||||
this.queryParams.month = month;
|
||||
this.getReportData(this.deviceId);
|
||||
},
|
||||
// 切换年份
|
||||
onChangeYear(year) {
|
||||
this.queryParams.year = year;
|
||||
let now = new Date();
|
||||
if (year === now.getFullYear()) {
|
||||
if (this.queryParams.month > now.getMonth() + 1) {
|
||||
this.queryParams.month = new Date().getMonth() + 1;
|
||||
}
|
||||
}
|
||||
this.getReportData(this.deviceId);
|
||||
},
|
||||
// 获取报表信息
|
||||
getReportData(deviceId) {
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listCountRecord(this.queryParams).then(response => {
|
||||
this.records = response.data;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped type="scss">
|
||||
.used {
|
||||
line-height: 36px;
|
||||
text-align: right;
|
||||
}
|
||||
.used-num {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
75
src/views/mch/device/components/readingRecord.vue
Normal file
75
src/views/mch/device/components/readingRecord.vue
Normal file
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="tableData">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="时间" prop="createTime"></el-table-column>
|
||||
<el-table-column align="center" label="总用电量" prop="totalElectriQuantity">
|
||||
<template slot-scope="d">{{d.row.totalElectriQuantity | money}} 度</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getChargeList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {listRecord} from "@/api/system/record";
|
||||
|
||||
export default {
|
||||
name: 'readingRecord',
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [], // 列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
type: 1,
|
||||
deviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getChargeList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getChargeList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取充值记录
|
||||
getChargeList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listRecord(this.queryParams).then(response => {
|
||||
this.tableData = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
91
src/views/mch/device/components/rechargeRecord.vue
Normal file
91
src/views/mch/device/components/rechargeRecord.vue
Normal file
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="rechargeList">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="时间" prop="createTime"></el-table-column>
|
||||
<el-table-column align="center" label="充值用户" prop="userName"></el-table-column>
|
||||
<el-table-column align="center" label="套餐名称" prop="suitName"></el-table-column>
|
||||
<el-table-column align="center" label="金额" prop="money">
|
||||
<template slot-scope="d">{{d.row.money | money}} 元</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="时长">
|
||||
<template slot-scope="d">
|
||||
<span>{{d.row.suitTime}} {{suitTimeUnit(d.row.suitTimeUnit)}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getChargeList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listBill} from "@/api/system/recharge";
|
||||
import { findLabel } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'rechargeRecord',
|
||||
dicts: ['time_unit'],
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rechargeList: [], // 充值记录列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
type: 1,
|
||||
deviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 时长单位
|
||||
suitTimeUnit() {
|
||||
return (unit) => {
|
||||
return findLabel(this.dict.type.time_unit, unit);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getChargeList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getChargeList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取充值记录
|
||||
getChargeList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listBill(this.queryParams).then(response => {
|
||||
this.rechargeList = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
74
src/views/mch/device/components/resetRecord.vue
Normal file
74
src/views/mch/device/components/resetRecord.vue
Normal file
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="recordList">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="时间" prop="createTime"></el-table-column>
|
||||
<el-table-column align="center" label="商户名称" prop="mchName"></el-table-column>
|
||||
<el-table-column align="center" label="归零前剩余时长" prop="surplusTime">
|
||||
<template slot-scope="d">{{d.row.surplusTime | money}} 分钟</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getRecordList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listResetRecord} from "@/api/system/resetRecord";
|
||||
|
||||
export default {
|
||||
name: 'resetRecord',
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recordList: [], // 记录列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getRecordList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRecordList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取记录列表
|
||||
getRecordList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listResetRecord(this.queryParams).then(response => {
|
||||
this.recordList = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
71
src/views/mch/device/components/suitList.vue
Normal file
71
src/views/mch/device/components/suitList.vue
Normal file
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="recordList">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="时间" prop="createTime"></el-table-column>
|
||||
<el-table-column align="center" label="用户名称" prop="userName"></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getRecordList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listBindRecord} from "@/api/system/bindRecord";
|
||||
|
||||
export default {
|
||||
name: 'suitList',
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recordList: [], // 记录列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getRecordList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRecordList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取记录列表
|
||||
getRecordList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.deviceId = deviceId | this.deviceId;
|
||||
listBindRecord(this.queryParams).then(response => {
|
||||
this.recordList = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
75
src/views/mch/device/components/tenantList.vue
Normal file
75
src/views/mch/device/components/tenantList.vue
Normal file
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table v-loading="loading" :data="tenantList">
|
||||
<el-table-column align="center" type="index" label="#"></el-table-column>
|
||||
<el-table-column align="center" label="头像" prop="avatar">
|
||||
<template slot-scope="d">
|
||||
<image-preview :src="d.row.avatar" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="用户名称" prop="userName"></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
:auto-scroll="false"
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getUserList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listSmUser} from "@/api/system/smUser";
|
||||
|
||||
export default {
|
||||
name: 'tenantList',
|
||||
props: {
|
||||
// 设备id
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tenantList: [], // 记录列表
|
||||
loading: false,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
tenantDeviceId: null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
deviceId(nv, ov) {
|
||||
this.getUserList(nv);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getUserList(this.deviceId);
|
||||
},
|
||||
methods: {
|
||||
// 获取记录列表
|
||||
getUserList(deviceId) {
|
||||
if(deviceId == null) {
|
||||
this.recordList = [];
|
||||
this.total = 0;
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.queryParams.tenantDeviceId = deviceId | this.deviceId;
|
||||
listSmUser(this.queryParams).then(response => {
|
||||
this.tenantList = response.rows;
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
341
src/views/mch/device/detail.vue
Normal file
341
src/views/mch/device/detail.vue
Normal file
|
@ -0,0 +1,341 @@
|
|||
<template>
|
||||
<div class="app-container" v-loading="loading" >
|
||||
<div v-if="deviceData">
|
||||
<el-card class="box-card" >
|
||||
<el-descriptions title="设备详情">
|
||||
<template slot="extra">
|
||||
<el-dropdown style="margin-right: 1em">
|
||||
<el-button>
|
||||
更多操作<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item>
|
||||
<el-link :underline="false" icon="el-icon-plus" @click="handleAddElectricity">增加时长</el-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-link :underline="false" icon="el-icon-refresh" @click="handleReset">时长归零</el-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-link :underline="false" icon="el-icon-switch-button" v-if="!isOpen" @click="handleSwitch(true)">强制开启</el-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-link :underline="false" icon="el-icon-switch-button" v-if="isOpen" @click="handleSwitch(false)">强制关闭</el-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-link :underline="false" icon="el-icon-link" type="danger" @click="handleUnbind" :disabled="deviceData.userId == null">强制解绑</el-link>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
<el-button icon="el-icon-refresh" @click="refreshIot(deviceId, true)" style="margin-right: 1em">刷新设备信息</el-button>
|
||||
<el-popover
|
||||
placement="left"
|
||||
width="180"
|
||||
trigger="click">
|
||||
<div class="qr-code-box">
|
||||
<qr-code :text="qrCodeText(deviceData)" :width="150" :height="150" />
|
||||
<p>扫描二维码进行设备绑定</p>
|
||||
</div>
|
||||
<el-button slot="reference" type="primary" icon="el-icon-picture">设备二维码</el-button>
|
||||
</el-popover>
|
||||
</template>
|
||||
<el-descriptions-item label="MAC">{{deviceData.mac | defaultValue}}
|
||||
<dict-tag :options="dict.type.sm_device_status" :value="deviceData.status" size="mini"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="SN">{{deviceData.deviceNo | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="在线状态">
|
||||
<dict-tag :options="dict.type.sm_device_online_status" :value="deviceData.onlineStatus" size="mini"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{deviceData.model | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号功能">
|
||||
<dict-tag :options="dict.type.sm_model_tag" :value="deviceData.modelTags" size="mini"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开关状态">
|
||||
<el-tag :type="isOpen ? 'success' : 'danger'" size="mini">{{isOpen ? '已开启' : '已关闭'}}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="WIFI">{{deviceData.wifi | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="剩余时长">{{surplusTimeDesc(surplusTime).text}}</el-descriptions-item>
|
||||
<el-descriptions-item label="设备剩余时长">
|
||||
{{surplusTimeDesc(deviceData.remainTime).text}}
|
||||
<span class="remark-text">最近更新时间:{{deviceData.lastPullTime}}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<el-descriptions title="所属人信息">
|
||||
<el-descriptions-item label="所属用户">
|
||||
<user-link :name="deviceData.userName" :id="deviceData.userId"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="设备名称">{{deviceData.deviceName | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺名称">
|
||||
<store-link :name="deviceData.storeName" :id="deviceData.storeId"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="服务费">
|
||||
<template v-if="deviceData.serviceRate == null || deviceData.serviceType == null">跟随用户</template>
|
||||
<template v-else>
|
||||
<dict-tag :options="dict.type.service_type" :value="deviceData.serviceType" size="mini"/>
|
||||
{{deviceData.serviceRate}} {{serviceUnit(deviceData.serviceType)}}
|
||||
</template>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">{{deviceData.remark | defaultValue}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<!-- <el-card class="box-card">-->
|
||||
<!-- <el-row type="flex">-->
|
||||
<!-- <el-statistic class="statistic" group-separator=",">-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <svg-icon icon-class="time" />剩余时长-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #formatter>-->
|
||||
<!-- {{surplusTimeDesc(surplusTime).text}}-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-statistic>-->
|
||||
<!-- <el-statistic class="statistic" group-separator=",">-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <svg-icon icon-class="time" />在线状态-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #formatter>-->
|
||||
<!-- {{findLabel(dict.type.sm_device_online_status, deviceData.onlineStatus)}}-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-statistic>-->
|
||||
<!-- <el-statistic class="statistic" group-separator=",">-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <svg-icon icon-class="time" />开关状态-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #formatter>-->
|
||||
<!-- <el-tag :type="isOpen ? 'success' : 'danger'" size="mini">{{isOpen ? '已开启' : '已关闭'}}</el-tag>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-statistic>-->
|
||||
<!-- </el-row>-->
|
||||
<!-- </el-card>-->
|
||||
|
||||
<el-card class="box-card">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="套餐列表" :lazy="true">
|
||||
<suit v-if="deviceData.deviceId != null" :device-id="deviceData.deviceId"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="用户充值记录" :lazy="true">
|
||||
<recharge-record :device-id="deviceData.deviceId"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="时长变化记录" :lazy="true">
|
||||
<record-time :query="{deviceId: deviceData.deviceId}" view="device"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="抄表记录" :lazy="true">
|
||||
<reading-record :device-id="deviceData.deviceId"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="绑定记录" :lazy="true">
|
||||
<bind-record :device-id="deviceData.deviceId"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-empty v-else description="设备已被删除或不存在"/>
|
||||
|
||||
|
||||
<!--添加时长-->
|
||||
<el-dialog title="增加时长" :visible.sync="showAddElectricity" center width="400px">
|
||||
<el-form :model="addElectricityForm" :rules="addRules">
|
||||
<el-form-item label="时长" prop="amount">
|
||||
<el-input-number v-model="addElectricityForm.amount" style="width: 250px" controls-position="right" :step="1" step-strictly :min="0"/> 分钟
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" plain @click="submitAddElectricity">确认</el-button>
|
||||
<el-button plain @click="showAddElectricity = false">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { addTime, getDevice, refreshIot, resetDevice, switchDevice, unbind } from '@/api/system/device'
|
||||
import LineChart from "@/views/dashboard/LineChart.vue";
|
||||
import RechargeRecord from "@/views/system/device/components/rechargeRecord.vue";
|
||||
import { findLabel, formatDate } from '@/utils'
|
||||
import QrCode from "@/components/QrCode/index.vue";
|
||||
import MeterRecordReport from "@/views/system/device/components/meterRecordReport.vue";
|
||||
import ReadingRecord from "@/views/system/device/components/readingRecord.vue";
|
||||
import {getWxIndexUrl} from "@/utils/wx";
|
||||
import BindRecord from "@/views/system/device/components/bindRecord.vue";
|
||||
import ResetRecord from "@/views/system/device/components/resetRecord.vue";
|
||||
import TenantList from "@/views/system/device/components/tenantList.vue";
|
||||
import SuitList from '@/views/system/device/components/suitList.vue'
|
||||
import Suit from '@/views/ss/suit/index.vue'
|
||||
import RecordTime from '@/views/ss/time/index.vue'
|
||||
import { toDescriptionFromSecond } from '@/utils/date'
|
||||
import StoreLink from '@/components/Business/Store/StoreLink.vue'
|
||||
import UserLink from '@/components/Business/SmUser/UserLink.vue'
|
||||
import { $serviceType } from '@/utils/mixins'
|
||||
import { mchGetDevice, mchRefreshIot } from '@/api/mch/device'
|
||||
|
||||
export default {
|
||||
name: 'MyDeviceDetail',
|
||||
mixins: [$serviceType],
|
||||
components: {
|
||||
UserLink,
|
||||
StoreLink,
|
||||
RecordTime,
|
||||
Suit,
|
||||
SuitList,
|
||||
TenantList, ResetRecord, BindRecord, ReadingRecord, MeterRecordReport, QrCode, RechargeRecord, LineChart},
|
||||
dicts: ['sm_device_status', 'sm_device_outage_way', 'sm_device_notice_way', 'sm_model_tag', 'sm_device_online_status', 'service_type'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
deviceData: {},
|
||||
timer: null,
|
||||
surplusTime: 0, // 剩余时长
|
||||
addElectricityForm: {
|
||||
amount: 0
|
||||
},
|
||||
showAddElectricity: false,
|
||||
addRules: {
|
||||
amount: [
|
||||
{ required: true, message: '请输入电量', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
// 设备ID
|
||||
deviceId: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
qrCodeText() {
|
||||
return (device) => {
|
||||
return getWxIndexUrl({ s: device.deviceNo});
|
||||
}
|
||||
},
|
||||
surplusTimeDesc() {
|
||||
return (second) => {
|
||||
return toDescriptionFromSecond(second);
|
||||
}
|
||||
},
|
||||
isOpen() {
|
||||
return this.deviceData != null && this.deviceData.powerStatus === '1';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.deviceId = this.$route.params.deviceId;
|
||||
this.refreshIot(this.deviceId);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
methods: {
|
||||
handleUnbind() {
|
||||
this.$confirm('是否强制解绑该设备?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
unbind(this.deviceData.deviceId).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success("操作成功");
|
||||
}
|
||||
}).finally(() => {
|
||||
this.getDevice();
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSwitch(open) {
|
||||
this.$confirm(`是否确认强制${open ? '开启' : '关闭'}设备?`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
switchDevice(this.deviceData.deviceId, open).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success("操作成功");
|
||||
this.deviceData.powerStatus = open ? '1' : '0';
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
})
|
||||
},
|
||||
// 计算剩余时长
|
||||
computeSurplusTime() {
|
||||
if (this.deviceData.expireTime == null) {
|
||||
return 0;
|
||||
}
|
||||
let expireTime = new Date(this.deviceData.expireTime).getTime();
|
||||
let now = new Date().getTime();
|
||||
if (expireTime < now) {
|
||||
return 0;
|
||||
}
|
||||
return ((expireTime - now) / 1000).toFixed(2);
|
||||
},
|
||||
handleReset() {
|
||||
this.$confirm('是否确认归零设备?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
resetDevice(this.deviceData.deviceId).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success('操作成功');
|
||||
this.getDevice();
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleAddElectricity() {
|
||||
this.resetAddElectricityForm();
|
||||
this.showAddElectricity = true;
|
||||
},
|
||||
submitAddElectricity() {
|
||||
addTime(this.deviceData.deviceId, this.addElectricityForm.amount).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success('操作成功');
|
||||
this.showAddElectricity = false;
|
||||
this.getDevice();
|
||||
}
|
||||
})
|
||||
},
|
||||
resetAddElectricityForm() {
|
||||
this.addElectricityForm = {
|
||||
amount: 0
|
||||
}
|
||||
},
|
||||
// 刷新设备信息
|
||||
refreshIot(deviceId, notice = false) {
|
||||
this.loading = true;
|
||||
mchRefreshIot(deviceId).then(res => {
|
||||
if (res.code !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
if (notice) {
|
||||
this.$message.success('操作成功');
|
||||
}
|
||||
}).finally(() => {
|
||||
this.getDevice();
|
||||
})
|
||||
},
|
||||
getDevice() {
|
||||
this.loading = true;
|
||||
mchGetDevice(this.deviceId).then(response => {
|
||||
this.deviceData = response.data;
|
||||
this.surplusTime = this.computeSurplusTime();
|
||||
if (this.timer == null) {
|
||||
this.timer = setInterval(() => {
|
||||
this.surplusTime = this.computeSurplusTime();
|
||||
}, 1000)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.remark-text {
|
||||
color: #ccc;
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
498
src/views/mch/device/index.vue
Normal file
498
src/views/mch/device/index.vue
Normal file
|
@ -0,0 +1,498 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="SN" prop="deviceNo">
|
||||
<el-input
|
||||
v-model="queryParams.deviceNo"
|
||||
placeholder="请输入设备SN"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="MAC" prop="mac">
|
||||
<el-input
|
||||
v-model="queryParams.mac"
|
||||
placeholder="请输入设备Mac"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="型号" prop="model">
|
||||
<el-input
|
||||
v-model="queryParams.model"
|
||||
placeholder="请输入型号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备名称" prop="deviceName">
|
||||
<el-input
|
||||
v-model="queryParams.deviceName"
|
||||
placeholder="请输入设备名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺名称" prop="storeName">
|
||||
<el-input
|
||||
v-model="queryParams.storeName"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="在线状态" prop="onlineStatus">
|
||||
<el-select v-model="queryParams.onlineStatus" placeholder="请选择在线状态" clearable @change="handleQuery">
|
||||
<el-option
|
||||
v-for="dict in dict.type.sm_device_online_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable @change="handleQuery">
|
||||
<el-option
|
||||
v-for="dict in dict.type.sm_device_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="设备ID" align="center" prop="deviceId" width="100"/>
|
||||
<el-table-column label="图片" align="center" prop="picture" width="100">
|
||||
<template slot-scope="scope">
|
||||
<image-preview v-if="isEmpty(scope.row.customPicture)" :src="scope.row.picture" :width="50" :height="50"/>
|
||||
<image-preview v-else :src="scope.row.customPicture" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="二维码" align="center" width="80">
|
||||
<template slot-scope="d">
|
||||
<el-popover
|
||||
placement="top"
|
||||
width="180"
|
||||
trigger="hover">
|
||||
<div class="qr-code-box">
|
||||
<qr-code :text="qrCodeText(d.row)" :width="150" :height="150" />
|
||||
<p>扫描二维码进行设备绑定</p>
|
||||
</div>
|
||||
<el-button slot="reference" type="text" icon="el-icon-picture">查看</el-button>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备Mac" align="center" prop="mac" min-width="100">
|
||||
<device-link slot-scope="d" :text="d.row.mac" :id="d.row.deviceId"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备SN" align="center" prop="deviceNo" min-width="60">
|
||||
<template slot-scope="d">
|
||||
<device-link :text="d.row.deviceNo" :id="d.row.deviceId"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备名称" align="center" prop="deviceName" >
|
||||
<device-link slot-scope="d" :text="d.row.deviceName" :id="d.row.deviceId"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="型号" align="center" prop="model" />
|
||||
<el-table-column label="在线状态" align="center" prop="onlineStatus" width="80">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sm_device_online_status" :value="scope.row.onlineStatus"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" width="80">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sm_device_status" :value="scope.row.status"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所属店铺" align="center" prop="storeName" >
|
||||
<store-link slot-scope="d" :id="d.row.storeId" :name="d.row.storeName"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="服务费" align="center" prop="serviceRate" >
|
||||
<template slot-scope="d">
|
||||
<template v-if="d.row.serviceRate == null || d.row.serviceType == null">跟随用户</template>
|
||||
<template v-else>
|
||||
<dict-tag :options="dict.type.service_type" :value="d.row.serviceType"/>
|
||||
{{d.row.serviceRate}} {{serviceUnit(d.row.serviceType)}}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleSee(scope.row)"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleUnbind(scope.row)"
|
||||
>解绑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<sn-input :show.sync="showBindSn" @submit="onSubmitSn"></sn-input>
|
||||
|
||||
<!-- 添加或修改设备对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="6em">
|
||||
<el-row :gutter="gutter">
|
||||
<form-col :span="span" label="图片" prop="customPicture">
|
||||
<image-upload v-model="form.customPicture" :limit="1"/>
|
||||
</form-col>
|
||||
<form-col :span="span" label="设备名称" prop="deviceName">
|
||||
<el-input v-model="form.deviceName" placeholder="请输入设备名称" />
|
||||
</form-col>
|
||||
<form-col :span="span * 2" label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
|
||||
</form-col>
|
||||
<!--计时配置-->
|
||||
<form-col :span="span" label="起步时长" prop="startTime">
|
||||
<el-input v-model="form.startTime" type="number" placeholder="请输入起步时长" >
|
||||
<template #append>
|
||||
<el-select v-model="form.startUnit" style="width: 6em">
|
||||
<el-option v-for="dict in dict.type.time_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</form-col>
|
||||
<form-col :span="span" label="起步价" prop="startPrice">
|
||||
<el-input v-model="form.startPrice" type="number" placeholder="请输入起步价" >
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</form-col>
|
||||
<form-col :span="span" label="续期时长" prop="overTime">
|
||||
<el-input v-model="form.overTime" type="number" placeholder="请输入续期时长" >
|
||||
<template #append>
|
||||
<el-select v-model="form.overUnit" style="width: 6em">
|
||||
<el-option v-for="dict in dict.type.time_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</form-col>
|
||||
<form-col :span="span" label="续期价" prop="overPrice">
|
||||
<el-input v-model="form.overPrice" type="number" placeholder="请输入续期价" >
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</form-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!--型号选择弹窗-->
|
||||
<model-dialog
|
||||
:show.sync="showCheckModel"
|
||||
@select="onSubmitBatchModel"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listDevice,
|
||||
getDevice,
|
||||
addDevice,
|
||||
updateDevice,
|
||||
logicDelDevice,
|
||||
updateDeviceSn,
|
||||
batchUpdateModel, updateDeviceServiceRate
|
||||
} from '@/api/system/device'
|
||||
import ModelSelect from "@/components/Business/Model/modelSelect.vue";
|
||||
import SmUserSelect from "@/components/Business/SmUser/smUserSelect.vue";
|
||||
import QrCode from "@/components/QrCode/index.vue";
|
||||
import {getWxIndexUrl} from "@/utils/wx";
|
||||
import SnInput from '@/components/SnInput/index.vue'
|
||||
import StoreInput from '@/components/Business/Store/StoreInput.vue'
|
||||
import UserInput from '@/components/Business/SmUser/UserInput.vue'
|
||||
import { isEmpty } from '@/utils'
|
||||
import ModelDialog from '@/components/Business/Model/modelDialog.vue'
|
||||
import UserLink from '@/components/Business/SmUser/UserLink.vue'
|
||||
import StoreLink from '@/components/Business/Store/StoreLink.vue'
|
||||
import DeviceLink from '@/components/Business/Device/DeviceLink.vue'
|
||||
import { $serviceType } from '@/utils/mixins'
|
||||
import { mchGetDevice, mchListDevice, mchUnbindDevice, mchUpdateDevice } from '@/api/mch/device'
|
||||
|
||||
export default {
|
||||
name: "MyDevice",
|
||||
mixins: [$serviceType],
|
||||
components: { DeviceLink, StoreLink, UserLink, ModelDialog, UserInput, StoreInput, SnInput, QrCode, SmUserSelect, ModelSelect},
|
||||
dicts: ['sm_device_online_status', 'sm_device_status', 'sm_device_outage_way','sm_device_notice_way', 'service_type', 'time_unit'],
|
||||
data() {
|
||||
return {
|
||||
// 是否展示选择型号弹窗
|
||||
showCheckModel: false,
|
||||
span: 12,
|
||||
gutter: 8,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 设备表格数据
|
||||
deviceList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
storeName: null,
|
||||
deviceName: null,
|
||||
model: null,
|
||||
mac: null,
|
||||
deviceNo: null,
|
||||
onlineStatus: null,
|
||||
status: null,
|
||||
userName: null,
|
||||
tenantName: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
modelId: [
|
||||
{ required: true, message: "型号不能为空", trigger: "change" }
|
||||
],
|
||||
mac: [
|
||||
{ required: true, message: "设备MAC不能为空", trigger: "change" }
|
||||
],
|
||||
},
|
||||
// 房租提醒日期选项配置
|
||||
expireDatePickerOptions: {
|
||||
disabledDate(date) {
|
||||
return date.getTime() <= Date.now();
|
||||
}
|
||||
},
|
||||
showBindSn: false,
|
||||
snLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
return this.title === "修改设备";
|
||||
},
|
||||
// 二维码文本
|
||||
qrCodeText() {
|
||||
return (device) => {
|
||||
return getWxIndexUrl({ s: device.deviceNo});
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
// 选中型号后
|
||||
onSubmitBatchModel(model) {
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
batchUpdateModel(this.ids, model.modelId).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success("操作成功");
|
||||
this.showCheckModel = false;
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
},
|
||||
isEmpty,
|
||||
handleBindSn(row) {
|
||||
this.form.deviceId = row.deviceId;
|
||||
this.showBindSn = true;
|
||||
},
|
||||
// 绑定SN
|
||||
onSubmitSn(data) {
|
||||
this.snLoading = true;
|
||||
updateDeviceSn(this.form.deviceId, data.sn).then(res => {
|
||||
if (res.code !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success("操作成功");
|
||||
this.showBindSn = false;
|
||||
this.getList();
|
||||
}).finally(()=> {
|
||||
this.snLoading = false;
|
||||
})
|
||||
},
|
||||
// 选中店铺后
|
||||
onSubmitGroup(group) {
|
||||
this.form.groupId = group?.groupId;
|
||||
this.form.groupName = group?.groupName;
|
||||
},
|
||||
// 选中型号后
|
||||
onSubmitModel(model) {
|
||||
this.form.model = model?.modelName;
|
||||
// 若是新增,则填入默认的服务费
|
||||
if (this.form.deviceId == null) {
|
||||
this.form.serviceType = model?.serviceType;
|
||||
this.form.serviceRate = model?.serviceRate;
|
||||
}
|
||||
},
|
||||
/** 查询设备列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
mchListDevice(this.queryParams).then(response => {
|
||||
this.deviceList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
deviceId: null,
|
||||
picture: null,
|
||||
modelId: null,
|
||||
mac: null,
|
||||
deviceNo: null,
|
||||
deviceName: null,
|
||||
serviceType: '1',
|
||||
serviceRate: null,
|
||||
remark: null,
|
||||
startTime: null,
|
||||
startUnit: "3",
|
||||
startPrice: null,
|
||||
overTime: null,
|
||||
overUnit: "3",
|
||||
overPrice: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.deviceId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
// 查看按钮操作
|
||||
handleSee(row) {
|
||||
this.$router.push({path: `/device/${row.deviceId}`})
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加设备";
|
||||
},
|
||||
// 重置服务费
|
||||
handleResetService(row) {
|
||||
this.$confirm(`确定重置设备${row.deviceNo}的服务费吗?`, '重置服务费', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
updateDeviceServiceRate(row.deviceId, null).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success("重置成功")
|
||||
}
|
||||
}).finally(() => {
|
||||
this.getList();
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const deviceId = row.deviceId || this.ids
|
||||
mchGetDevice(deviceId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改设备";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.deviceId != null) {
|
||||
mchUpdateDevice(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
handleBatchModel() {
|
||||
this.showCheckModel = true;
|
||||
},
|
||||
/** 解绑按钮操作 */
|
||||
handleUnbind(row) {
|
||||
this.$modal.confirm(`是否确认解绑设备"${row.deviceName}"(SN:${row.deviceNo})?`).then(function() {
|
||||
return mchUnbindDevice(row.deviceId);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("解绑成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('system/device/export', {
|
||||
...this.queryParams
|
||||
}, `device_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
104
src/views/mch/store/components/storeRechargeReport.vue
Normal file
104
src/views/mch/store/components/storeRechargeReport.vue
Normal file
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row type="flex">
|
||||
<el-tabs v-model="queryParams.groupBy" style="width: 100%">
|
||||
<el-tab-pane label="月报表" name="create_month">
|
||||
<range-picker v-model="queryParams.year" @change="onChangeYear" suffix="年"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-row>
|
||||
<single-line-chart v-loading="loading" :labels="labels" :chart-data="chartData" name="收入" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleLineChart from "@/components/SingleLineChart/index.vue";
|
||||
import RangePicker from "@/components/RangePicker/index.vue";
|
||||
import {countBill, listBill} from "@/api/system/recharge";
|
||||
import { mchCountBill } from '@/api/mch/bill'
|
||||
|
||||
export default {
|
||||
name: 'MyStoreRechargeReport',
|
||||
components: {RangePicker, SingleLineChart},
|
||||
props: {
|
||||
// 店铺id
|
||||
storeId: {
|
||||
type: String,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
labels: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], // x轴
|
||||
chartData: [], // 报表数据
|
||||
queryParams: {
|
||||
type: 1,
|
||||
year: new Date().getFullYear(),
|
||||
status: "2",
|
||||
groupBy: "create_month",
|
||||
storeId: this.storeId,
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
storeId(nv, ov) {
|
||||
this.getReportData(nv);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 当年份发生变化
|
||||
onChangeYear(year) {
|
||||
console.log(year);
|
||||
this.queryParams.year = year;
|
||||
this.getReportData(this.storeId);
|
||||
},
|
||||
// 获取到账人的报表
|
||||
getReportData(storeId) {
|
||||
this.loading = true;
|
||||
this.queryParams.storeId = storeId | this.storeId;
|
||||
mchCountBill(this.queryParams).then(response => {
|
||||
let data = response.data;
|
||||
// 按月统计数据
|
||||
let list = [];
|
||||
if (data != null) {
|
||||
for (let i = 1; i <= this.getReportMonth(); i ++) {
|
||||
let monthData = data.find(item => item.createMonth === i);
|
||||
list[i - 1] = monthData == null ? 0 : monthData.recharge;
|
||||
}
|
||||
}
|
||||
this.chartData = list;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
// 获取报表显示的月份
|
||||
getReportMonth() {
|
||||
let now = new Date();
|
||||
let nowYear = new Date().getFullYear()
|
||||
let paramYear = this.queryParams.year;
|
||||
if (paramYear < nowYear) {
|
||||
return 12;
|
||||
}
|
||||
if (paramYear === nowYear) {
|
||||
return now.getMonth() + 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
// 获取字符串时间的月份
|
||||
getMonth(str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
return new Date(str).getMonth() + 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
line-height: 36px;
|
||||
}
|
||||
</style>
|
151
src/views/mch/store/detail.vue
Normal file
151
src/views/mch/store/detail.vue
Normal file
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<div class="app-container" v-loading="loading">
|
||||
<el-card class="box-card" header="店铺详情">
|
||||
<el-row type="flex">
|
||||
<image-preview :src="store.picture" :width="80" :height="80"/>
|
||||
<div style="flex: 1;margin-left: 2em">
|
||||
<el-descriptions>
|
||||
<el-descriptions-item label="店铺名称">{{store.name | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺类型">
|
||||
<dict-tag :value="store.type" :options="dict.type.ss_store_type" size="small"/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="所属商户">{{store.userName | defaultValue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="营业时间">
|
||||
{{store.businessTimeStart | defaultValue}} 至 {{store.businessTimeEnd | defaultValue}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺地址" :span="2">
|
||||
{{store.province}}{{store.city}}{{store.county}}{{store.address}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联系方式">{{store.contactName | defaultValue}}({{store.contactMobile | defaultValue}})</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{store.createTime | defaultValue}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="18">
|
||||
|
||||
|
||||
<el-card class="box-card" >
|
||||
<el-row type="flex">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="store.todayIncome"
|
||||
suffix="¥"
|
||||
title="今日收入"
|
||||
></el-statistic>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="store.monthIncome"
|
||||
suffix="¥"
|
||||
title="本月收入"
|
||||
></el-statistic>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="store.lastMonthIncome"
|
||||
suffix="¥"
|
||||
title="上月收入"
|
||||
></el-statistic>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:value="store.deviceCount"
|
||||
suffix="台"
|
||||
title="设备总数"
|
||||
></el-statistic>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:value="store.onlineCount"
|
||||
suffix="台"
|
||||
title="在线设备"
|
||||
></el-statistic>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:value="store.offlineCount"
|
||||
suffix="台"
|
||||
title="离线设备"
|
||||
></el-statistic>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<el-card class="box-card">
|
||||
<my-store-recharge-report :store-id="store.storeId"/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="box-card">
|
||||
<place-search-map
|
||||
v-if="showMap"
|
||||
height="534px"
|
||||
:init-lng="store.lng"
|
||||
:init-lat="store.lat"
|
||||
enable-geo
|
||||
marker-type="store"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="box-card">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="设备列表" :lazy="true">
|
||||
<my-device :store-id="store.storeId"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="订单列表" :lazy="true">
|
||||
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PlaceSearchMap from '@/components/Map/PlaceSearch/PlaceSearchMap.vue'
|
||||
import { mchGetStore } from '@/api/mch/store'
|
||||
import MyStoreRechargeReport from '@/views/mch/store/components/storeRechargeReport.vue'
|
||||
import MyDevice from '@/views/mch/device/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'MyStoreDetail',
|
||||
components: { MyDevice, MyStoreRechargeReport, PlaceSearchMap },
|
||||
dicts: ['ss_store_type'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
store: {},
|
||||
showMap: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDetail();
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
this.loading = true;
|
||||
mchGetStore(this.$route.params.storeId).then(res => {
|
||||
this.store = res.data;
|
||||
this.showMap = true;
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.remark-text {
|
||||
color: #ccc;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.app-container .box-card:nth-child(n + 1) {
|
||||
margin-top: 1em;
|
||||
}
|
||||
</style>
|
410
src/views/mch/store/index.vue
Normal file
410
src/views/mch/store/index.vue
Normal file
|
@ -0,0 +1,410 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="店铺名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="danger"-->
|
||||
<!-- plain-->
|
||||
<!-- icon="el-icon-delete"-->
|
||||
<!-- size="mini"-->
|
||||
<!-- :disabled="multiple"-->
|
||||
<!-- @click="handleDelete"-->
|
||||
<!-- >删除</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="warning"-->
|
||||
<!-- plain-->
|
||||
<!-- icon="el-icon-download"-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="handleExport"-->
|
||||
<!-- >导出</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="storeList" @selection-change="handleSelectionChange">
|
||||
<!-- <el-table-column type="selection" width="55" align="center" />-->
|
||||
<el-table-column type="index" width="55" align="center" label="#" />
|
||||
<el-table-column label="店铺图片" align="center" prop="picture" width="100">
|
||||
<template slot-scope="scope">
|
||||
<image-preview :src="scope.row.picture" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="店铺名称" align="center" prop="name" >
|
||||
<store-link slot-scope="d" :id="d.row.storeId" :name="d.row.name"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="店铺类型" align="center" prop="type" width="100">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :value="scope.row.type" :options="dict.type.ss_store_type"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="营业时间" align="center" min-width="100">
|
||||
<template slot-scope="d">
|
||||
{{d.row.businessTimeStart}} 至 {{d.row.businessTimeEnd}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="门店地址" align="center">
|
||||
<template slot-scope="d">
|
||||
{{d.row.province}}{{d.row.city}}{{d.row.county}}{{d.row.address}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleView(scope.row)"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改店铺列表对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="50%" append-to-body :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row :gutter="8">
|
||||
<form-col label="店铺图片" prop="picture" :span="span * 2">
|
||||
<image-upload v-model="form.picture" :limit="9"/>
|
||||
</form-col>
|
||||
<form-col label="店铺名称" prop="name" :span="span">
|
||||
<el-input v-model="form.name" placeholder="请输入店铺名称" />
|
||||
</form-col>
|
||||
<form-col label="店铺类型" prop="type" :span="span">
|
||||
<el-select v-model="form.type" placeholder="请选择店铺类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="opt of dict.type.ss_store_type"
|
||||
:label="opt.label"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</form-col>
|
||||
<form-col label="营业时间" prop="businessTimeStart" :span="span">
|
||||
<el-time-picker
|
||||
is-range
|
||||
v-model="formatBusinessTime"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
:clearable="false"
|
||||
style="width: 100%"
|
||||
placeholder="请选择营业时间范围">
|
||||
</el-time-picker>
|
||||
</form-col>
|
||||
<form-col label="是否在地图展示" prop="show" :span="span" label-width="9em">
|
||||
<el-switch v-model="form.show"/>
|
||||
</form-col>
|
||||
<form-col label="定位地址" prop="address" :span="span * 2">
|
||||
<el-input v-model="form.address" placeholder="请输入店铺地址">
|
||||
<template #prepend>
|
||||
<div>
|
||||
{{form.province}}{{form.city}}{{form.county}}
|
||||
</div>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button @click="showPlaceSearchMap = true" icon="el-icon-location">选择定位</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</form-col>
|
||||
<form-col label="联系人" prop="contactName" :span="span">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人"/>
|
||||
</form-col>
|
||||
<form-col label="联系电话" prop="contactMobile" :span="span">
|
||||
<el-input v-model="form.contactMobile" placeholder="请输入联系电话" maxlength="11" show-word-limit/>
|
||||
</form-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<place-search-dialog
|
||||
:show.sync="showPlaceSearchMap"
|
||||
:init-lat="form.lat"
|
||||
:init-lng="form.lng"
|
||||
@submit="onSubmitAddress"
|
||||
marker-type="store"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserInput from '@/components/Business/SmUser/UserInput.vue'
|
||||
import PlaceSearchDialog from '@/components/Map/PlaceSearch/PlaceSearchDialog.vue'
|
||||
import AreaTextSelect from '@/components/AreaTextSelect/index.vue'
|
||||
import { parseTime } from '@/utils/ruoyi'
|
||||
import { $view } from '@/utils/mixins'
|
||||
import UserLink from '@/components/Business/SmUser/UserLink.vue'
|
||||
import StoreLink from '@/components/Business/Store/StoreLink.vue'
|
||||
import { mchAddStore, mchDelStore, mchGetStore, mchListStore, mchUpdateStore } from '@/api/mch/store'
|
||||
|
||||
export default {
|
||||
name: "MyStore",
|
||||
mixins: [$view],
|
||||
dicts: ['ss_store_type'],
|
||||
components: { StoreLink, UserLink, AreaTextSelect, PlaceSearchDialog, UserInput },
|
||||
props: {
|
||||
query: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 店铺列表表格数据
|
||||
storeList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
storeId: null,
|
||||
userId: null,
|
||||
name: null,
|
||||
address: null,
|
||||
deleted: null
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
userId: [
|
||||
{ required: true, message: "用户不能为空", trigger: "change" }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: "店铺名称不能为空", trigger: "change" }
|
||||
],
|
||||
address: [
|
||||
{ required: true, message: "定位地址不能为空", trigger: "change" }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: "店铺类型不能为空", trigger: "change" }
|
||||
],
|
||||
businessTimeStart: [
|
||||
{ required: true, message: "营业时间不允许为空", trigger: "change" }
|
||||
],
|
||||
contactName: [
|
||||
{ required: true, message: "联系人不允许为空", trigger: "change" }
|
||||
],
|
||||
contactMobile: [
|
||||
{ required: true, message: "联系电话不允许为空", trigger: "change" }
|
||||
],
|
||||
},
|
||||
showPlaceSearchMap: false,
|
||||
span: 12,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
formatBusinessTime: {
|
||||
set(val) {
|
||||
this.form.businessTimeStart = val[0];
|
||||
this.form.businessTimeEnd = val[1];
|
||||
},
|
||||
get() {
|
||||
if (this.form.businessTimeStart == null || this.form.businessTimeEnd == null) {
|
||||
return null;
|
||||
}
|
||||
return [this.form.businessTimeStart, this.form.businessTimeEnd]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.queryParams = {
|
||||
...this.queryParams,
|
||||
...this.query
|
||||
}
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
parseTime,
|
||||
onSubmitAddress(addr) {
|
||||
this.form.address = addr.name;
|
||||
this.form.lat = addr.lat;
|
||||
this.form.lng = addr.lng;
|
||||
this.form.province = addr.province;
|
||||
this.form.city = addr.city;
|
||||
this.form.county = addr.county;
|
||||
this.form.specificAddress = addr.name;
|
||||
},
|
||||
/** 查询店铺列表列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
mchListStore(this.queryParams).then(response => {
|
||||
this.storeList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
storeId: null,
|
||||
userId: this.query.userId,
|
||||
picture: null,
|
||||
name: null,
|
||||
address: null,
|
||||
specificAddress: null,
|
||||
businessTimeStart: "08:00",
|
||||
businessTimeEnd: "18:00",
|
||||
province: "福建省",
|
||||
city: "宁德市",
|
||||
county: "福鼎市",
|
||||
lng: null,
|
||||
lat: null,
|
||||
createTime: null,
|
||||
createBy: null,
|
||||
updateTime: null,
|
||||
updateBy: null,
|
||||
deleted: null,
|
||||
show: true
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.storeId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加店铺列表";
|
||||
},
|
||||
handleView(row) {
|
||||
this.$router.push({
|
||||
path: `/business/store/${row.storeId}`,
|
||||
})
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const storeId = row.storeId || this.ids
|
||||
mchGetStore(storeId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改店铺列表";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.storeId != null) {
|
||||
mchUpdateStore(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
mchAddStore(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
this.$modal.confirm(`是否确认删除店铺${row.storeName}?`).then(function() {
|
||||
return mchDelStore(row.storeId);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('ss/store/export', {
|
||||
...this.queryParams
|
||||
}, `store_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user