提交 f98a35c0 authored 作者: 何忠建's avatar 何忠建

物业缴费+报表统计

上级 1c8592de
......@@ -5,6 +5,12 @@ import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
const homeDataStatistics = (params)=>getAction("/community/homepage/dataStatistics",params);
const companyNoticeList = (params)=>getAction("/property-company/notice/companyNotice/list",params);
// 报表统计
const propertyFeeStatistics = (params)=>getAction("/property-community/payment/communityPayment/propertyFeeStatistics",params);
const paymentStatistics = (params)=>getAction("/property-community/payment/communityPayment/paymentStatistics",params);
const repairStatistics = (params)=>getAction("/property-community/property/communityRepair/repairStatistics",params);
const complaintStatistics = (params)=>getAction("/property-community/property/communityComplaint/complaintStatistics",params);
//角色管理
const addRole = (params)=>postAction("/sys/role/add",params);
const editRole = (params)=>putAction("/sys/role/edit",params);
......@@ -74,6 +80,8 @@ const auditCommunityOwnerApi = (params)=>postAction("/property-community/info/co
const downloadOwnerTemplate = (params)=>postAction("/property-community/info/communityOwner/downloadOwnerTemplate",params);
// 生活缴费-费用规则
const companyPropertyChargerulesApi = (params)=>getAction("/property-company/system/companyChargerule/companyPropertyChargerules",params);
const getTotalMoneyApi = (params)=>getAction("/property-community/payment/communityPayment/getTotalMoney",params);
const geCommunityRuleListApi = (params)=>getAction("/property-company/system/companyChargerule/communityRuleList",params);
const queryByRoomIdApi = (params)=>getAction("/property-community/info/communityOwner/queryByRoomId",params);
const queryLastDegreesByIdApi = (params)=>getAction("/property-community/payment/communityPayment/queryLastDegreesById",params);
......@@ -136,6 +144,10 @@ export const transitRESTful = {
export {
homeDataStatistics,
companyNoticeList,
propertyFeeStatistics,
paymentStatistics,
repairStatistics,
complaintStatistics,
addRole,
editRole,
checkRoleCode,
......@@ -201,6 +213,8 @@ export {
geCommunityOwnertInfoApi,
auditCommunityOwnerApi,
geCommunityRuleListApi,
companyPropertyChargerulesApi,
getTotalMoneyApi,
queryByRoomIdApi,
queryLastDegreesByIdApi,
callPayMentApi,
......
......@@ -35,6 +35,10 @@
<a-button type="primary" icon="import">导入</a-button>
</a-upload>
<a-button type="primary" icon="download" @click="handleExportXls('生活缴费')">导出</a-button>
<div style="float: right; color: #f00;">
<span style="margin-right: 20px;">已缴费金额 (元):{{ statistical.paidMoney || 0 }}</span>
<span>待缴费金额 (元):{{ statistical.unPaidMoney || 0 }}</span>
</div>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="onBatchCallpay"><a-icon type="message" />催缴</a-menu-item>
......@@ -88,7 +92,7 @@
</template>
<script>
import { getBuildingListApi, getUnitListApi, getRoomListApi, callPayMentApi } from '@/api/api'
import { getBuildingListApi, getUnitListApi, getRoomListApi, callPayMentApi,getTotalMoneyApi } from '@/api/api'
import { downFile } from '@/api/manage'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import NoticeModal from './modules/NoticeModal'
......@@ -215,11 +219,12 @@ export default {
downloadExcelUrl: '/property-community/payment/communityPayment/downloadPaymentTemplate',
},
treeData: [],
statistical: {},
}
},
created() {
this.getBuildingList()
// this.initDictData()
this.getTotalMoney()
},
computed: {
importExcelUrl: function () {
......@@ -243,6 +248,10 @@ export default {
}
})
},
async getTotalMoney() {
let { result } = await getTotalMoneyApi({ type: 'payment' })
this.statistical = result
},
onClickTree(value, option) {
console.log(value, option)
let level = option.node.pos.split('-').length
......
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
switchFullscreen
@ok="handleOk"
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
@cancel="handleCancel"
cancelText="关闭">
<property-settled-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></property-settled-form>
</j-modal>
</template>
<script>
import PropertySettledForm from './NoticeForm'
export default {
name: 'PropertySettledModal',
components: {
PropertySettledForm
},
data () {
return {
title:'',
width: '70%',
visible: false,
disableSubmit: false
}
},
methods: {
add () {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.add();
})
},
edit (record) {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.edit(record);
})
},
close () {
this.$emit('close');
this.visible = false;
},
handleOk () {
this.$refs.realForm.submitForm();
},
submitCallback(){
this.$emit('ok');
this.visible = false;
},
handleCancel () {
this.close()
}
}
}
</script>
\ No newline at end of file
差异被折叠。
<template>
<div class="page-content">
<a-spin :spinning="confirmLoading">
<div style="padding:24px 30px;font-weight:600;">投诉详情</div>
<j-form-container :disabled="true">
<a-form-model ref="form" :model="model" slot="detail">
<a-row>
<a-col :span="12">
<a-form-model-item label="投诉主题" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="complaintTheme">
<a-input v-model="model.complaintTheme" placeholder="请输入"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="投诉人" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userName">
<a-input v-model="model.userName" placeholder="请输入"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="联系方式" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userPhone">
<a-input v-model="model.userPhone" placeholder="请输入"></a-input>
</a-form-model-item>
</a-col>
<!-- <a-col :span="12">
<a-form-model-item label="住户地址" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="repairAddress">
<a-input v-model="model.repairAddress" placeholder="请输入"></a-input>
</a-form-model-item>
</a-col> -->
<a-col :span="12">
<a-form-model-item label="投诉时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="createTime">
<a-input v-model="model.createTime" placeholder="请输入"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="complaintImg">
<j-image-upload bizPath="scott/pic" accept="image/png, image/jpeg"
v-model="model.complaintImg"></j-image-upload>
</a-form-model-item>
</a-col>
<a-col :span="24">
<a-form-model-item label="问题描述" :labelCol="{ xs: { span: 24 }, sm: { span: 2 } }" :wrapperCol="wrapperCol"
prop="problemDesc">
<a-textarea v-model="model.problemDesc" placeholder="请输入" style="width:80%" />
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</j-form-container>
<j-form-container v-if="!formDisabled || model.handleStatus == 'finish'"
:disabled="model.handleStatus == 'finish'">
<a-form-model ref="form" :model="form" slot="detail">
<a-row>
<a-col :span="24">
<a-form-model-item label="处理状态" :labelCol="{ xs: { span: 24 }, sm: { span: 2 } }" :wrapperCol="wrapperCol"
prop="handleStatus">
<a-select v-model="form.handleStatus" placeholder="请选择处理状态" style="width:50%">
<a-select-option value="pending">处理中</a-select-option>
<a-select-option value="finish">处理完成</a-select-option>
</a-select>
</a-form-model-item>
</a-col>
<a-col :span="24">
<a-form-model-item label="处理结果" :labelCol="{ xs: { span: 24 }, sm: { span: 2 } }" :wrapperCol="wrapperCol"
prop="handleResult">
<a-textarea v-model="form.handleResult" placeholder="请输入" style="width:80%" />
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</j-form-container>
<div style="text-align:center">
<a-button @click="onReturn">返回</a-button>
<a-button style="margin-left: 16px" type="primary" v-if="!formDisabled" @click="onSubmit">提交</a-button>
</div>
</a-spin>
</div>
</template>
<script>
import { querycommunityComplaintApi, auditCommunityComplaintApi } from '@/api/api'
export default {
name: 'PropertyChargruleForm',
inject: ['closeCurrent'],
data() {
return {
currentStep: 1,
model: {},
form: {
handleStatus: 'pending',
handleResult: '',
},
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 },
},
confirmLoading: false,
}
},
computed: {
formDisabled() {
return this.$route.query.type === '1'
},
},
created() {
//备份model原始值
this.getDetail()
},
methods: {
async getDetail() {
this.confirmLoading = true
let { result } = await querycommunityComplaintApi({ id: this.$route.query.id })
this.model = { ...result }
if (this.model.handleStatus == 'finish') {
this.form.handleStatus = this.model.handleStatus
this.form.handleResult = this.model.handleResult
}
this.confirmLoading = false
},
onReturn() {
this.$store.dispatch('tags/delView', this.$route.path)
this.$router.go(-1)
},
async onSubmit() {
let res = await auditCommunityComplaintApi({
id: this.$route.query.id,
handleStatus: this.form.handleStatus,
handleResult: this.form.handleResult,
})
this.$message.success(res.message)
this.$store.dispatch('tags/delView', this.$route.path)
this.$router.go(-1)
},
},
}
</script>
<style scoped lang="less">
.page-content {
min-height: 430px;
background-color: #fff;
padding: 0 15px 50px 5px;
.row-box {
padding: 0 50px;
}
}
</style>
\ No newline at end of file
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<a-form-item label="投诉单号">
<j-input placeholder="请输入投诉单号" v-model="queryParam.complaintNo"></j-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-form-model-item label="状态">
<a-select style="width: 100%" v-model="queryParam.handleStatus" placeholder="请选择状态">
<a-select-option v-for="item in dictOptions" :key="item.value"
:value="item.value">{{item.label}}</a-select-option>
</a-select>
</a-form-model-item>
</a-col>
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a-button type="primary" @click="searchQuery">查询</a-button>
<a-button style="margin-left: 8px" @click="searchReset">重置</a-button>
</a-col>
</span>
</a-row>
</a-form>
</div>
<!-- table区域-begin -->
<div>
<a-row :gutter="24">
<a-col :sm="24" :md="12" :xl="14" :style="{ marginBottom: '24px' }">
<a-table ref="table" size="middle" :scroll="{x:true}" bordered rowKey="id" :columns="columns"
:dataSource="dataSource" :pagination="ipagination" :loading="loading" class="j-table-force-nowrap"
@change="handleTableChange">
</a-table>
</a-col>
<a-col :sm="24" :md="12" :xl="10" :style="{ marginBottom: '24px' }">
<div class="pay-cost t-box">
<h3 class="box-title">投诉</h3>
<pie :dataSource="repairData" />
<div class="number">
<p>全部报修 {{totalNum}}</p>
<p v-for="(item, index) in repairData" :key="index">{{ item.item }} {{ item.count }}</p>
</div>
</div>
</a-col>
</a-row>
</div>
<!-- table区域-end -->
</a-card>
</template>
<script>
import { complaintStatistics } from '@/api/api'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import { COMPLAINT_STATUS, filterDictTextByStatic } from '@/assets/static.js'
import Pie from '@/components/chart/Pie'
const columns = [
{
title: '投诉工单',
dataIndex: 'complaintNo',
key: 'complaintNo',
width: 130,
align: 'center',
},
{
title: '投诉主题',
dataIndex: 'complaintTheme',
key: 'complaintTheme',
align: 'center',
},
// {
// title: '问题描述',
// dataIndex: 'problemDesc',
// key: 'problemDesc',
// align: 'center',
// },
{
title: '投诉人',
dataIndex: 'userName',
key: 'userName',
align: 'center',
},
{
title: '联系方式',
dataIndex: 'userPhone',
key: 'userPhone',
align: 'center',
},
{
title: '状态',
dataIndex: 'handleStatus',
key: 'handleStatus',
align: 'center',
customRender: function (text) {
return filterDictTextByStatic(COMPLAINT_STATUS, text)
},
},
]
export default {
name: 'PermissionListAsync',
mixins: [JeecgListMixin],
components: { Pie },
data() {
return {
dictOptions: COMPLAINT_STATUS,
// 表头
columns: columns,
url: {
list: '/property-community/property/communityComplaint/list'
},
repairData:[],
totalNum:0
}
},
created() {
this.onDetail()
},
methods: {
async onDetail(typeCode) {
let { result } = await complaintStatistics({ typeCode: typeCode })
this.totalNum = result.totalNum
this.repairData = [
// { item: '全部报修', count: result.repairTotal || 0 },
// { item: '待派单', count: result.waitDispatch || 0 },
{ item: '未完成', count: result.incompleteNum|| 0 },
{ item: '已完成', count: result.finishComplaintNum || 0 },
]
},
},
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style lang="less" scoped>
.number {
width: 80%;
margin: 0 10%;
display: flex;
justify-content: space-evenly;
p {
font-size: 14px;
margin: 0;
}
}
.pay-cost{
height: 506px;
}
.t-box {
background: #fff;
padding: 15px;
border: 1px solid #e8e8e8;
}
.box-title {
font-weight: bold;
margin-bottom: 15px;
display: inline-block;
padding-left: 10px;
border-left: 3px solid #1890ff;
height: 20px;
line-height: 20px;
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="confirmLoading">
<j-form-container :disabled="formDisabled">
<a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail">
<a-row>
<a-col :span="12">
<a-form-model-item label="投诉主题" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="complaintTheme">
<a-input v-model="model.complaintTheme" readonly placeholder="请输入投诉主题"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="投诉人" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userName">
<a-input v-model="model.userName" placeholder="请输入投诉人"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="联系方式" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userPhone">
<a-input v-model="model.userPhone" placeholder="请输入联系方式"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="住户地址" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userAddress">
<a-input v-model="model.userAddress" placeholder="请输入住户地址"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="投诉时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="complaintTime">
<a-input v-model="model.complaintTime" placeholder="请输入投诉时间"></a-input>
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item label="问题描述" :labelCol="{ xs:{ span: 24 }, sm:{ span: 3 } }" :wrapperCol="wrapperCol" prop="problemDesc">
<a-textarea placeholder="请输入问题描述" v-model="model.problemDesc" :auto-size="{ minRows: 3, maxRows: 5 }" allow-clear />
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item label="处理结果" :labelCol="{ xs:{ span: 24 }, sm:{ span: 3 } }" :wrapperCol="wrapperCol" prop="handleResult">
<a-textarea placeholder="请输入处理结果" v-model="model.handleResult" :auto-size="{ minRows: 3, maxRows: 5 }" allow-clear />
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item label="处理状态" :labelCol="{ xs:{ span: 24 }, sm:{ span: 3 } }" :wrapperCol="wrapperCol" prop="handleStatus">
<a-select style="width: 100%" v-model="model.handleStatus" placeholder="请选择处理状态">
<a-select-option v-for="item in dictOptions" :key="item.value" :value="item.value">{{item.label}}</a-select-option>
</a-select>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</j-form-container>
</a-spin>
</template>
<script>
import { httpAction, getAction } from '@/api/manage'
import { validateDuplicateValue } from '@/utils/util'
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
export default {
name: 'PropertyChargruleForm',
components: {
},
props: {
//表单禁用
disabled: {
type: Boolean,
default: false,
required: false
}
},
data () {
return {
dictOptions: [],
model:{
complaintTheme: '',
userName: '',
userPhone: '',
userAddress: '',
complaintTime: '',
problemDesc: '',
handleResult: '',
handleStatus: ''
},
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
confirmLoading: false,
validatorRules: {
complaintTheme: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
employeePhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
employeeDuties: [{ required: true, message: '请选择员工职务', trigger: 'change' }]
},
url: {
add: "/property-community/employee/companyEmployee/add",
edit: "/property-community/property/communityComplaint/edit",
queryById: "/property-community/property/communityComplaint/queryById"
}
}
},
computed: {
formDisabled(){
return this.disabled
},
},
created () {
//备份model原始值
this.modelDefault = JSON.parse(JSON.stringify(this.model));
this.initDictData()
},
methods: {
initDictData() {
//优先从缓存中读取字典配置
if(getDictItemsFromCache('complaint_status')){
this.dictOptions = getDictItemsFromCache('complaint_status');
return
}
// //根据字典Code, 初始化字典数组
ajaxGetDictItems('complaint_status', null).then((res) => {
if (res.success) {
this.dictOptions = res.result;
}
})
},
ruleNumberInput(event) {
let rateValue = event.target.value.replace(/[^\d]/g,"");//清除"数字"和"."和"-"以外的字符
this.model['empowerDays'] = rateValue
},
add () {
this.edit(this.modelDefault);
},
edit (record) {
console.log(record)
this.model = Object.assign({}, record);
this.visible = true;
},
submitForm () {
const that = this;
// 触发表单验证
this.$refs.form.validate(valid => {
if (valid) {
that.confirmLoading = true;
let httpurl = '';
let method = '';
if(!this.model.id){
httpurl+=this.url.add;
method = 'post';
}else{
httpurl+=this.url.edit;
method = 'put';
}
httpAction(httpurl,this.model,method).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.$emit('ok');
}else{
that.$message.warning(res.message);
}
}).finally(() => {
that.confirmLoading = false;
})
}
})
},
}
}
</script>
\ No newline at end of file
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
switchFullscreen
@ok="handleOk"
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
@cancel="handleCancel"
cancelText="关闭">
<property-settled-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></property-settled-form>
</j-modal>
</template>
<script>
import PropertySettledForm from './NoticeForm'
export default {
name: 'PropertySettledModal',
components: {
PropertySettledForm
},
data () {
return {
title:'',
width: '70%',
visible: false,
disableSubmit: false
}
},
methods: {
add () {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.add();
})
},
edit (record) {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.edit(record);
})
},
close () {
this.$emit('close');
this.visible = false;
},
handleOk () {
this.$refs.realForm.submitForm();
},
submitCallback(){
this.$emit('ok');
this.visible = false;
},
handleCancel () {
this.close()
}
}
}
</script>
\ No newline at end of file
<template>
<div class="hone-content-box">
<a-row :gutter="24">
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#1890ff;"><a-icon type="area-chart" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">已缴水费</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.waterFeePaidTotal}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#7262fd;"><a-icon type="pie-chart" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">已缴电费</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.electricFeePaidTotal}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#ffaa00;"><a-icon type="bar-chart" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">已缴燃气费</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.gasFeePaidTotal}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#52c41a;"><a-icon type="dot-chart" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">已缴暖气费</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.heatFeePaidTotal}}</p>
</div>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<div class="pay-cost t-box">
<div class="pay-cost-tit">水费统计</div>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource1" />
</a-col>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource2" />
</a-col>
</div>
</a-row>
<a-row :gutter="24">
<div class="pay-cost t-box">
<div class="pay-cost-tit">电费统计</div>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource3" />
</a-col>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource4" />
</a-col>
</div>
</a-row>
<a-row :gutter="24">
<div class="pay-cost t-box">
<div class="pay-cost-tit">燃气费统计</div>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource5" />
</a-col>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource6" />
</a-col>
</div>
</a-row>
<a-row :gutter="24">
<div class="pay-cost t-box">
<div class="pay-cost-tit">暖气费统计</div>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource7" />
</a-col>
<a-col :sm="24" :md="12" :xl="12">
<pie :dataSource="dataSource8" />
</a-col>
</div>
</a-row>
<a-row :gutter="24">
<a-col :sm="24" :md="24" :xl="24" :style="{ marginBottom: '24px' }">
<div class="salesCard t-box">
<!-- <h3 class="box-title">缴费统计</h3> -->
<div class="extra-type">
<a-radio-group @change="handleSizeChange" :value="typeCode">
<a-radio-button value="1">水费</a-radio-button>
<a-radio-button value="2">电费</a-radio-button>
<a-radio-button value="3">燃气费</a-radio-button>
<a-radio-button value="4">暖气费</a-radio-button>
<a-radio-button value="5">已缴金额</a-radio-button>
</a-radio-group>
</div>
<div>
<bar :dataSource="barData" style="padding: 0;" />
</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script>
import Bar from '@/components/chart/Bar'
import Pie from '@/components/chart/Pie'
import { paymentStatistics, companyNoticeList } from '@/api/api'
// const barData = []
// for (let i = 0; i < 12; i += 1) {
// barData.push({
// x: `${i + 1}月`,
// y: 1000,
// })
// }
export default {
name: 'Analysis',
components: {
Bar,
Pie,
},
data() {
return {
pageForm: {},
loading: true,
dataSource1:[],
dataSource2:[],
dataSource3:[],
dataSource4:[],
dataSource5:[],
dataSource6:[],
dataSource7:[],
dataSource8:[],
typeCode: '1',
repairData: [],
complaintsData: [],
barData: [],
visible: false,
}
},
created() {
this.onDetail('1')
},
methods: {
async onDetail(typeCode) {
let { result } = await paymentStatistics({ beginDate: '', endDate: '' })
this.pageForm = { ...result }
this.barData = result.monthlyStatistics.map((item) => {
var num = '';
if(typeCode == '1'){
num = item.waterFeePaidTotal
}else if(typeCode == '2'){
num = item.electricFeePaidTotal
}else if(typeCode == '3'){
num = item.gasFeePaidTotal
}else if(typeCode == '4'){
num = item.heatFeePaidTotal
}else if(typeCode == '5'){
num = item.totalAmount
}
return {
x: item.monthNum + '月',
y: num
}
})
this.dataSource1 = [
{ item: '未缴总金额', count: result.waterFeeUnPaidTotal || 0 },
{ item: '已缴总金额', count: result.waterFeePaidTotal || 0 },
]
this.dataSource2 = [
{ item: '未缴纳业主', count: result.electricFeeUnPaidOwnerNum || 0 },
{ item: '已缴纳业主', count: result.waterFeePaidOwnerNum || 0 },
]
this.dataSource3 = [
{ item: '未缴总金额', count: result.electricFeeUnPaidTotal || 0 },
{ item: '已缴总金额', count: result.electricFeePaidTotal || 0 },
]
this.dataSource4 = [
{ item: '未缴纳业主', count: result.electricFeeUnPaidOwnerNum || 0 },
{ item: '已缴纳业主', count: result.electricFeePaidOwnerNum || 0 },
]
this.dataSource5 = [
{ item: '未缴总金额', count: result.gasFeeUnPaidTotal || 0 },
{ item: '已缴总金额', count: result.gasFeePaidTotal || 0 },
]
this.dataSource6 = [
{ item: '未缴纳业主', count: result.gasFeeUnPaidOwnerNum || 0 },
{ item: '已缴纳业主', count: result.gasFeePaidOwnerNum || 0 },
]
this.dataSource7 = [
{ item: '未缴总金额', count: result.heatFeeUnPaidTotal || 0 },
{ item: '已缴总金额', count: result.heatFeePaidTotal || 0 },
]
this.dataSource8 = [
{ item: '未缴纳业主', count: result.heatFeeUnPaidOwnerNum || 0 },
{ item: '已缴纳业主', count: result.heatFeePaidOwnerNum || 0 },
]
this.loading = !this.loading
},
handleSizeChange(e) {
let that = this
this.typeCode = e.target.value
that.onDetail(this.typeCode)
},
},
}
</script>
<style lang="less" scoped>
.hone-content-box {
padding: 10px;
.statistics {
// flex: none;
background: #fff;
width: 100%;
height: 90px;
box-sizing: border-box;
border: 1px solid #e0dfdf;
display: flex;
align-items: center;
padding-left: 20px;
.icon {
width: 50px;
height: 50px;
border-radius: 50px;
margin-right: 12px;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
.anticon {
font-size: 26px;
color: #ffffff;
}
}
}
.pay-box {
display: flex;
.left-box {
flex: none;
width: 50%;
}
}
}
.t-box {
background: #fff;
padding: 15px;
border: 1px solid #e0dfdf;
}
.box-title {
font-weight: bold;
margin-bottom: 15px;
display: inline-block;
padding-left: 10px;
border-left: 3px solid #1890ff;
height: 20px;
line-height: 20px;
}
.pay-cost {
height: 280px;
padding: 50px 0 0;
margin: 0 12px;
position: relative;
.pay-cost-tit {
writing-mode: vertical-rl;
position: absolute;
padding: 0 12px;
text-align: center;
background: #dcedff;
height: 278px;
top: 0;
color: #000;
font-weight: bold;
font-size: 16px;
letter-spacing: 12px;
}
}
.salesCard {
height: 380px;
}
.extra-type {
text-align: center;
a {
margin-right: 20px;
}
}
.number {
width: 80%;
margin: 0 10%;
display: flex;
justify-content: space-evenly;
p {
font-size: 14px;
margin: 0;
}
}
</style>
\ No newline at end of file
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<a-form-item label="报修单号">
<j-input placeholder="请输入报修单号" v-model="queryParam.id"></j-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-form-model-item label="工单状态">
<a-select style="width: 100%" v-model="queryParam.repairStatus" placeholder="请选择工单状态">
<a-select-option v-for="item in repairStatus" :key="item.value"
:value="item.value">{{item.label}}</a-select-option>
</a-select>
</a-form-model-item>
</a-col>
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a-button type="primary" @click="searchQuery">查询</a-button>
<a-button style="margin-left: 8px" @click="searchReset">重置</a-button>
</a-col>
</span>
</a-row>
</a-form>
</div>
<!-- table区域-begin -->
<div>
<a-row :gutter="24">
<a-col :sm="24" :md="12" :xl="14" :style="{ marginBottom: '24px' }">
<a-table ref="table" size="middle" :scroll="{x:true}" bordered rowKey="id" :columns="columns"
:dataSource="dataSource" :pagination="ipagination" :loading="loading" class="j-table-force-nowrap"
@change="handleTableChange">
</a-table>
</a-col>
<a-col :sm="24" :md="12" :xl="10" :style="{ marginBottom: '24px' }">
<div class="pay-cost t-box">
<h3 class="box-title">报修统计</h3>
<pie :dataSource="repairData" />
<div class="number">
<p>全部报修 {{totalNum}}</p>
<p v-for="(item, index) in repairData" :key="index">{{ item.item }} {{ item.count }}</p>
</div>
</div>
</a-col>
</a-row>
</div>
<!-- table区域-end -->
</a-card>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import { dispatchCommunityRepairApi,repairStatistics } from '@/api/api'
import { REPAIR_STATUS, filterDictTextByStatic } from '@/assets/static.js'
import Pie from '@/components/chart/Pie'
const columns = [
{
title: '报修单号',
dataIndex: 'id',
key: 'id',
width: 170,
align: 'center',
ellipsis: true,
},
// {
// title: '报修地址',
// dataIndex: 'repairAddress',
// key: 'repairAddress',
// align: 'center',
// ellipsis: true
// },
{
title: '报修物品',
dataIndex: 'repairArticle',
key: 'repairArticle',
align: 'center',
},
{
title: '报修人',
dataIndex: 'ownerName',
scopedSlots: { customRender: 'ownerName' },
align: 'center',
},
{
title: '工单状态',
dataIndex: 'repairStatus',
key: 'repairStatus',
align: 'center',
customRender: function (text) {
return filterDictTextByStatic(REPAIR_STATUS, text)
},
},
{
title: '报修时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
},
// {
// title: '维修员',
// dataIndex: 'maintenanceName',
// key: 'maintenanceName',
// align: 'center'
// }
]
let currentDispathId = ''
export default {
name: 'PermissionListAsync',
mixins: [JeecgListMixin],
components: {Pie },
data() {
return {
repairStatus: REPAIR_STATUS,
// 表头
columns: columns,
url: {
list: '/property-community/property/communityRepair/list'
},
repairData:[],
totalNum:0
}
},
created() {
this.onDetail()
},
methods: {
async onDetail(typeCode) {
let { result } = await repairStatistics({ typeCode: typeCode })
this.totalNum = result.totalNum
this.repairData = [
// { item: '全部报修', count: result.repairTotal || 0 },
// { item: '待派单', count: result.waitDispatch || 0 },
{ item: '未完成', count: result.incompleteNum|| 0 },
{ item: '已完成', count: result.finishRepairNum || 0 },
]
},
onDispatch(id) {
currentDispathId = id
this.$nextTick(() => {
this.$refs.jPopupOnlReport.show()
})
},
async callBack(rows) {
let row = rows[0]
let res = await dispatchCommunityRepairApi({
id: currentDispathId,
maintainerId: row.id,
maintenanceName: row.employeeName,
maintenancePhone: row.employeePhone,
})
this.$message.success(res.message)
this.searchQuery()
},
},
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style lang="less" scoped>
.number {
width: 80%;
margin: 0 10%;
display: flex;
justify-content: space-evenly;
p {
font-size: 14px;
margin: 0;
}
}
.pay-cost{
height: 506px;
}
.t-box {
background: #fff;
padding: 15px;
border: 1px solid #e8e8e8;
}
.box-title {
font-weight: bold;
margin-bottom: 15px;
display: inline-block;
padding-left: 10px;
border-left: 3px solid #1890ff;
height: 20px;
line-height: 20px;
}
</style>
\ No newline at end of file
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
switchFullscreen
@ok="handleOk"
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
@cancel="handleCancel"
cancelText="关闭">
<property-settled-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></property-settled-form>
</j-modal>
</template>
<script>
import PropertySettledForm from './NoticeForm'
export default {
name: 'PropertySettledModal',
components: {
PropertySettledForm
},
data () {
return {
title:'',
width: '70%',
visible: false,
disableSubmit: false
}
},
methods: {
add () {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.add();
})
},
edit (record) {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.edit(record);
})
},
close () {
this.$emit('close');
this.visible = false;
},
handleOk () {
this.$refs.realForm.submitForm();
},
submitCallback(){
this.$emit('ok');
this.visible = false;
},
handleCancel () {
this.close()
}
}
}
</script>
\ No newline at end of file
<template>
<a-spin :spinning="confirmLoading">
<j-form-container :disabled="formDisabled">
<a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail">
<a-row>
<a-col :span="12">
<a-form-model-item label="报修物品" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="repairArticle">
<a-input v-model="model.repairArticle" placeholder="请输入报修物品"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="报修地址" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="repairAddress">
<a-input v-model="model.repairAddress" placeholder="请输入报修地址"></a-input>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item label="预约上门时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="reservationTime">
<j-date style="width:100%" v-model="model.reservationTime" placeholder="请选择预约上门时间" :showTime="true" dateFormat="YYYY-MM-DD HH:mm:ss"/>
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item label="报修描述" :labelCol="{ xs:{ span: 24 }, sm:{ span: 3 } }" :wrapperCol="wrapperCol" prop="repairDesc">
<a-textarea placeholder="请输入报修描述" v-model="model.repairDesc" :auto-size="{ minRows: 3, maxRows: 5 }" allow-clear />
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item label="报修图片" :labelCol="{ xs:{ span: 24 }, sm:{ span: 3 } }" :wrapperCol="wrapperCol" prop="repairPhoto">
<j-image-upload :isMultiple="false" text="点击上传" bizPath="scott/pic" v-model="model.repairPhoto"></j-image-upload>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</j-form-container>
</a-spin>
</template>
<script>
import { httpAction, getAction } from '@/api/manage'
import { validateDuplicateValue } from '@/utils/util'
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
export default {
name: 'PropertyChargruleForm',
components: {
},
props: {
//表单禁用
disabled: {
type: Boolean,
default: false,
required: false
}
},
data () {
return {
dictOptions: [],
model:{
repairArticle: '',
repairAddress: '',
reservationTime: '',
repairDesc: '',
repairPhoto: ''
},
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
confirmLoading: false,
validatorRules: {
repairArticle: [{ required: true, message: '请输入报修物品', trigger: 'blur' }],
employeeDuties: [{ required: true, message: '请输入报修地址', trigger: 'change' }],
reservationTime: [{ required: true, message: '请选择预约上门时间', trigger: 'change' }],
},
url: {
add: "/property-community/property/communityRepair/add",
edit: "/property-community/property/communityRepair/edit",
queryById: "/property-community/property/communityRepair/queryById"
}
}
},
computed: {
formDisabled(){
return this.disabled
},
},
created () {
//备份model原始值
this.modelDefault = JSON.parse(JSON.stringify(this.model));
this.initDictData()
},
methods: {
initDictData() {
//优先从缓存中读取字典配置
if(getDictItemsFromCache('duties')){
this.dictOptions = getDictItemsFromCache('duties');
return
}
// //根据字典Code, 初始化字典数组
ajaxGetDictItems('duties', null).then((res) => {
if (res.success) {
this.dictOptions = res.result;
}
})
},
ruleNumberInput(event) {
let rateValue = event.target.value.replace(/[^\d]/g,"");//清除"数字"和"."和"-"以外的字符
this.model['empowerDays'] = rateValue
},
add () {
this.edit(this.modelDefault);
},
edit (record) {
console.log(record)
this.model = Object.assign({}, record);
this.visible = true;
},
submitForm () {
const that = this;
// 触发表单验证
this.$refs.form.validate(valid => {
if (valid) {
that.confirmLoading = true;
let httpurl = '';
let method = '';
if(!this.model.id){
httpurl+=this.url.add;
method = 'post';
}else{
httpurl+=this.url.edit;
method = 'put';
}
httpAction(httpurl,this.model,method).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.$emit('ok');
}else{
that.$message.warning(res.message);
}
}).finally(() => {
that.confirmLoading = false;
})
}
})
},
}
}
</script>
\ No newline at end of file
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
switchFullscreen
@ok="handleOk"
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
@cancel="handleCancel"
cancelText="关闭">
<property-settled-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></property-settled-form>
</j-modal>
</template>
<script>
import PropertySettledForm from './NoticeForm'
export default {
name: 'PropertySettledModal',
components: {
PropertySettledForm
},
data () {
return {
title:'',
width: '70%',
visible: false,
disableSubmit: false
}
},
methods: {
add () {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.add();
})
},
edit (record) {
this.visible=true
this.$nextTick(()=>{
this.$refs.realForm.edit(record);
})
},
close () {
this.$emit('close');
this.visible = false;
},
handleOk () {
this.$refs.realForm.submitForm();
},
submitCallback(){
this.$emit('ok');
this.visible = false;
},
handleCancel () {
this.close()
}
}
}
</script>
\ No newline at end of file
<template>
<div class="hone-content-box">
<a-row :gutter="24">
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#1890ff;"><a-icon type="team" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">总人口</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.ownerTotalNum}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#7262fd;"><a-icon type="home" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">业主</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.ownerNum}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#ffaa00;"><a-icon type="user" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">租客</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.tenantNum}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#52c41a;"><a-icon type="bank" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">房屋数量</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.roomNum}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#36cfc9;"><a-icon type="appstore" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">单元数量</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.unitNum}}</p>
</div>
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="4" :style="{ marginBottom: '24px' }">
<div class="statistics">
<div class="icon" style="background-color:#ff7875;"><a-icon type="database" /></div>
<div>
<p style="color:#666;margin-bottom:5px;">楼栋数量</p>
<p style="margin-bottom:0;color:#333;font-size:28px;line-height:1;">{{pageForm.buildingNum}}</p>
</div>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :sm="24" :md="12" :xl="12" :style="{ marginBottom: '24px' }">
<div class="pay-cost t-box">
<pie :dataSource="repairData" />
</div>
</a-col>
<a-col :sm="24" :md="12" :xl="12" :style="{ marginBottom: '24px' }">
<div class="pay-cost t-box">
<pie :dataSource="complaintsData" />
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :sm="24" :md="24" :xl="24" :style="{ marginBottom: '24px' }">
<div class="salesCard t-box">
<!-- <h3 class="box-title">缴费统计</h3> -->
<div class="extra-type">
<a-radio-group @change="handleSizeChange" :value="typeCode">
<a-radio-button value="1">已缴纳总金额</a-radio-button>
<a-radio-button value="2">未缴纳总金额</a-radio-button>
<a-radio-button value="3">已缴纳业主</a-radio-button>
<a-radio-button value="4">未缴纳业主</a-radio-button>
</a-radio-group>
</div>
<div>
<bar :dataSource="barData" style="padding: 0;" />
</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script>
import Bar from '@/components/chart/Bar'
import Pie from '@/components/chart/Pie'
import { propertyFeeStatistics, companyNoticeList } from '@/api/api'
// const barData = []
// for (let i = 0; i < 12; i += 1) {
// barData.push({
// x: `${i + 1}月`,
// y: 1000,
// })
// }
export default {
name: 'Analysis',
components: {
Bar,
Pie,
},
data() {
return {
pageForm: {},
loading: true,
noticeList: [],
typeCode: '2',
repairData: [],
complaintsData: [],
barData: [],
visible: false,
}
},
created() {
this.onDetail('2')
},
methods: {
async onDetail(typeCode) {
console.log(typeCode)
let { result } = await propertyFeeStatistics({ beginDate: '',endDate:'' })
this.pageForm = { ...result }
this.barData = result.monthlyStatistics.map((item) => {
var num = '';
if(typeCode == '1'){
num = item.paidTotal
}else if(typeCode == '2'){
num = item.unPaidTotal
}else if(typeCode == '3'){
num = item.paidOwnerNum
}else if(typeCode == '4'){
num = item.unPaidOwnerNum
}
return {
x: item.monthNum + '月',
y: num
}
})
this.repairData = [
{ item: '未缴总金额', count: result.unPaidTotal || 0 },
{ item: '已缴总金额', count: result.paidTotal || 0 },
]
this.complaintsData = [
{ item: '未缴纳业主', count: result.unPaidOwnerNum || 0 },
{ item: '已缴纳业主', count: result.paidOwnerNum || 0 },
]
this.loading = !this.loading
},
handleSizeChange(e) {
let that = this
this.typeCode = e.target.value
that.onDetail(this.typeCode)
},
},
}
</script>
<style lang="less" scoped>
.hone-content-box {
padding: 10px;
.statistics {
// flex: none;
background: #fff;
width: 100%;
height: 90px;
box-sizing: border-box;
border: 1px solid #e0dfdf;
display: flex;
align-items: center;
padding-left: 20px;
.icon {
width: 50px;
height: 50px;
border-radius: 50px;
margin-right: 12px;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
.anticon {
font-size: 26px;
color: #ffffff;
}
}
}
.pay-box {
display: flex;
.left-box {
flex: none;
width: 50%;
}
}
}
.t-box {
background: #fff;
padding: 15px;
border: 1px solid #e0dfdf;
}
.box-title {
font-weight: bold;
margin-bottom: 15px;
display: inline-block;
padding-left: 10px;
border-left: 3px solid #1890ff;
height: 20px;
line-height: 20px;
}
.pay-cost {
height: 260px;
padding: 30px 0;
}
.salesCard {
height: 380px;
padding-top: 50px;
}
.extra-type {
text-align: center;
a {
margin-right: 20px;
}
}
.number {
width: 80%;
margin: 0 10%;
display: flex;
justify-content: space-evenly;
p {
font-size: 14px;
margin: 0;
}
}
</style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论