From 0201c32312f6478b2bde706607c8c6338e9e1d06 Mon Sep 17 00:00:00 2001
From: doum <doum>
Date: 星期三, 27 五月 2026 17:05:29 +0800
Subject: [PATCH] 新增智能电表、空调管理
---
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerGsConfigDTO.java | 24
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalChargeCloudController.java | 11
server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/ConditionerUtil.java | 80 +
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeDetailVO.java | 19
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerGsMapper.java | 7
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerElectricalMapper.java | 7
server/db/business.yw_electrical.menu.sql | 1
server/db/business.yw_electrical_charge.permissions.sql | 1
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalBalanceItem.java | 13
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwCustomerRechargeCloudController.java | 212 +++++
server/db/business.yw_customer_recharge.admin_role_grant.sql | 34
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerConditionerMapper.java | 7
server/visits/dmvisit_service/src/main/java/com/doumee/core/device/ElectronicToolUtil.java | 69 +
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalActionsService.java | 3
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordVO.java | 61 +
admin/src/views/business/ywelectricalcharge.vue | 14
server/db/business.yw_customer_gs.stop_money.sql | 12
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeQueryDTO.java | 14
server/system_timer/src/main/java/com/doumee/jobs/fegin/VisitServiceFegin.java | 4
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeElectricalDTO.java | 16
server/db/business.yw_customer_recharge.menu.sql | 34
server/db/business.yw_electrical_actions.menu.sql | 2
server/visits/admin_timer/src/main/java/com/doumee/api/YwTimerController.java | 7
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerElectrical.java | 32
server/db/business.yw_electrical_actions.permissions.sql | 1
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeMerchantVO.java | 48 +
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwElectricalCharge.java | 8
admin/src/views/business/ywelectricalactions.vue | 24
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalActionsCloudController.java | 9
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwCustomerRechargeBizService.java | 56 +
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeConditionerDTO.java | 13
server/db/business.yw_electrical_actions.queryResult.grant.sql | 14
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalActionsServiceImpl.java | 26
server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/ConditionerConstant.java | 3
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalSaveDTO.java | 12
server/db/business.yw_customer_recharge.permissions.sql | 33
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerConditioner.java | 35
server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/ConditionerSessionRequest.java | 3
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java | 943 ++++++++++++++++++++++
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwElectricalOperateDTO.java | 2
server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/CompanyGsManageRequest.java | 3
admin/src/api/business/ywelectricalcharge.js | 4
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalBizService.java | 9
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalServiceImpl.java | 16
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordQueryDTO.java | 21
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerGs.java | 51 +
server/db/quartz_job.yw_timer.sql | 6
admin/src/api/business/ywelectricalactions.js | 4
server/db/ELECTRICAL_INTEGRATION.md | 1
server/db/business.yw_customer_recharge.sql | 76 +
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwConditioner.java | 4
server/visits/dmvisit_service/src/main/java/com/doumee/core/device/model/request/RequestStatusRequest.java | 19
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalBizServiceImpl.java | 373 ++++++++
53 files changed, 2,468 insertions(+), 33 deletions(-)
diff --git a/admin/src/api/business/ywelectricalactions.js b/admin/src/api/business/ywelectricalactions.js
index b1c430c..5d925e6 100644
--- a/admin/src/api/business/ywelectricalactions.js
+++ b/admin/src/api/business/ywelectricalactions.js
@@ -5,3 +5,7 @@
export function fetchList (data) {
return request.post(base + '/page', data, { trim: true })
}
+
+export function queryResult (id) {
+ return request.get(base + '/queryResult/' + id)
+}
diff --git a/admin/src/api/business/ywelectricalcharge.js b/admin/src/api/business/ywelectricalcharge.js
index 04229fa..199d1fc 100644
--- a/admin/src/api/business/ywelectricalcharge.js
+++ b/admin/src/api/business/ywelectricalcharge.js
@@ -9,3 +9,7 @@
export function exportExcel (data) {
return request.post(base + '/exportExcel', data, { trim: true, download: true })
}
+
+export function syncStatus (id) {
+ return request.get(base + '/syncStatus/' + id)
+}
diff --git a/admin/src/views/business/ywelectricalactions.vue b/admin/src/views/business/ywelectricalactions.vue
index d1ec309..82bae2c 100644
--- a/admin/src/views/business/ywelectricalactions.vue
+++ b/admin/src/views/business/ywelectricalactions.vue
@@ -59,6 +59,17 @@
<el-button type="text" :disabled="!row.responseBody" @click="openJson('鍝嶅簲鎶ユ枃', row.responseBody)">鏌ョ湅</el-button>
</template>
</el-table-column>
+ <el-table-column label="鎿嶄綔" min-width="120" align="center" fixed="right">
+ <template slot-scope="{ row }">
+ <el-button
+ v-if="row.status === 0 && row.oprId"
+ type="text"
+ :loading="queryLoadingId === row.id"
+ v-permissions="['business:ywelectricalactions:queryResult']"
+ @click="handleQueryResult(row)"
+ >鎵嬪姩鏌ヨ缁撴灉</el-button>
+ </template>
+ </el-table-column>
</el-table>
<pagination
@size-change="handleSizeChange"
@@ -101,7 +112,8 @@
actionTypeOptions: Object.keys(ACTION_TYPE_MAP).map(key => ({
value: Number(key),
label: ACTION_TYPE_MAP[key]
- }))
+ })),
+ queryLoadingId: null
}
},
created () {
@@ -164,6 +176,16 @@
openJson (title, content) {
if (!content) return
this.$refs.jsonWindow.open(title, { content })
+ },
+ handleQueryResult (row) {
+ this.queryLoadingId = row.id
+ actionsApi.queryResult(row.id)
+ .then(msg => {
+ this.$tip.success(msg || '鏌ヨ瀹屾垚')
+ this.handlePageChange(this.tableData.pagination.pageIndex)
+ })
+ .catch(e => this.$tip.apiFailed(e))
+ .finally(() => { this.queryLoadingId = null })
}
}
}
diff --git a/admin/src/views/business/ywelectricalcharge.vue b/admin/src/views/business/ywelectricalcharge.vue
index 7eac02a..17f3039 100644
--- a/admin/src/views/business/ywelectricalcharge.vue
+++ b/admin/src/views/business/ywelectricalcharge.vue
@@ -31,6 +31,7 @@
<el-table-column prop="roomNames" label="缁戝畾鎴块棿" min-width="150" align="center" show-overflow-tooltip/>
<el-table-column prop="money" label="鍏呭�奸噾棰�(鍏�)" min-width="110" align="center"/>
<el-table-column prop="banlance" label="鍏呭�煎墠浣欓" min-width="110" align="center"/>
+ <el-table-column prop="balanceAfter" label="鍏呭�煎悗浣欓" min-width="110" align="center"/>
<el-table-column label="鐘舵��" min-width="100" align="center">
<template slot-scope="{ row }">
<span v-if="row.status === 0">鍏呭�间腑</span>
@@ -44,6 +45,11 @@
<el-table-column prop="statusInfo" label="鐘舵�佽鏄�" min-width="140" align="center" show-overflow-tooltip/>
<el-table-column prop="createDate" label="鎻愪氦鏃堕棿" min-width="160" align="center"/>
<el-table-column prop="statusTime" label="鐘舵�佹洿鏂版椂闂�" min-width="160" align="center"/>
+ <el-table-column label="鎿嶄綔" min-width="100" align="center" fixed="right">
+ <template slot-scope="{ row }">
+ <el-button v-if="row.status === 0" type="text" v-permissions="['business:ywelectricalcharge:syncStatus']" @click="handleSync(row)">鎵嬪姩鍚屾</el-button>
+ </template>
+ </el-table-column>
</el-table>
<pagination @size-change="handleSizeChange" @current-change="handlePageChange" :pagination="tableData.pagination"/>
</template>
@@ -103,6 +109,14 @@
reset () {
this.searchForm = { meterKeyword: '', status: '', oprId: '' }
this.search()
+ },
+ handleSync (row) {
+ chargeApi.syncStatus(row.id)
+ .then(msg => {
+ this.$tip.success(msg || '鍚屾瀹屾垚')
+ this.handlePageChange(this.tableData.pagination.pageIndex)
+ })
+ .catch(e => this.$tip.apiFailed(e))
}
}
}
diff --git a/server/db/ELECTRICAL_INTEGRATION.md b/server/db/ELECTRICAL_INTEGRATION.md
index 7c85612..a0aee48 100644
--- a/server/db/ELECTRICAL_INTEGRATION.md
+++ b/server/db/ELECTRICAL_INTEGRATION.md
@@ -174,5 +174,6 @@
| 閲囬泦鍣ㄧ姸鎬� | `0 */5 * * * ?` | `getElectricalStatus` | GET `/timer/yw/getElectricalStatus` |
| 鎵归噺鎶勮〃 | `30 0 * * * ?` | `syncElectricalMeterData` | GET `/timer/yw/syncElectricalMeterData` |
| 鏃ュ織娓呯悊 | `0 30 2 * * ?` | `cleanElectricalLog` | GET `/timer/yw/cleanElectricalLog` |
+| 寮傛浠诲姟鐘舵�佽ˉ鍋� | `0 5 * * * ?` | `syncElectricalAsyncStatus` | GET `/timer/yw/syncElectricalAsyncStatus` |
| 绌鸿皟缃戝叧鐘舵�� | `0 */5 * * * ?` | `syncConditionerGatewayStatus` | GET `/timer/yw/syncConditionerGatewayStatus` |
| 绌鸿皟鍐呮満鐘舵�� | `0 */10 * * * ?` | `syncConditionerIndoorUnits` | GET `/timer/yw/syncConditionerIndoorUnits` |
diff --git a/server/db/business.yw_customer_gs.stop_money.sql b/server/db/business.yw_customer_gs.stop_money.sql
new file mode 100644
index 0000000..d334336
--- /dev/null
+++ b/server/db/business.yw_customer_gs.stop_money.sql
@@ -0,0 +1,12 @@
+-- 鍟嗘埛绌鸿皟 GS 閰嶇疆锛氭瑺璐归搴︼紙鍏冿級
+SET @db := DATABASE();
+
+SET @sql := IF(
+ (SELECT COUNT(*) FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'yw_customer_gs' AND COLUMN_NAME = 'stop_money') = 0,
+ 'ALTER TABLE `yw_customer_gs` ADD COLUMN `stop_money` decimal(12,2) DEFAULT 0 COMMENT ''娆犺垂棰濆害锛堝厓锛�'' AFTER `gs_bz`',
+ 'SELECT 1'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/server/db/business.yw_customer_recharge.admin_role_grant.sql b/server/db/business.yw_customer_recharge.admin_role_grant.sql
new file mode 100644
index 0000000..9a65f9b
--- /dev/null
+++ b/server/db/business.yw_customer_recharge.admin_role_grant.sql
@@ -0,0 +1,34 @@
+-- 鍟嗘埛鍏呭�硷細涓鸿秴绾х鐞嗗憳瑙掕壊琛ュ叏鏉冮檺锛堝彲閲嶅鎵ц锛�
+-- 鎵ц鍚庤閲嶆柊鐧诲綍浠ュ埛鏂� Redis 涓殑鏉冮檺缂撳瓨
+
+INSERT INTO `SYSTEM_ROLE_PERMISSION` (`ROLE_ID`, `PERMISSION_ID`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`)
+SELECT r.`ID`, p.`ID`, CURRENT_TIMESTAMP, NULL, 1, NULL, 0
+FROM `SYSTEM_ROLE` r
+INNER JOIN `SYSTEM_PERMISSION` p ON p.`CODE` IN (
+ 'business:ywcustomerrecharge:query',
+ 'business:ywcustomerrecharge:exportExcel',
+ 'business:ywcustomerrecharge:bindDevice',
+ 'business:ywcustomerrecharge:recharge',
+ 'business:ywcustomerrechargerecord:query',
+ 'business:ywcustomerrechargerecord:exportExcel',
+ 'business:ywcustomerrechargerecord:retry',
+ 'business:ywcustomerrechargerecord:syncStatus'
+) AND p.`DELETED` = 0
+WHERE r.`DELETED` = 0 AND (r.`CODE` = 'admin' OR r.`NAME` IN ('瓒呯骇绠$悊鍛�', '绠$悊鍛�'))
+ AND NOT EXISTS (
+ SELECT 1 FROM `SYSTEM_ROLE_PERMISSION` rp
+ WHERE rp.`ROLE_ID` = r.`ID` AND rp.`PERMISSION_ID` = p.`ID` AND rp.`DELETED` = 0
+ );
+
+INSERT INTO `SYSTEM_ROLE_MENU` (`ROLE_ID`, `MENU_ID`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`)
+SELECT r.`ID`, menu.`ID`, CURRENT_TIMESTAMP, NULL, 1, NULL, 0
+FROM `SYSTEM_ROLE` r
+INNER JOIN `SYSTEM_MENU` menu ON menu.`DELETED` = 0 AND (
+ (menu.`NAME` = '鍟嗘埛鍏呭��' AND (menu.`PATH` IS NULL OR menu.`PATH` = ''))
+ OR menu.`PATH` IN ('/business/ywcustomerrecharge', '/business/ywcustomerrechargerecord')
+)
+WHERE r.`DELETED` = 0 AND (r.`CODE` = 'admin' OR r.`NAME` IN ('瓒呯骇绠$悊鍛�', '绠$悊鍛�'))
+ AND NOT EXISTS (
+ SELECT 1 FROM `SYSTEM_ROLE_MENU` rm
+ WHERE rm.`ROLE_ID` = r.`ID` AND rm.`MENU_ID` = menu.`ID` AND rm.`DELETED` = 0
+ );
diff --git a/server/db/business.yw_customer_recharge.menu.sql b/server/db/business.yw_customer_recharge.menu.sql
new file mode 100644
index 0000000..81c598e
--- /dev/null
+++ b/server/db/business.yw_customer_recharge.menu.sql
@@ -0,0 +1,34 @@
+-- 鍟嗘埛鍏呭�硷細涓�绾ц彍鍗� + 2 瀛愯彍鍗� + 瓒呯骇绠$悊鍛樿彍鍗曟巿鏉�
+
+INSERT INTO `SYSTEM_MENU` (`PARENT_ID`, `NAME`, `PATH`, `REMARK`, `ICON`, `DISABLED`, `SORT`, `FIXED`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`, `PARAMS`)
+SELECT 0, '鍟嗘埛鍏呭��', '', '鍟嗘埛鐢佃〃/绌鸿皟鍏呭�肩鐞�', NULL, 0,
+ IFNULL((SELECT MAX(sm.`SORT`) FROM `SYSTEM_MENU` sm WHERE sm.`PARENT_ID` = 0 AND sm.`DELETED` = 0), 0) + 1,
+ 0, CURRENT_TIMESTAMP, NULL, 1, NULL, 0, NULL
+WHERE NOT EXISTS (
+ SELECT 1 FROM `SYSTEM_MENU` x WHERE x.`DELETED` = 0 AND x.`NAME` = '鍟嗘埛鍏呭��' AND (x.`PATH` IS NULL OR x.`PATH` = '')
+);
+
+INSERT INTO `SYSTEM_MENU` (`PARENT_ID`, `NAME`, `PATH`, `REMARK`, `ICON`, `DISABLED`, `SORT`, `FIXED`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`, `PARAMS`)
+SELECT p.`ID`, '鍟嗘埛鍏呭��', '/business/ywcustomerrecharge', '鍟嗘埛鍒楄〃銆佸叧鑱旇澶囥�佸厖鍊�', NULL, 0, 1, 0, CURRENT_TIMESTAMP, NULL, 1, NULL, 0, NULL
+FROM `SYSTEM_MENU` p WHERE p.`DELETED` = 0 AND p.`NAME` = '鍟嗘埛鍏呭��' AND (p.`PATH` IS NULL OR p.`PATH` = '')
+ AND NOT EXISTS (SELECT 1 FROM `SYSTEM_MENU` x WHERE x.`DELETED` = 0 AND x.`PATH` = '/business/ywcustomerrecharge')
+LIMIT 1;
+
+INSERT INTO `SYSTEM_MENU` (`PARENT_ID`, `NAME`, `PATH`, `REMARK`, `ICON`, `DISABLED`, `SORT`, `FIXED`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`, `PARAMS`)
+SELECT p.`ID`, '鍏呭�艰褰�', '/business/ywcustomerrechargerecord', '鐢佃〃/绌鸿皟缁熶竴鍏呭�艰褰�', NULL, 0, 2, 0, CURRENT_TIMESTAMP, NULL, 1, NULL, 0, NULL
+FROM `SYSTEM_MENU` p WHERE p.`DELETED` = 0 AND p.`NAME` = '鍟嗘埛鍏呭��' AND (p.`PATH` IS NULL OR p.`PATH` = '')
+ AND NOT EXISTS (SELECT 1 FROM `SYSTEM_MENU` x WHERE x.`DELETED` = 0 AND x.`PATH` = '/business/ywcustomerrechargerecord')
+LIMIT 1;
+
+INSERT INTO `SYSTEM_ROLE_MENU` (`ROLE_ID`, `MENU_ID`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`)
+SELECT r.`ID`, menu.`ID`, CURRENT_TIMESTAMP, NULL, 1, NULL, 0
+FROM `SYSTEM_ROLE` r
+INNER JOIN `SYSTEM_MENU` menu ON menu.`DELETED` = 0 AND (
+ (menu.`NAME` = '鍟嗘埛鍏呭��' AND (menu.`PATH` IS NULL OR menu.`PATH` = ''))
+ OR menu.`PATH` IN ('/business/ywcustomerrecharge', '/business/ywcustomerrechargerecord')
+)
+WHERE r.`DELETED` = 0 AND (r.`CODE` = 'admin' OR r.`NAME` IN ('瓒呯骇绠$悊鍛�', '绠$悊鍛�'))
+ AND NOT EXISTS (
+ SELECT 1 FROM `SYSTEM_ROLE_MENU` rm
+ WHERE rm.`ROLE_ID` = r.`ID` AND rm.`MENU_ID` = menu.`ID` AND rm.`DELETED` = 0
+ );
diff --git a/server/db/business.yw_customer_recharge.permissions.sql b/server/db/business.yw_customer_recharge.permissions.sql
new file mode 100644
index 0000000..ddb4a4f
--- /dev/null
+++ b/server/db/business.yw_customer_recharge.permissions.sql
@@ -0,0 +1,33 @@
+-- 鍟嗘埛鍏呭�兼ā鍧楁潈闄愶紙闃查噸澶� INSERT锛�
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrecharge:query', '鏌ヨ鍟嗘埛鍏呭��', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrecharge:query' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrecharge:exportExcel', '瀵煎嚭鍟嗘埛鍏呭��', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrecharge:exportExcel' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrecharge:bindDevice', '鍏宠仈璁惧', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrecharge:bindDevice' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrecharge:recharge', '鍟嗘埛鍏呭��/娓呴浂', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrecharge:recharge' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrechargerecord:query', '鏌ヨ鍏呭�艰褰�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrechargerecord:query' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrechargerecord:exportExcel', '瀵煎嚭鍏呭�艰褰�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrechargerecord:exportExcel' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrechargerecord:retry', '鍐嶆鎻愪氦鍏呭��', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrechargerecord:retry' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywcustomerrechargerecord:syncStatus', '鎵嬪姩鍚屾鍏呭�肩姸鎬�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywcustomerrechargerecord:syncStatus' AND `DELETED` = 0);
diff --git a/server/db/business.yw_customer_recharge.sql b/server/db/business.yw_customer_recharge.sql
new file mode 100644
index 0000000..a85a497
--- /dev/null
+++ b/server/db/business.yw_customer_recharge.sql
@@ -0,0 +1,76 @@
+-- 鍟嗘埛鍏呭�兼ā鍧楋細瀹㈡埛 GS 閰嶇疆銆佺數琛�/绌鸿皟鍏宠仈銆佸厖鍊艰褰曟墿灞�
+
+CREATE TABLE IF NOT EXISTS `yw_customer_gs` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `creator` int DEFAULT NULL,
+ `create_date` datetime DEFAULT NULL,
+ `editor` int DEFAULT NULL,
+ `edit_date` datetime DEFAULT NULL,
+ `isdeleted` int DEFAULT 0,
+ `remark` varchar(500) DEFAULT NULL,
+ `customer_id` int NOT NULL COMMENT '鍏宠仈 yw_customer.id',
+ `platform_gs_id` int DEFAULT NULL COMMENT '鏅虹簿鐏� addGs 杩斿洖鐨勫叕鍙� ID',
+ `is_pwr` tinyint DEFAULT 1 COMMENT '璁¤垂寮�鍏� 0鍏� 1寮�',
+ `is_rest_stop` tinyint DEFAULT 0 COMMENT '18:00-09:00 涓嶅仠鏈� 0鍚� 1鏄�',
+ `gs_bz` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+ `stop_money` decimal(12,2) DEFAULT 0 COMMENT '娆犺垂棰濆害锛堝厓锛�',
+ `left_money` decimal(12,4) DEFAULT NULL COMMENT '鍓╀綑閲戦锛屽悓姝ヨ嚜 getGs',
+ `sync_date` datetime DEFAULT NULL COMMENT '浣欓鍚屾鏃堕棿',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_customer_id` (`customer_id`),
+ KEY `idx_platform_gs_id` (`platform_gs_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鍟嗘埛绌鸿皟 GS 閰嶇疆';
+
+CREATE TABLE IF NOT EXISTS `yw_customer_electrical` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `creator` int DEFAULT NULL,
+ `create_date` datetime DEFAULT NULL,
+ `editor` int DEFAULT NULL,
+ `edit_date` datetime DEFAULT NULL,
+ `isdeleted` int DEFAULT 0,
+ `remark` varchar(500) DEFAULT NULL,
+ `customer_id` int NOT NULL COMMENT '鍏宠仈 yw_customer.id',
+ `electrical_id` int NOT NULL COMMENT '鍏宠仈 yw_electrical.id',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_customer_electrical` (`customer_id`, `electrical_id`),
+ KEY `idx_electrical_id` (`electrical_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鍟嗘埛鍏宠仈鐢佃〃';
+
+CREATE TABLE IF NOT EXISTS `yw_customer_conditioner` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `creator` int DEFAULT NULL,
+ `create_date` datetime DEFAULT NULL,
+ `editor` int DEFAULT NULL,
+ `edit_date` datetime DEFAULT NULL,
+ `isdeleted` int DEFAULT 0,
+ `remark` varchar(500) DEFAULT NULL,
+ `customer_id` int NOT NULL COMMENT '鍏宠仈 yw_customer.id',
+ `conditioner_id` int NOT NULL COMMENT '鍏宠仈 yw_conditioner.id',
+ `dev_ratio` int DEFAULT 100 COMMENT '鐢佃垂鍗犳瘮%',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_customer_conditioner` (`customer_id`, `conditioner_id`),
+ KEY `idx_conditioner_id` (`conditioner_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鍟嗘埛鍏宠仈绌鸿皟鍐呮満';
+
+-- yw_electrical_charge 鎵╁睍鍒楋紙鑻ュ凡瀛樺湪鍒欒烦杩囷級
+SET @db := DATABASE();
+
+SET @sql := IF(
+ (SELECT COUNT(*) FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'yw_electrical_charge' AND COLUMN_NAME = 'balance_after') = 0,
+ 'ALTER TABLE `yw_electrical_charge` ADD COLUMN `balance_after` decimal(12,4) DEFAULT NULL COMMENT ''鍏呭�煎悗浣欓锛堝厓锛�'' AFTER `banlance`',
+ 'SELECT 1'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @sql := IF(
+ (SELECT COUNT(*) FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'yw_electrical_charge' AND COLUMN_NAME = 'device_info') = 0,
+ 'ALTER TABLE `yw_electrical_charge` ADD COLUMN `device_info` varchar(500) DEFAULT NULL COMMENT ''璁惧灞曠ず淇℃伅'' AFTER `balance_after`',
+ 'SELECT 1'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/server/db/business.yw_electrical.menu.sql b/server/db/business.yw_electrical.menu.sql
index a02e5d6..cb8431c 100644
--- a/server/db/business.yw_electrical.menu.sql
+++ b/server/db/business.yw_electrical.menu.sql
@@ -63,6 +63,7 @@
'business:ywelectrical:exportExcel',
'business:ywelectricalcharge:query',
'business:ywelectricalcharge:exportExcel',
+ 'business:ywelectricalcharge:syncStatus',
'business:ywelectricalparam:query',
'business:ywelectricalparam:create',
'business:ywelectricalparam:update',
diff --git a/server/db/business.yw_electrical_actions.menu.sql b/server/db/business.yw_electrical_actions.menu.sql
index 58793c5..4746ff0 100644
--- a/server/db/business.yw_electrical_actions.menu.sql
+++ b/server/db/business.yw_electrical_actions.menu.sql
@@ -22,7 +22,7 @@
INSERT INTO `SYSTEM_ROLE_PERMISSION` (`ROLE_ID`, `PERMISSION_ID`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`)
SELECT r.`ID`, p.`ID`, CURRENT_TIMESTAMP, NULL, 1, NULL, 0
FROM `SYSTEM_ROLE` r
-INNER JOIN `SYSTEM_PERMISSION` p ON p.`CODE` = 'business:ywelectricalactions:query' AND p.`DELETED` = 0
+INNER JOIN `SYSTEM_PERMISSION` p ON p.`CODE` IN ('business:ywelectricalactions:query', 'business:ywelectricalactions:queryResult') AND p.`DELETED` = 0
WHERE r.`DELETED` = 0 AND (r.`CODE` = 'admin' OR r.`NAME` = '绠$悊鍛�')
AND NOT EXISTS (
SELECT 1 FROM `SYSTEM_ROLE_PERMISSION` rp
diff --git a/server/db/business.yw_electrical_actions.permissions.sql b/server/db/business.yw_electrical_actions.permissions.sql
index 0c1995c..cbbcd8c 100644
--- a/server/db/business.yw_electrical_actions.permissions.sql
+++ b/server/db/business.yw_electrical_actions.permissions.sql
@@ -1 +1,2 @@
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:ywelectricalactions:query', '鏌ヨ鐢佃〃杩滅▼鎿嶄綔璁板綍', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:ywelectricalactions:queryResult', '鎵嬪姩鏌ヨ寮傛鎿嶄綔缁撴灉', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
diff --git a/server/db/business.yw_electrical_actions.queryResult.grant.sql b/server/db/business.yw_electrical_actions.queryResult.grant.sql
new file mode 100644
index 0000000..edb6d8d
--- /dev/null
+++ b/server/db/business.yw_electrical_actions.queryResult.grant.sql
@@ -0,0 +1,14 @@
+-- 鎿嶄綔璁板綍銆屾墜鍔ㄦ煡璇㈢粨鏋溿�嶆潈闄愶紙宸查儴缃茬幆澧冭ˉ鎵ц锛�
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`)
+SELECT 'business:ywelectricalactions:queryResult', '鎵嬪姩鏌ヨ寮傛鎿嶄綔缁撴灉', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0
+WHERE NOT EXISTS (SELECT 1 FROM `SYSTEM_PERMISSION` WHERE `CODE` = 'business:ywelectricalactions:queryResult' AND `DELETED` = 0);
+
+INSERT INTO `SYSTEM_ROLE_PERMISSION` (`ROLE_ID`, `PERMISSION_ID`, `CREATE_TIME`, `UPDATE_TIME`, `CREATE_USER`, `UPDATE_USER`, `DELETED`)
+SELECT r.`ID`, p.`ID`, CURRENT_TIMESTAMP, NULL, 1, NULL, 0
+FROM `SYSTEM_ROLE` r
+INNER JOIN `SYSTEM_PERMISSION` p ON p.`CODE` = 'business:ywelectricalactions:queryResult' AND p.`DELETED` = 0
+WHERE r.`DELETED` = 0 AND (r.`CODE` = 'admin' OR r.`NAME` = '绠$悊鍛�')
+ AND NOT EXISTS (
+ SELECT 1 FROM `SYSTEM_ROLE_PERMISSION` rp
+ WHERE rp.`ROLE_ID` = r.`ID` AND rp.`PERMISSION_ID` = p.`ID` AND rp.`DELETED` = 0
+ );
diff --git a/server/db/business.yw_electrical_charge.permissions.sql b/server/db/business.yw_electrical_charge.permissions.sql
index 2c01ffa..a2fa22b 100644
--- a/server/db/business.yw_electrical_charge.permissions.sql
+++ b/server/db/business.yw_electrical_charge.permissions.sql
@@ -1,2 +1,3 @@
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:ywelectricalcharge:query', '鏌ヨ鐢佃〃鍏呭�艰褰�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:ywelectricalcharge:exportExcel', '瀵煎嚭鐢佃〃鍏呭�艰褰�(Excel)', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:ywelectricalcharge:syncStatus', '鎵嬪姩鍚屾鐢佃〃鍏呭�肩姸鎬�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
diff --git a/server/db/quartz_job.yw_timer.sql b/server/db/quartz_job.yw_timer.sql
index 449636b..5f38d66 100644
--- a/server/db/quartz_job.yw_timer.sql
+++ b/server/db/quartz_job.yw_timer.sql
@@ -22,6 +22,12 @@
);
INSERT INTO `quartz_job` (`bean_name`, `params`, `module`, `cron_expres`, `state`, `remark`, `create_time`)
+SELECT 'visitServiceJob', '', 'syncElectricalAsyncStatus', '0 5 * * * ?', 1, '鏅鸿兘鐢佃〃-寮傛浠诲姟鐘舵�佽ˉ鍋挎煡璇�', CURRENT_TIMESTAMP
+WHERE NOT EXISTS (
+ SELECT 1 FROM `quartz_job` WHERE `module` = 'syncElectricalAsyncStatus' AND `bean_name` = 'visitServiceJob'
+);
+
+INSERT INTO `quartz_job` (`bean_name`, `params`, `module`, `cron_expres`, `state`, `remark`, `create_time`)
SELECT 'visitServiceJob', '', 'syncConditionerGatewayStatus', '0 */5 * * * ?', 1, '绌鸿皟澶氳仈鏈�-缃戝叧鍦ㄧ嚎鐘舵�佸悓姝�', CURRENT_TIMESTAMP
WHERE NOT EXISTS (
SELECT 1 FROM `quartz_job` WHERE `module` = 'syncConditionerGatewayStatus' AND `bean_name` = 'visitServiceJob'
diff --git a/server/system_timer/src/main/java/com/doumee/jobs/fegin/VisitServiceFegin.java b/server/system_timer/src/main/java/com/doumee/jobs/fegin/VisitServiceFegin.java
index 15fa368..36e72a6 100644
--- a/server/system_timer/src/main/java/com/doumee/jobs/fegin/VisitServiceFegin.java
+++ b/server/system_timer/src/main/java/com/doumee/jobs/fegin/VisitServiceFegin.java
@@ -100,6 +100,10 @@
@GetMapping("/timer/yw/cleanElectricalLog")
ApiResponse cleanElectricalLog();
+ @ApiOperation("銆愰槣瀹佽繍缁淬�戝畾鏃舵煡璇㈠鐞嗕腑鐨勭數琛ㄥ紓姝ヤ换鍔$姸鎬�")
+ @GetMapping("/timer/yw/syncElectricalAsyncStatus")
+ ApiResponse syncElectricalAsyncStatus();
+
@ApiOperation("銆愰槣瀹佽繍缁淬�戝畾鏃跺悓姝ユ櫤绮剧伒缃戝叧鍦ㄧ嚎鐘舵��")
@GetMapping("/timer/yw/syncConditionerGatewayStatus")
ApiResponse syncConditionerGatewayStatus();
diff --git a/server/visits/admin_timer/src/main/java/com/doumee/api/YwTimerController.java b/server/visits/admin_timer/src/main/java/com/doumee/api/YwTimerController.java
index ca761db..739ac07 100644
--- a/server/visits/admin_timer/src/main/java/com/doumee/api/YwTimerController.java
+++ b/server/visits/admin_timer/src/main/java/com/doumee/api/YwTimerController.java
@@ -109,6 +109,13 @@
return ApiResponse.success("鐢佃〃鎺ュ彛鏃ュ織娓呯悊鎴愬姛");
}
+ @ApiOperation("瀹氭椂鏌ヨ澶勭悊涓殑鐢佃〃寮傛浠诲姟鐘舵��")
+ @GetMapping("/syncElectricalAsyncStatus")
+ public ApiResponse syncElectricalAsyncStatus() {
+ ywElectricalBizService.syncPendingAsyncActionsScheduled();
+ return ApiResponse.success("鐢佃〃寮傛浠诲姟鐘舵�佸悓姝ユ垚鍔�");
+ }
+
@Autowired
private com.doumee.service.business.ConditionerBizService conditionerBizService;
diff --git a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwCustomerRechargeCloudController.java b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwCustomerRechargeCloudController.java
new file mode 100644
index 0000000..da8fe3d
--- /dev/null
+++ b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwCustomerRechargeCloudController.java
@@ -0,0 +1,212 @@
+package com.doumee.cloud.admin;
+
+import com.doumee.api.BaseController;
+import com.doumee.core.annotation.pr.PreventRepeat;
+import com.doumee.core.model.ApiResponse;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.core.utils.Constants;
+import com.doumee.config.annotation.CloudRequiredPermission;
+import com.doumee.dao.business.dto.*;
+import com.doumee.dao.business.model.YwConditioner;
+import com.doumee.dao.business.model.YwCustomerGs;
+import com.doumee.dao.business.model.YwElectrical;
+import com.doumee.service.business.YwCustomerRechargeBizService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+@Api(tags = "鍟嗘埛鍏呭��")
+@RestController
+@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX + "/business/ywCustomerRecharge")
+public class YwCustomerRechargeCloudController extends BaseController {
+
+ @Autowired
+ private YwCustomerRechargeBizService ywCustomerRechargeBizService;
+
+ @ApiOperation("鍟嗘埛鍒嗛〉鍒楄〃")
+ @PostMapping("/merchantPage")
+ @CloudRequiredPermission("business:ywcustomerrecharge:query")
+ public ApiResponse<PageData<YwCustomerRechargeMerchantVO>> merchantPage(
+ @RequestBody PageWrap<YwCustomerRechargeQueryDTO> pageWrap,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.findMerchantPage(pageWrap));
+ }
+
+ @ApiOperation("鍟嗘埛璇︽儏")
+ @GetMapping("/{customerId}/detail")
+ @CloudRequiredPermission("business:ywcustomerrecharge:query")
+ public ApiResponse<YwCustomerRechargeDetailVO> detail(@PathVariable Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.getDetail(customerId));
+ }
+
+ @ApiOperation("鍏宠仈鐢佃〃鍒楄〃")
+ @PostMapping("/electrical/page")
+ @CloudRequiredPermission("business:ywcustomerrecharge:query")
+ public ApiResponse<PageData<YwElectrical>> electricalPage(
+ @RequestBody PageWrap<YwElectrical> pageWrap,
+ @RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.listCustomerElectrical(pageWrap, customerId));
+ }
+
+ @ApiOperation("鍙�夌數琛ㄥ垪琛�")
+ @PostMapping("/electrical/selectablePage")
+ @CloudRequiredPermission("business:ywcustomerrecharge:bindDevice")
+ public ApiResponse<PageData<YwElectrical>> selectableElectricalPage(
+ @RequestBody PageWrap<YwElectrical> pageWrap,
+ @RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.pageSelectableElectrical(pageWrap, customerId));
+ }
+
+ @PreventRepeat
+ @ApiOperation("淇濆瓨鍏宠仈鐢佃〃")
+ @PostMapping("/electrical/save")
+ @CloudRequiredPermission("business:ywcustomerrecharge:bindDevice")
+ public ApiResponse saveElectrical(@RequestBody YwCustomerElectricalSaveDTO dto,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ ywCustomerRechargeBizService.saveCustomerElectrical(dto, getLoginUser(token));
+ return ApiResponse.success(null);
+ }
+
+ @ApiOperation("鍒犻櫎鍏宠仈鐢佃〃")
+ @GetMapping("/electrical/delete")
+ @CloudRequiredPermission("business:ywcustomerrecharge:bindDevice")
+ public ApiResponse deleteElectrical(@RequestParam Integer customerId,
+ @RequestParam Integer electricalId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ ywCustomerRechargeBizService.removeCustomerElectrical(customerId, electricalId, getLoginUser(token));
+ return ApiResponse.success(null);
+ }
+
+ @ApiOperation("鍏宠仈绌鸿皟鍒楄〃")
+ @PostMapping("/conditioner/page")
+ @CloudRequiredPermission("business:ywcustomerrecharge:query")
+ public ApiResponse<PageData<YwConditioner>> conditionerPage(
+ @RequestBody PageWrap<YwConditioner> pageWrap,
+ @RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.listCustomerConditioner(pageWrap, customerId));
+ }
+
+ @ApiOperation("绌鸿皟 GS 閰嶇疆")
+ @GetMapping("/conditioner/gsConfig")
+ @CloudRequiredPermission("business:ywcustomerrecharge:query")
+ public ApiResponse<YwCustomerGs> gsConfig(@RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.getCustomerGsConfig(customerId));
+ }
+
+ @PreventRepeat
+ @ApiOperation("淇濆瓨绌鸿皟 GS 閰嶇疆")
+ @PostMapping("/conditioner/saveGsConfig")
+ @CloudRequiredPermission("business:ywcustomerrecharge:bindDevice")
+ public ApiResponse saveGsConfig(@RequestBody YwCustomerGsConfigDTO dto,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ ywCustomerRechargeBizService.saveCustomerGsConfig(dto, getLoginUser(token));
+ return ApiResponse.success(null);
+ }
+
+ @PreventRepeat
+ @ApiOperation("鐢佃〃鍏呭��")
+ @PostMapping("/recharge/electrical")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<String> rechargeElectrical(@RequestBody YwCustomerRechargeElectricalDTO dto,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.rechargeElectrical(dto, getLoginUser(token)));
+ }
+
+ @PreventRepeat
+ @ApiOperation("鐢佃〃娓呴浂")
+ @PostMapping("/reset/electrical")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<String> resetElectrical(@RequestBody YwCustomerRechargeElectricalDTO dto,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.resetElectricalAccount(dto, getLoginUser(token)));
+ }
+
+ @ApiOperation("鐢佃〃鎶勮〃鍒锋柊")
+ @GetMapping("/readMeter")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<Map<String, Object>> readMeter(@RequestParam Integer customerId,
+ @RequestParam Integer electricalId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.readMeterAndRefresh(customerId, electricalId, getLoginUser(token)));
+ }
+
+ @ApiOperation("鐢佃〃杩滅▼淇℃伅")
+ @GetMapping("/electrical/remoteInfo")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<Map<String, Object>> electricalRemoteInfo(@RequestParam Integer electricalId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.getElectricalRemoteInfo(electricalId));
+ }
+
+ @ApiOperation("绌鸿皟鍏呭�煎墠淇℃伅")
+ @GetMapping("/recharge/conditioner/info")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<Map<String, Object>> conditionerRechargeInfo(@RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.getConditionerRechargeInfo(customerId));
+ }
+
+ @PreventRepeat
+ @ApiOperation("绌鸿皟鍏呭��")
+ @PostMapping("/recharge/conditioner")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<String> rechargeConditioner(@RequestBody YwCustomerRechargeConditionerDTO dto,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.rechargeConditioner(dto, getLoginUser(token)));
+ }
+
+ @PreventRepeat
+ @ApiOperation("绌鸿皟娓呴浂")
+ @PostMapping("/clean/conditioner")
+ @CloudRequiredPermission("business:ywcustomerrecharge:recharge")
+ public ApiResponse<String> cleanConditioner(@RequestParam Integer customerId,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.cleanConditionerAccount(customerId, getLoginUser(token)));
+ }
+
+ @ApiOperation("鍏呭�艰褰曞垎椤�")
+ @PostMapping("/rechargeRecord/page")
+ @CloudRequiredPermission("business:ywcustomerrechargerecord:query")
+ public ApiResponse<PageData<YwCustomerRechargeRecordVO>> rechargeRecordPage(
+ @RequestBody PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.findRechargeRecordPage(pageWrap));
+ }
+
+ @PreventRepeat
+ @ApiOperation("鍐嶆鎻愪氦鍏呭��")
+ @PostMapping("/rechargeRecord/retry/{id}")
+ @CloudRequiredPermission("business:ywcustomerrechargerecord:retry")
+ public ApiResponse<String> retryRecharge(@PathVariable Integer id,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.retryRecharge(id, getLoginUser(token)));
+ }
+
+ @PreventRepeat
+ @ApiOperation("鎵嬪姩鍚屾鍏呭�肩姸鎬�")
+ @PostMapping("/rechargeRecord/sync/{id}")
+ @CloudRequiredPermission("business:ywcustomerrechargerecord:syncStatus")
+ public ApiResponse<String> syncRechargeStatus(@PathVariable Integer id,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywCustomerRechargeBizService.syncRechargeStatus(id, getLoginUser(token)));
+ }
+
+ @ApiOperation("瀵煎嚭鍏呭�艰褰�")
+ @PostMapping("/rechargeRecord/exportExcel")
+ @CloudRequiredPermission("business:ywcustomerrechargerecord:exportExcel")
+ public void exportRechargeRecord(@RequestBody PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap,
+ HttpServletResponse response,
+ @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ ywCustomerRechargeBizService.exportRechargeRecord(pageWrap, response);
+ }
+}
diff --git a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalActionsCloudController.java b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalActionsCloudController.java
index d2b16b8..2befc44 100644
--- a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalActionsCloudController.java
+++ b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalActionsCloudController.java
@@ -1,5 +1,6 @@
package com.doumee.cloud.admin;
+import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.api.BaseController;
import com.doumee.config.annotation.CloudRequiredPermission;
import com.doumee.core.model.ApiResponse;
@@ -34,4 +35,12 @@
}
return ApiResponse.success(ywElectricalActionsService.findPage(pageWrap));
}
+
+ @PreventRepeat
+ @ApiOperation("鎵嬪姩鏌ヨ寮傛鎿嶄綔缁撴灉")
+ @GetMapping("/queryResult/{id}")
+ @CloudRequiredPermission("business:ywelectricalactions:queryResult")
+ public ApiResponse<String> queryResult(@PathVariable Integer id) {
+ return ApiResponse.success(ywElectricalActionsService.queryAsyncResult(id));
+ }
}
diff --git a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalChargeCloudController.java b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalChargeCloudController.java
index 0b5143c..22604b2 100644
--- a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalChargeCloudController.java
+++ b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/YwElectricalChargeCloudController.java
@@ -32,6 +32,9 @@
@Autowired
private YwElectricalChargeService ywElectricalChargeService;
+ @Autowired
+ private com.doumee.service.business.YwElectricalBizService ywElectricalBizService;
+
@PreventRepeat
@ApiOperation("鏂板缓")
@PostMapping("/create")
@@ -88,4 +91,12 @@
public ApiResponse findById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
return ApiResponse.success(ywElectricalChargeService.findById(id));
}
+
+ @PreventRepeat
+ @ApiOperation("鎵嬪姩鍚屾鍏呭�肩姸鎬�")
+ @GetMapping("/syncStatus/{id}")
+ @CloudRequiredPermission("business:ywelectricalcharge:syncStatus")
+ public ApiResponse<String> syncStatus(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
+ return ApiResponse.success(ywElectricalBizService.syncChargeStatusById(id));
+ }
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/ConditionerUtil.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/ConditionerUtil.java
index 95dd398..0872b5e 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/ConditionerUtil.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/ConditionerUtil.java
@@ -283,11 +283,51 @@
}
public static ConditionerBaseResponse<Object> addGs(CompanyGsManageRequest req) {
- return postJson("/addGs", req, Object.class);
+ if (req == null) {
+ return null;
+ }
+ req.fillSessionDefaults();
+ JSONObject body = new JSONObject(true);
+ putSessionFields(body, req);
+ body.put("is_pwr", req.getIs_pwr() != null ? req.getIs_pwr() : 1);
+ if (req.getLi_dev() != null && !req.getLi_dev().isEmpty()) {
+ body.put("li_dev", req.getLi_dev());
+ }
+ if (req.getD_dev() != null && !req.getD_dev().isEmpty()) {
+ body.put("d_dev", req.getD_dev());
+ }
+ body.put("gs_name", req.getGs_name());
+ body.put("is_rest_stop", req.getIs_rest_stop() != null ? req.getIs_rest_stop() : 0);
+ body.put("gs_bz", StringUtils.defaultString(req.getGs_bz()));
+ putStopMoney(body, req.getStop_money());
+ return postJsonBody("/addGs", body, Object.class);
}
public static ConditionerBaseResponse<Object> changeGs(CompanyGsManageRequest req) {
- return postJson("/changeGs", req, Object.class);
+ if (req == null || req.getId() == null) {
+ return null;
+ }
+ req.fillSessionDefaults();
+ JSONObject body = new JSONObject(true);
+ body.put("id", req.getId());
+ body.put("is_pwr", req.getIs_pwr() != null ? req.getIs_pwr() : 1);
+ body.put("is_rest_stop", req.getIs_rest_stop() != null ? req.getIs_rest_stop() : 0);
+ body.put("gs_name", req.getGs_name());
+ if (req.getLeft_money() != null) {
+ body.put("left_money", req.getLeft_money());
+ }
+ body.put("is_stop", req.getIs_stop() != null ? req.getIs_stop() : 0);
+ body.put("li_dev", req.getLi_dev());
+ body.put("d_dev", req.getD_dev());
+ body.put("gs_bz", StringUtils.defaultString(req.getGs_bz()));
+ putStopMoney(body, req.getStop_money());
+ return postJsonBody("/changeGs", body, Object.class);
+ }
+
+ private static void putStopMoney(JSONObject body, Object stopMoney) {
+ if (stopMoney != null) {
+ body.put("stop_money", stopMoney);
+ }
}
public static ConditionerBaseResponse<Object> delGs(CompanyGsManageRequest req) {
@@ -299,11 +339,26 @@
}
public static ConditionerBaseResponse<Object> addMoney(AddMoneyRequest req) {
- return postJson("/addMoney", req, Object.class);
+ if (req == null) {
+ return null;
+ }
+ req.fillSessionDefaults();
+ JSONObject body = new JSONObject(true);
+ putSessionFields(body, req);
+ body.put("id", req.getId());
+ body.put("cz_money", req.getCz_money());
+ return postJsonBody("/addMoney", body, Object.class);
}
public static ConditionerBaseResponse<Object> cleanMoney(CompanyGsManageRequest req) {
- return postJson("/cleanMoney", req, Object.class);
+ if (req == null || req.getId() == null) {
+ return null;
+ }
+ req.fillSessionDefaults();
+ JSONObject body = new JSONObject(true);
+ putSessionFields(body, req);
+ body.put("id", req.getId());
+ return postJsonBody("/cleanMoney", body, Object.class);
}
public static ConditionerBaseResponse<List<Object>> getCzLog(LogQueryRequest req) {
@@ -381,6 +436,23 @@
}
}
+ private static <T> ConditionerBaseResponse<T> postJsonBody(String path, JSONObject body, Class<T> dataClass) {
+ try {
+ String raw = doPostRaw(path, body.toJSONString());
+ return parseObjectResponse(raw, dataClass);
+ } catch (Exception e) {
+ log.error("conditioner POST {} failed", path, e);
+ return null;
+ }
+ }
+
+ private static void putSessionFields(JSONObject body, ConditionerSessionRequest req) {
+ body.put("kt_token", req.getKt_token());
+ body.put("kt_dwid", req.getKt_dwid());
+ body.put("kt_unit", StringUtils.defaultIfBlank(req.getKt_unit(), ConditionerConstant.DEFAULT_KT_UNIT));
+ body.put("kt_sonid", req.getKt_sonid());
+ }
+
private static String resolveUrl(String path) {
String base = StringUtils.defaultIfBlank(ConditionerConstant.base_url, ConditionerConstant.DEFAULT_BASE_URL);
if (base.endsWith("/")) {
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/ConditionerConstant.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/ConditionerConstant.java
index c7b6df4..1a2ea80 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/ConditionerConstant.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/ConditionerConstant.java
@@ -11,6 +11,8 @@
public static final String DEFAULT_USERNAME = "admin";
public static final String DEFAULT_PASSWORD = "12345678";
public static final String DEFAULT_KT_SONID = "0";
+ /** 鍗曞厓 ID锛宎ddGs/addMoney 绛� POST 鎺ュ彛鏂囨。绀轰緥鍧囦负 "1" */
+ public static final String DEFAULT_KT_UNIT = "1";
/** API 鏍瑰湴鍧�锛屽 http://119.45.163.5:1125/zjl/API */
public static String base_url = DEFAULT_BASE_URL;
@@ -21,6 +23,7 @@
public static String kt_token;
public static String kt_dwid;
public static String kt_sonid = DEFAULT_KT_SONID;
+ public static String kt_unit = DEFAULT_KT_UNIT;
private ConditionerConstant() {
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/CompanyGsManageRequest.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/CompanyGsManageRequest.java
index a215ed7..78e257e 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/CompanyGsManageRequest.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/CompanyGsManageRequest.java
@@ -37,4 +37,7 @@
@ApiModelProperty("澶囨敞")
private String gs_bz;
+
+ @ApiModelProperty("娆犺垂棰濆害锛堝厓锛�")
+ private Object stop_money;
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/ConditionerSessionRequest.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/ConditionerSessionRequest.java
index 22ddda8..34c8200 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/ConditionerSessionRequest.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/conditoner/model/request/ConditionerSessionRequest.java
@@ -35,5 +35,8 @@
if (StringUtils.isBlank(kt_sonid)) {
kt_sonid = ConditionerConstant.kt_sonid;
}
+ if (StringUtils.isBlank(kt_unit)) {
+ kt_unit = ConditionerConstant.kt_unit;
+ }
}
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/ElectronicToolUtil.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/ElectronicToolUtil.java
index 065155a..4b86b6b 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/ElectronicToolUtil.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/ElectronicToolUtil.java
@@ -203,7 +203,7 @@
return null;
}
/**
- * 鐢佃〃寮�鎴穇鐢佃〃鍏呭��
+ * 鐢佃〃_鐢佃〃鍏呭��
*/
public static ElectronicBaseResponse recharger(List<OpenAccountRequest> param) {
if(param ==null || param.size()==0){
@@ -216,7 +216,7 @@
String r = requestAsync(url, request_content);
return parseAsyncMeterResponse(r);
}catch (Exception e){
- log.error("鐢佃〃==============寮�鎴�",e);
+ log.error("鐢佃〃==============鍏呭��",e);
}
return null;
}
@@ -227,7 +227,7 @@
if(param ==null || param.size()==0){
return null;
}
- String url = ElectronicConstant.api2_url+"/Api_v2/ele_security/ele_control";
+ String url = ElectronicConstant.api2_url+"/Api_v2/ele_control";
try {
String request_content = JSON.toJSONString(param);
@@ -239,6 +239,69 @@
return null;
}
/**
+ * 鏌ヨ寮傛鎿嶄綔浠诲姟鐘舵�侊紙/Api_v2/request/status锛夈��
+ * request_content 涓� JSON 鏁扮粍锛屽彲鍚堝苟浼犲叆澶氫釜 opr_id 涓�娆℃煡璇€��
+ * 璋冪敤鎴愬姛鍚庡缓璁� 30s 棣栨鏌ヨ锛屽悗缁棿闅旈�掑锛�1h銆�2h銆�4h鈥︼級锛岀姝㈤绻佽皟鐢ㄣ��
+ * 鍝嶅簲 SUCCESS銆丗AIL銆乀IMEOUT銆丆ANCELED銆丷ESPONSE_FAIL 鍚庢棤闇�鍐嶆煡璇€��
+ */
+ public static ElectronicBaseResponse requestStatus(List<RequestStatusRequest> param) {
+ if (param == null || param.isEmpty()) {
+ return null;
+ }
+ String url = ElectronicConstant.api2_url + "/Api_v2/request/status";
+ try {
+ String request_content = JSON.toJSONString(param);
+ String r = request(url, request_content);
+ return parseAsyncMeterResponse(r);
+ } catch (Exception e) {
+ log.error("鐢佃〃==============鏌ヨ寮傛浠诲姟鐘舵��", e);
+ }
+ return null;
+ }
+
+ /**
+ * 鎸� opr_id 鍒楄〃鍚堝苟鏌ヨ寮傛浠诲姟鐘舵�併��
+ */
+ public static ElectronicBaseResponse requestStatusByOprIds(List<String> oprIds) {
+ if (oprIds == null || oprIds.isEmpty()) {
+ return null;
+ }
+ List<RequestStatusRequest> param = new ArrayList<>();
+ for (String oprId : oprIds) {
+ if (StringUtils.isNotBlank(oprId)) {
+ RequestStatusRequest req = new RequestStatusRequest();
+ req.setOpr_id(oprId.trim());
+ param.add(req);
+ }
+ }
+ return param.isEmpty() ? null : requestStatus(param);
+ }
+
+ /**
+ * 鏌ヨ鍗曚釜寮傛鎿嶄綔浠诲姟鐘舵�併��
+ */
+ public static ElectronicBaseResponse requestStatus(String oprId) {
+ if (StringUtils.isBlank(oprId)) {
+ return null;
+ }
+ RequestStatusRequest req = new RequestStatusRequest();
+ req.setOpr_id(oprId.trim());
+ return requestStatus(Collections.singletonList(req));
+ }
+
+ /**
+ * 寮傛浠诲姟鏄惁宸插埌杈剧粓鎬侊紝骞冲彴鍚庣画涓嶅啀澶勭悊锛屾棤闇�鍐嶈疆璇€��
+ */
+ public static boolean isAsyncStatusFinal(String status) {
+ if (StringUtils.isBlank(status)) {
+ return false;
+ }
+ String s = status.trim().toUpperCase(Locale.ROOT);
+ return "SUCCESS".equals(s) || "FAIL".equals(s) || "TIMEOUT".equals(s)
+ || "CANCELED".equals(s) || "RESPONSE_FAIL".equals(s);
+ }
+
+ /**
* 鐢佃〃_绔嬪嵆鎶勮〃
*/
public static ElectronicBaseResponse eleRead(List<EleReadRequest> param) {
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/model/request/RequestStatusRequest.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/model/request/RequestStatusRequest.java
new file mode 100644
index 0000000..e79fd10
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/device/model/request/RequestStatusRequest.java
@@ -0,0 +1,19 @@
+package com.doumee.core.device.model.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 寮傛鎿嶄綔浠诲姟鐘舵�佹煡璇㈣姹傞」
+ */
+@ApiModel("寮傛鎿嶄綔浠诲姟鐘舵�佹煡璇�")
+@Data
+public class RequestStatusRequest implements Serializable {
+
+ @ApiModelProperty(value = "鎿嶄綔ID锛岄暱搴�16-32锛屼笌鎻愪氦寮傛浠诲姟鏃朵竴鑷�")
+ private String opr_id;
+
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerConditionerMapper.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerConditionerMapper.java
new file mode 100644
index 0000000..bbc044c
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerConditionerMapper.java
@@ -0,0 +1,7 @@
+package com.doumee.dao.business;
+
+import com.doumee.dao.business.model.YwCustomerConditioner;
+import com.github.yulichang.base.MPJBaseMapper;
+
+public interface YwCustomerConditionerMapper extends MPJBaseMapper<YwCustomerConditioner> {
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerElectricalMapper.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerElectricalMapper.java
new file mode 100644
index 0000000..781c409
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerElectricalMapper.java
@@ -0,0 +1,7 @@
+package com.doumee.dao.business;
+
+import com.doumee.dao.business.model.YwCustomerElectrical;
+import com.github.yulichang.base.MPJBaseMapper;
+
+public interface YwCustomerElectricalMapper extends MPJBaseMapper<YwCustomerElectrical> {
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerGsMapper.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerGsMapper.java
new file mode 100644
index 0000000..2c4e8b2
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/YwCustomerGsMapper.java
@@ -0,0 +1,7 @@
+package com.doumee.dao.business;
+
+import com.doumee.dao.business.model.YwCustomerGs;
+import com.github.yulichang.base.MPJBaseMapper;
+
+public interface YwCustomerGsMapper extends MPJBaseMapper<YwCustomerGs> {
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalBalanceItem.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalBalanceItem.java
new file mode 100644
index 0000000..30e66a2
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalBalanceItem.java
@@ -0,0 +1,13 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class YwCustomerElectricalBalanceItem {
+
+ private String name;
+ private String address;
+ private BigDecimal balance;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalSaveDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalSaveDTO.java
new file mode 100644
index 0000000..f5ac380
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerElectricalSaveDTO.java
@@ -0,0 +1,12 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class YwCustomerElectricalSaveDTO {
+
+ private Integer customerId;
+ private List<Integer> electricalIds;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerGsConfigDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerGsConfigDTO.java
new file mode 100644
index 0000000..93f4661
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerGsConfigDTO.java
@@ -0,0 +1,24 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class YwCustomerGsConfigDTO {
+
+ private Integer customerId;
+ private Integer isPwr;
+ private Integer isRestStop;
+ private String gsBz;
+ /** 娆犺垂棰濆害锛堝厓锛� */
+ private BigDecimal stopMoney;
+ private List<ConditionerItem> conditioners;
+
+ @Data
+ public static class ConditionerItem {
+ private Integer conditionerId;
+ private Integer devRatio;
+ }
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeConditionerDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeConditionerDTO.java
new file mode 100644
index 0000000..be553f4
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeConditionerDTO.java
@@ -0,0 +1,13 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class YwCustomerRechargeConditionerDTO {
+
+ private Integer customerId;
+ private BigDecimal money;
+ private String remark;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeDetailVO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeDetailVO.java
new file mode 100644
index 0000000..96fe49f
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeDetailVO.java
@@ -0,0 +1,19 @@
+package com.doumee.dao.business.dto;
+
+import com.doumee.dao.business.model.YwConditioner;
+import com.doumee.dao.business.model.YwCustomerGs;
+import com.doumee.dao.business.model.YwElectrical;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class YwCustomerRechargeDetailVO {
+
+ private Integer customerId;
+ private String customerName;
+ private String phone;
+ private YwCustomerGs gsConfig;
+ private List<YwElectrical> electricalList;
+ private List<YwConditioner> conditionerList;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeElectricalDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeElectricalDTO.java
new file mode 100644
index 0000000..c3a10b3
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeElectricalDTO.java
@@ -0,0 +1,16 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class YwCustomerRechargeElectricalDTO {
+
+ private Integer customerId;
+ private Integer electricalId;
+ private BigDecimal money;
+ private String remark;
+ /** resetPrepay / resetPostpay */
+ private String resetAction;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeMerchantVO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeMerchantVO.java
new file mode 100644
index 0000000..92007e2
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeMerchantVO.java
@@ -0,0 +1,48 @@
+package com.doumee.dao.business.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class YwCustomerRechargeMerchantVO {
+
+ private Integer id;
+ /** 瀹㈡埛绫诲瀷 0涓汉 1浼佷笟 */
+ private Integer type;
+ private String name;
+ private String phone;
+ /** 榛樿鑱旂郴浜猴紙鍚� clientList锛� */
+ private String memberName;
+ /** 鑱旂郴浜虹數璇濓紙鍚� clientList锛� */
+ private String memberPhone;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createDate;
+
+ private Integer electricalCount;
+ /** 鍏宠仈鐢佃〃浣欓鏄庣粏 */
+ private List<YwCustomerElectricalBalanceItem> electricalBalances;
+ private Integer conditionerCount;
+ private BigDecimal acBalance;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date acBalanceSyncDate;
+
+ /** 绛涢�夎緟鍔╋細鐢佃〃鏄惁鍏ㄥ湪绾� */
+ @JsonIgnore
+ private Boolean electricalOnlineAll;
+ /** 绛涢�夎緟鍔╋細鐢佃〃鏄惁瀛樺湪绂荤嚎 */
+ @JsonIgnore
+ private Boolean electricalHasOffline;
+ /** 绛涢�夎緟鍔╋細绌鸿皟鏄惁鍏ㄥ湪绾� */
+ @JsonIgnore
+ private Boolean conditionerOnlineAll;
+ /** 绛涢�夎緟鍔╋細绌鸿皟鏄惁瀛樺湪绂荤嚎 */
+ @JsonIgnore
+ private Boolean conditionerHasOffline;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeQueryDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeQueryDTO.java
new file mode 100644
index 0000000..9b63ae9
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeQueryDTO.java
@@ -0,0 +1,14 @@
+package com.doumee.dao.business.dto;
+
+import lombok.Data;
+
+@Data
+public class YwCustomerRechargeQueryDTO {
+
+ /** 瀹㈡埛鍚嶇О鍏抽敭瀛� */
+ private String nameKeyword;
+ /** 鐢佃〃鐘舵�佺瓫閫夛細1鍏ㄥ湪绾� 2瀛樺湪绂荤嚎 3鏃犺澶� */
+ private Integer electricalStatusFilter;
+ /** 绌鸿皟鐘舵�佺瓫閫夛細1鍏ㄥ湪绾� 2瀛樺湪绂荤嚎 3鏃犺澶� */
+ private Integer conditionerStatusFilter;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordQueryDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordQueryDTO.java
new file mode 100644
index 0000000..0411ce7
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordQueryDTO.java
@@ -0,0 +1,21 @@
+package com.doumee.dao.business.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class YwCustomerRechargeRecordQueryDTO {
+
+ private String customerName;
+ private Integer type;
+ private Integer status;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTimeBegin;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTimeEnd;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordVO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordVO.java
new file mode 100644
index 0000000..8ff517e
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwCustomerRechargeRecordVO.java
@@ -0,0 +1,61 @@
+package com.doumee.dao.business.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.doumee.core.annotation.excel.ExcelColumn;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class YwCustomerRechargeRecordVO {
+
+ private Integer id;
+
+ @ExcelColumn(name = "瀹㈡埛鍚嶇О", index = 1, width = 20)
+ private String customerName;
+
+ @ExcelColumn(name = "涓氬姟绫诲瀷", index = 2, width = 10)
+ private String typeText;
+
+ private Integer type;
+
+ @ExcelColumn(name = "璁惧淇℃伅", index = 3, width = 30)
+ private String deviceInfo;
+
+ @ExcelColumn(name = "鍏呭�奸噾棰�(鍏�)", index = 4, width = 12)
+ private BigDecimal money;
+
+ @ExcelColumn(name = "鍏呭�煎墠浣欓", index = 5, width = 12)
+ private BigDecimal banlance;
+
+ @ExcelColumn(name = "鍏呭�煎悗浣欓", index = 6, width = 12)
+ private BigDecimal balanceAfter;
+
+ @ExcelColumn(name = "鐘舵��", index = 7, width = 10)
+ private String statusText;
+
+ private Integer status;
+
+ @ExcelColumn(name = "浠诲姟ID", index = 8, width = 24)
+ private String oprId;
+
+ @ExcelColumn(name = "澶囨敞", index = 9, width = 20)
+ private String remark;
+
+ @ExcelColumn(name = "鐘舵�佽鏄�", index = 10, width = 20)
+ private String statusInfo;
+
+ @ExcelColumn(name = "鎻愪氦鏃堕棿", index = 11, width = 20)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createDate;
+
+ @ExcelColumn(name = "鐘舵�佹洿鏂版椂闂�", index = 12, width = 20)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date statusTime;
+
+ private Integer customerId;
+ private Integer objId;
+ private String address;
+ private String name;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwElectricalOperateDTO.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwElectricalOperateDTO.java
index 739535a..88981ec 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwElectricalOperateDTO.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/dto/YwElectricalOperateDTO.java
@@ -12,4 +12,6 @@
private String action;
private BigDecimal money;
private String remark;
+ /** 鍟嗘埛鍏呭�煎叆鍙d紶鍏ョ殑瀹㈡埛 ID */
+ private Integer customerId;
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwConditioner.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwConditioner.java
index 21b9db0..da9272c 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwConditioner.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwConditioner.java
@@ -135,4 +135,8 @@
@TableField(exist = false)
@ApiModelProperty("鍗$墖绛涢��-缃戝叧MAC")
private String wgMacFilter;
+
+ @TableField(exist = false)
+ @ApiModelProperty("鍟嗘埛鍏宠仈-鐢佃垂鍗犳瘮%")
+ private Integer devRatio;
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerConditioner.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerConditioner.java
new file mode 100644
index 0000000..c7bff05
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerConditioner.java
@@ -0,0 +1,35 @@
+package com.doumee.dao.business.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.doumee.core.model.LoginUserModel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("yw_customer_conditioner")
+@ApiModel("鍟嗘埛鍏宠仈绌鸿皟鍐呮満")
+public class YwCustomerConditioner extends LoginUserModel {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+ private Integer creator;
+ private Date createDate;
+ private Integer editor;
+ private Date editDate;
+ private Integer isdeleted;
+ private String remark;
+
+ @ApiModelProperty("瀹㈡埛 ID")
+ private Integer customerId;
+
+ @ApiModelProperty("绌鸿皟鍐呮満 ID")
+ private Integer conditionerId;
+
+ @ApiModelProperty("鐢佃垂鍗犳瘮%")
+ private Integer devRatio;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerElectrical.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerElectrical.java
new file mode 100644
index 0000000..8772028
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerElectrical.java
@@ -0,0 +1,32 @@
+package com.doumee.dao.business.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.doumee.core.model.LoginUserModel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("yw_customer_electrical")
+@ApiModel("鍟嗘埛鍏宠仈鐢佃〃")
+public class YwCustomerElectrical extends LoginUserModel {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+ private Integer creator;
+ private Date createDate;
+ private Integer editor;
+ private Date editDate;
+ private Integer isdeleted;
+ private String remark;
+
+ @ApiModelProperty("瀹㈡埛 ID")
+ private Integer customerId;
+
+ @ApiModelProperty("鐢佃〃 ID")
+ private Integer electricalId;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerGs.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerGs.java
new file mode 100644
index 0000000..533c526
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwCustomerGs.java
@@ -0,0 +1,51 @@
+package com.doumee.dao.business.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.doumee.core.model.LoginUserModel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("yw_customer_gs")
+@ApiModel("鍟嗘埛绌鸿皟 GS 閰嶇疆")
+public class YwCustomerGs extends LoginUserModel {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+ private Integer creator;
+ private Date createDate;
+ private Integer editor;
+ private Date editDate;
+ private Integer isdeleted;
+ private String remark;
+
+ @ApiModelProperty("瀹㈡埛 ID")
+ private Integer customerId;
+
+ @ApiModelProperty("鏅虹簿鐏� GS 鍏徃 ID")
+ private Integer platformGsId;
+
+ @ApiModelProperty("璁¤垂寮�鍏� 0鍏� 1寮�")
+ private Integer isPwr;
+
+ @ApiModelProperty("18:00-09:00 涓嶅仠鏈� 0鍚� 1鏄�")
+ private Integer isRestStop;
+
+ @ApiModelProperty("澶囨敞")
+ private String gsBz;
+
+ @ApiModelProperty("娆犺垂棰濆害锛堝厓锛�")
+ private BigDecimal stopMoney;
+
+ @ApiModelProperty("鍓╀綑閲戦")
+ private BigDecimal leftMoney;
+
+ @ApiModelProperty("浣欓鍚屾鏃堕棿")
+ private Date syncDate;
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwElectricalCharge.java b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwElectricalCharge.java
index f50a488..520a07b 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwElectricalCharge.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/YwElectricalCharge.java
@@ -98,8 +98,14 @@
@ApiModelProperty("鍏呭�煎墠璐﹀彿浣欓锛堝厓锛�")
@ExcelColumn(name="鍏呭�煎墠璐﹀彿浣欓锛堝厓锛�",index=25 ,width=10)
private BigDecimal banlance;
+ @ApiModelProperty("鍏呭�煎悗浣欓锛堝厓锛�")
+ @ExcelColumn(name="鍏呭�煎悗浣欓锛堝厓锛�",index=26 ,width=10)
+ private BigDecimal balanceAfter;
+ @ApiModelProperty("璁惧灞曠ず淇℃伅")
+ @ExcelColumn(name="璁惧灞曠ず淇℃伅",index=27 ,width=10)
+ private String deviceInfo;
@ApiModelProperty("閫夋嫨鐢佃〃鍙傛暟鐩存帴锛坹w_electrical_param)")
- @ExcelColumn(name="閫夋嫨鐢佃〃鍙傛暟鐩存帴锛坹w_electrical_param)",index=26 ,width=10)
+ @ExcelColumn(name="閫夋嫨鐢佃〃鍙傛暟鐩存帴锛坹w_electrical_param)",index=28 ,width=10)
private Integer paramId;
@TableField(exist = false)
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwCustomerRechargeBizService.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwCustomerRechargeBizService.java
new file mode 100644
index 0000000..d81dfc8
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwCustomerRechargeBizService.java
@@ -0,0 +1,56 @@
+package com.doumee.service.business;
+
+import com.doumee.core.model.LoginUserInfo;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.dao.business.dto.*;
+import com.doumee.dao.business.model.YwConditioner;
+import com.doumee.dao.business.model.YwCustomerGs;
+import com.doumee.dao.business.model.YwElectrical;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+
+public interface YwCustomerRechargeBizService {
+
+ PageData<YwCustomerRechargeMerchantVO> findMerchantPage(PageWrap<YwCustomerRechargeQueryDTO> pageWrap);
+
+ YwCustomerRechargeDetailVO getDetail(Integer customerId);
+
+ PageData<YwElectrical> listCustomerElectrical(PageWrap<YwElectrical> pageWrap, Integer customerId);
+
+ PageData<YwElectrical> pageSelectableElectrical(PageWrap<YwElectrical> pageWrap, Integer customerId);
+
+ void saveCustomerElectrical(YwCustomerElectricalSaveDTO dto, LoginUserInfo user);
+
+ void removeCustomerElectrical(Integer customerId, Integer electricalId, LoginUserInfo user);
+
+ PageData<YwConditioner> listCustomerConditioner(PageWrap<YwConditioner> pageWrap, Integer customerId);
+
+ YwCustomerGs getCustomerGsConfig(Integer customerId);
+
+ void saveCustomerGsConfig(YwCustomerGsConfigDTO dto, LoginUserInfo user);
+
+ String rechargeElectrical(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user);
+
+ String resetElectricalAccount(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user);
+
+ Map<String, Object> readMeterAndRefresh(Integer customerId, Integer electricalId, LoginUserInfo user);
+
+ Map<String, Object> getElectricalRemoteInfo(Integer electricalId);
+
+ Map<String, Object> getConditionerRechargeInfo(Integer customerId);
+
+ String rechargeConditioner(YwCustomerRechargeConditionerDTO dto, LoginUserInfo user);
+
+ String cleanConditionerAccount(Integer customerId, LoginUserInfo user);
+
+ PageData<YwCustomerRechargeRecordVO> findRechargeRecordPage(PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap);
+
+ String retryRecharge(Integer id, LoginUserInfo user);
+
+ String syncRechargeStatus(Integer id, LoginUserInfo user);
+
+ void exportRechargeRecord(PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap, HttpServletResponse response);
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalActionsService.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalActionsService.java
index 4882fb9..38e7946 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalActionsService.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalActionsService.java
@@ -10,4 +10,7 @@
public interface YwElectricalActionsService {
PageData<YwElectricalActions> findPage(PageWrap<YwElectricalActions> pageWrap);
+
+ /** 涓诲姩鏌ヨ寮傛浠诲姟鐘舵�佸苟鍚屾鏈湴鎿嶄綔/鍏呭�肩粨鏋� */
+ String queryAsyncResult(Integer id);
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalBizService.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalBizService.java
index c2cf405..540e88c 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalBizService.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/YwElectricalBizService.java
@@ -21,6 +21,15 @@
boolean handleElectricalNotify(String responseContent, String timestamp, String sign);
+ /** 涓诲姩鏌ヨ鍗曚釜寮傛浠诲姟鐘舵�佸苟鍚屾鏈湴璁板綍 */
+ String syncAsyncActionStatus(String oprId);
+
+ /** 鎸夊厖鍊艰褰� ID 鎵嬪姩鍚屾锛堜粎鍏呭�间腑鐢佃〃璁板綍锛� */
+ String syncChargeStatusById(Integer chargeId);
+
+ /** 瀹氭椂鎵归噺鏌ヨ澶勭悊涓殑寮傛浠诲姟鐘舵�侊紙鍥炶皟涓㈠け鏃剁殑琛ュ伩锛� */
+ void syncPendingAsyncActionsScheduled();
+
void syncMeterDataScheduled();
/** 鎵嬪姩浠庣涓夋柟骞冲彴鎷夊彇鎶勮〃鏁版嵁鍏ュ簱 */
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java
new file mode 100644
index 0000000..8cfe1f1
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java
@@ -0,0 +1,943 @@
+package com.doumee.service.business.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.doumee.core.annotation.excel.ExcelExporter;
+import com.doumee.core.conditoner.ConditionerUtil;
+import com.doumee.core.conditoner.model.request.AddMoneyRequest;
+import com.doumee.core.conditoner.model.request.CompanyGsManageRequest;
+import com.doumee.core.conditoner.model.request.LogQueryRequest;
+import com.doumee.core.conditoner.model.response.CompanyGsInfoResponse;
+import com.doumee.core.conditoner.model.response.ConditionerBaseResponse;
+import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.exception.BusinessException;
+import com.doumee.core.model.LoginUserInfo;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.core.utils.Constants;
+import com.doumee.core.utils.Utils;
+import com.doumee.dao.business.*;
+import com.doumee.dao.business.dto.*;
+import com.doumee.dao.business.model.*;
+import com.doumee.service.business.ConditionerBizService;
+import com.doumee.service.business.YwCustomerRechargeBizService;
+import com.doumee.service.business.YwElectricalBizService;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class YwCustomerRechargeBizServiceImpl implements YwCustomerRechargeBizService {
+
+ private static final String ONLINE_TEXT = "鍦ㄧ嚎";
+
+ @Autowired
+ private YwCustomerMapper ywCustomerMapper;
+ @Autowired
+ private MemberMapper memberMapper;
+ @Autowired
+ private YwCustomerGsMapper ywCustomerGsMapper;
+ @Autowired
+ private YwCustomerElectricalMapper ywCustomerElectricalMapper;
+ @Autowired
+ private YwCustomerConditionerMapper ywCustomerConditionerMapper;
+ @Autowired
+ private YwElectricalMapper ywElectricalMapper;
+ @Autowired
+ private YwConditionerMapper ywConditionerMapper;
+ @Autowired
+ private YwElectricalChargeMapper ywElectricalChargeMapper;
+ @Autowired
+ private YwElectricalActionsMapper ywElectricalActionsMapper;
+ @Autowired
+ private YwElectricalBizService ywElectricalBizService;
+ @Autowired
+ private ConditionerBizService conditionerBizService;
+
+ @Override
+ public PageData<YwCustomerRechargeMerchantVO> findMerchantPage(PageWrap<YwCustomerRechargeQueryDTO> pageWrap) {
+ YwCustomerRechargeQueryDTO query = pageWrap.getModel() != null ? pageWrap.getModel() : new YwCustomerRechargeQueryDTO();
+ boolean hasDeviceFilter = query.getElectricalStatusFilter() != null || query.getConditionerStatusFilter() != null;
+
+ if (hasDeviceFilter) {
+ List<YwCustomer> all = ywCustomerMapper.selectList(new QueryWrapper<YwCustomer>().lambda()
+ .eq(YwCustomer::getIsdeleted, Constants.ZERO)
+ .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword())
+ .orderByDesc(YwCustomer::getCreateDate));
+ List<YwCustomerRechargeMerchantVO> enriched = enrichMerchantList(all);
+ List<YwCustomerRechargeMerchantVO> filtered = enriched.stream()
+ .filter(vo -> matchDeviceFilter(vo, query))
+ .collect(Collectors.toList());
+ return manualPage(filtered, pageWrap.getPage(), pageWrap.getCapacity());
+ }
+
+ IPage<YwCustomer> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+ IPage<YwCustomer> result = ywCustomerMapper.selectPage(page, new QueryWrapper<YwCustomer>().lambda()
+ .eq(YwCustomer::getIsdeleted, Constants.ZERO)
+ .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword())
+ .orderByDesc(YwCustomer::getCreateDate));
+ List<YwCustomerRechargeMerchantVO> list = enrichMerchantList(result.getRecords());
+ PageData<YwCustomerRechargeMerchantVO> data = new PageData<>();
+ data.setRecords(list);
+ data.setTotal(result.getTotal());
+ data.setPage(result.getCurrent());
+ data.setCapacity(result.getSize());
+ return data;
+ }
+
+ private PageData<YwCustomerRechargeMerchantVO> manualPage(List<YwCustomerRechargeMerchantVO> list, long page, long capacity) {
+ int p = (int) Math.max(page, 1);
+ int size = (int) Math.max(capacity, 1);
+ int from = (p - 1) * size;
+ int to = Math.min(from + size, list.size());
+ PageData<YwCustomerRechargeMerchantVO> data = new PageData<>();
+ data.setTotal(list.size());
+ data.setPage(p);
+ data.setCapacity(size);
+ data.setRecords(from >= list.size() ? Collections.emptyList() : list.subList(from, to));
+ return data;
+ }
+
+ private boolean matchDeviceFilter(YwCustomerRechargeMerchantVO vo, YwCustomerRechargeQueryDTO query) {
+ if (query.getElectricalStatusFilter() != null && !matchStatusFilter(
+ query.getElectricalStatusFilter(), vo.getElectricalCount(), vo.getElectricalOnlineAll(), vo.getElectricalHasOffline())) {
+ return false;
+ }
+ if (query.getConditionerStatusFilter() != null && !matchStatusFilter(
+ query.getConditionerStatusFilter(), vo.getConditionerCount(), vo.getConditionerOnlineAll(), vo.getConditionerHasOffline())) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean matchStatusFilter(Integer filter, Integer count, Boolean allOnline, Boolean hasOffline) {
+ int c = count != null ? count : 0;
+ if (filter == 3) {
+ return c == 0;
+ }
+ if (c == 0) {
+ return false;
+ }
+ if (filter == 1) {
+ return Boolean.TRUE.equals(allOnline);
+ }
+ if (filter == 2) {
+ return Boolean.TRUE.equals(hasOffline);
+ }
+ return true;
+ }
+
+ private List<YwCustomerRechargeMerchantVO> enrichMerchantList(List<YwCustomer> customers) {
+ if (CollectionUtils.isEmpty(customers)) {
+ return Collections.emptyList();
+ }
+ List<Integer> customerIds = customers.stream().map(YwCustomer::getId).collect(Collectors.toList());
+
+ Map<Integer, YwCustomerGs> gsMap = ywCustomerGsMapper.selectList(new QueryWrapper<YwCustomerGs>().lambda()
+ .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
+ .in(YwCustomerGs::getCustomerId, customerIds))
+ .stream().collect(Collectors.toMap(YwCustomerGs::getCustomerId, g -> g, (a, b) -> a));
+
+ List<YwCustomerElectrical> relE = ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)
+ .in(YwCustomerElectrical::getCustomerId, customerIds));
+ Map<Integer, List<Integer>> customerElectricalIds = relE.stream()
+ .collect(Collectors.groupingBy(YwCustomerElectrical::getCustomerId,
+ Collectors.mapping(YwCustomerElectrical::getElectricalId, Collectors.toList())));
+
+ List<YwCustomerConditioner> relC = ywCustomerConditionerMapper.selectList(new QueryWrapper<YwCustomerConditioner>().lambda()
+ .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO)
+ .in(YwCustomerConditioner::getCustomerId, customerIds));
+ Map<Integer, List<Integer>> customerConditionerIds = relC.stream()
+ .collect(Collectors.groupingBy(YwCustomerConditioner::getCustomerId,
+ Collectors.mapping(YwCustomerConditioner::getConditionerId, Collectors.toList())));
+
+ Set<Integer> allElectricalIds = relE.stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet());
+ Map<Integer, YwElectrical> electricalMap = allElectricalIds.isEmpty() ? Collections.emptyMap()
+ : ywElectricalMapper.selectBatchIds(allElectricalIds).stream()
+ .filter(e -> !Objects.equals(e.getIsdeleted(), Constants.ONE))
+ .collect(Collectors.toMap(YwElectrical::getId, e -> e, (a, b) -> a));
+
+ Set<Integer> allConditionerIds = relC.stream().map(YwCustomerConditioner::getConditionerId).collect(Collectors.toSet());
+ Map<Integer, YwConditioner> conditionerMap = allConditionerIds.isEmpty() ? Collections.emptyMap()
+ : ywConditionerMapper.selectBatchIds(allConditionerIds).stream()
+ .filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE))
+ .collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a));
+
+ Set<Integer> memberIds = customers.stream()
+ .map(YwCustomer::getMemberId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ Map<Integer, Member> memberMap = memberIds.isEmpty() ? Collections.emptyMap()
+ : memberMapper.selectBatchIds(memberIds).stream()
+ .filter(m -> !Objects.equals(m.getIsdeleted(), Constants.ONE))
+ .collect(Collectors.toMap(Member::getId, m -> m, (a, b) -> a));
+
+ List<YwCustomerRechargeMerchantVO> list = new ArrayList<>();
+ for (YwCustomer c : customers) {
+ YwCustomerRechargeMerchantVO vo = new YwCustomerRechargeMerchantVO();
+ vo.setId(c.getId());
+ vo.setType(c.getType());
+ vo.setName(c.getName());
+ vo.setPhone(c.getPhone());
+ vo.setCreateDate(c.getCreateDate());
+ Member member = c.getMemberId() != null ? memberMap.get(c.getMemberId()) : null;
+ if (member != null) {
+ vo.setMemberName(member.getName());
+ vo.setMemberPhone(member.getPhone());
+ }
+
+ List<Integer> eIds = customerElectricalIds.getOrDefault(c.getId(), Collections.emptyList());
+ vo.setElectricalCount(eIds.size());
+ if (eIds.isEmpty()) {
+ vo.setElectricalBalances(Collections.emptyList());
+ vo.setElectricalOnlineAll(false);
+ vo.setElectricalHasOffline(false);
+ } else {
+ List<YwCustomerElectricalBalanceItem> balanceItems = new ArrayList<>();
+ boolean allOnline = true;
+ boolean hasOffline = false;
+ int index = 0;
+ for (Integer eid : eIds) {
+ YwElectrical e = electricalMap.get(eid);
+ if (e == null) continue;
+ YwCustomerElectricalBalanceItem item = new YwCustomerElectricalBalanceItem();
+ index++;
+ item.setName(StringUtils.isNotBlank(e.getName()) ? e.getName() : ("鐢佃〃" + index));
+ item.setAddress(StringUtils.isNotBlank(e.getAddress()) ? e.getAddress() : "-");
+ item.setBalance(e.getBalance() != null ? e.getBalance() : BigDecimal.ZERO);
+ balanceItems.add(item);
+ if (!Objects.equals(e.getOnline(), Constants.ONE)) {
+ allOnline = false;
+ hasOffline = true;
+ }
+ }
+ vo.setElectricalBalances(balanceItems);
+ vo.setElectricalOnlineAll(allOnline && !balanceItems.isEmpty());
+ vo.setElectricalHasOffline(hasOffline);
+ }
+
+ List<Integer> cIds = customerConditionerIds.getOrDefault(c.getId(), Collections.emptyList());
+ vo.setConditionerCount(cIds.size());
+ if (cIds.isEmpty()) {
+ vo.setConditionerOnlineAll(false);
+ vo.setConditionerHasOffline(false);
+ } else {
+ boolean allOnline = true;
+ boolean hasOffline = false;
+ for (Integer cid : cIds) {
+ YwConditioner cond = conditionerMap.get(cid);
+ if (cond == null) continue;
+ if (!ONLINE_TEXT.equals(cond.getOnline())) {
+ allOnline = false;
+ hasOffline = true;
+ }
+ }
+ vo.setConditionerOnlineAll(allOnline);
+ vo.setConditionerHasOffline(hasOffline);
+ }
+
+ YwCustomerGs gs = gsMap.get(c.getId());
+ if (gs != null) {
+ vo.setAcBalance(gs.getLeftMoney());
+ vo.setAcBalanceSyncDate(gs.getSyncDate());
+ }
+ list.add(vo);
+ }
+ return list;
+ }
+
+ @Override
+ public YwCustomerRechargeDetailVO getDetail(Integer customerId) {
+ YwCustomer customer = requireCustomer(customerId);
+ YwCustomerRechargeDetailVO vo = new YwCustomerRechargeDetailVO();
+ vo.setCustomerId(customer.getId());
+ vo.setCustomerName(customer.getName());
+ vo.setPhone(customer.getPhone());
+ vo.setGsConfig(getCustomerGsConfig(customerId));
+ vo.setElectricalList(loadCustomerElectricalList(customerId));
+ vo.setConditionerList(loadCustomerConditionerList(customerId));
+ return vo;
+ }
+
+ @Override
+ public PageData<YwElectrical> listCustomerElectrical(PageWrap<YwElectrical> pageWrap, Integer customerId) {
+ requireCustomer(customerId);
+ List<Integer> ids = listBoundElectricalIds(customerId);
+ if (ids.isEmpty()) {
+ return emptyPage(pageWrap);
+ }
+ return pageElectricalByIds(pageWrap, ids);
+ }
+
+ @Override
+ public PageData<YwElectrical> pageSelectableElectrical(PageWrap<YwElectrical> pageWrap, Integer customerId) {
+ requireCustomer(customerId);
+ Set<Integer> excluded = listAllBoundElectricalIds();
+ IPage<YwElectrical> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+ YwElectrical model = pageWrap.getModel();
+ QueryWrapper<YwElectrical> qw = new QueryWrapper<>();
+ qw.lambda()
+ .eq(YwElectrical::getIsdeleted, Constants.ZERO)
+ .notIn(!excluded.isEmpty(), YwElectrical::getId, excluded)
+ .and(model != null && StringUtils.isNotBlank(model.getName()), w -> w
+ .like(YwElectrical::getName, model.getName())
+ .or().like(YwElectrical::getAddress, model.getName()))
+ .orderByDesc(YwElectrical::getCreateDate);
+ IPage<YwElectrical> result = ywElectricalMapper.selectPage(page, qw);
+ ywElectricalBizService.enrichList(result.getRecords());
+ return PageData.from(result);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void saveCustomerElectrical(YwCustomerElectricalSaveDTO dto, LoginUserInfo user) {
+ requireCustomer(dto.getCustomerId());
+ if (CollectionUtils.isEmpty(dto.getElectricalIds())) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇烽�夋嫨鐢佃〃");
+ }
+ Set<Integer> excluded = listAllBoundElectricalIdsExcept(dto.getCustomerId());
+ for (Integer eid : dto.getElectricalIds()) {
+ if (excluded.contains(eid)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐢佃〃宸茶鍏朵粬鍟嗘埛缁戝畾锛�" + eid);
+ }
+ YwCustomerElectrical exist = ywCustomerElectricalMapper.selectOne(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getCustomerId, dto.getCustomerId())
+ .eq(YwCustomerElectrical::getElectricalId, eid)
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)
+ .last("limit 1"));
+ if (exist != null) {
+ continue;
+ }
+ YwCustomerElectrical rel = new YwCustomerElectrical();
+ rel.setCreator(user.getId());
+ rel.setCreateDate(new Date());
+ rel.setEditor(user.getId());
+ rel.setEditDate(new Date());
+ rel.setIsdeleted(Constants.ZERO);
+ rel.setCustomerId(dto.getCustomerId());
+ rel.setElectricalId(eid);
+ ywCustomerElectricalMapper.insert(rel);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void removeCustomerElectrical(Integer customerId, Integer electricalId, LoginUserInfo user) {
+ ywCustomerElectricalMapper.update(null, new UpdateWrapper<YwCustomerElectrical>().lambda()
+ .set(YwCustomerElectrical::getIsdeleted, Constants.ONE)
+ .set(YwCustomerElectrical::getEditDate, new Date())
+ .set(YwCustomerElectrical::getEditor, user.getId())
+ .eq(YwCustomerElectrical::getCustomerId, customerId)
+ .eq(YwCustomerElectrical::getElectricalId, electricalId)
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO));
+ }
+
+ @Override
+ public PageData<YwConditioner> listCustomerConditioner(PageWrap<YwConditioner> pageWrap, Integer customerId) {
+ requireCustomer(customerId);
+ List<YwConditioner> list = loadCustomerConditionerList(customerId);
+ if (CollectionUtils.isEmpty(list)) {
+ return emptyPage(pageWrap);
+ }
+ int p = (int) Math.max(pageWrap.getPage(), 1);
+ int size = (int) Math.max(pageWrap.getCapacity(), 1);
+ int from = (p - 1) * size;
+ int to = Math.min(from + size, list.size());
+ PageData<YwConditioner> data = new PageData<>();
+ data.setTotal(list.size());
+ data.setPage(p);
+ data.setCapacity(size);
+ data.setRecords(from >= list.size() ? Collections.emptyList() : list.subList(from, to));
+ return data;
+ }
+
+ @Override
+ public YwCustomerGs getCustomerGsConfig(Integer customerId) {
+ return ywCustomerGsMapper.selectOne(new QueryWrapper<YwCustomerGs>().lambda()
+ .eq(YwCustomerGs::getCustomerId, customerId)
+ .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
+ .last("limit 1"));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void saveCustomerGsConfig(YwCustomerGsConfigDTO dto, LoginUserInfo user) {
+ YwCustomer customer = requireCustomer(dto.getCustomerId());
+ if (CollectionUtils.isEmpty(dto.getConditioners())) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇疯嚦灏戝叧鑱斾竴鍙扮┖璋冨唴鏈�");
+ }
+ conditionerBizService.ensureLogin();
+
+ List<Integer> conditionerIds = dto.getConditioners().stream()
+ .map(YwCustomerGsConfigDTO.ConditionerItem::getConditionerId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ List<YwConditioner> conditioners = ywConditionerMapper.selectBatchIds(conditionerIds);
+ Map<Integer, YwConditioner> condMap = conditioners.stream()
+ .filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE))
+ .collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a));
+
+ List<Integer> liDev = new ArrayList<>();
+ Map<String, Object> dDev = new LinkedHashMap<>();
+ for (YwCustomerGsConfigDTO.ConditionerItem item : dto.getConditioners()) {
+ YwConditioner cond = condMap.get(item.getConditionerId());
+ if (cond == null || cond.getPlatformDevId() == null) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鍐呮満缂哄皯骞冲彴璁惧 ID");
+ }
+ liDev.add(cond.getPlatformDevId());
+ int ratio = item.getDevRatio() != null ? item.getDevRatio() : 100;
+ dDev.put(String.valueOf(cond.getPlatformDevId()), ratio);
+ }
+
+ YwCustomerGs gs = getCustomerGsConfig(dto.getCustomerId());
+ if (gs == null) {
+ gs = new YwCustomerGs();
+ gs.setCreator(user.getId());
+ gs.setCreateDate(new Date());
+ gs.setIsdeleted(Constants.ZERO);
+ gs.setCustomerId(dto.getCustomerId());
+ }
+ gs.setEditor(user.getId());
+ gs.setEditDate(new Date());
+ gs.setIsPwr(dto.getIsPwr() != null ? dto.getIsPwr() : Constants.ONE);
+ gs.setIsRestStop(dto.getIsRestStop() != null ? dto.getIsRestStop() : Constants.ZERO);
+ gs.setGsBz(StringUtils.defaultString(dto.getGsBz()));
+ gs.setStopMoney(dto.getStopMoney() != null ? dto.getStopMoney() : BigDecimal.ZERO);
+
+ if (StringUtils.isBlank(customer.getName())) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀹㈡埛鍚嶇О涓嶈兘涓虹┖");
+ }
+ if (liDev.isEmpty()) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鍏宠仈鍐呮満骞冲彴璁惧 ID 鏃犳晥");
+ }
+
+ CompanyGsManageRequest companyReq = new CompanyGsManageRequest();
+ companyReq.fillSessionDefaults();
+ companyReq.setGs_name(customer.getName().trim());
+ companyReq.setIs_pwr(gs.getIsPwr());
+ companyReq.setIs_rest_stop(gs.getIsRestStop());
+ companyReq.setGs_bz(gs.getGsBz());
+ companyReq.setStop_money(gs.getStopMoney());
+
+ if (gs.getPlatformGsId() == null) {
+ ConditionerBaseResponse<Object> addResp = ConditionerUtil.addGs(companyReq);
+ if (addResp == null || !addResp.isSuccess()) {
+ throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(addResp, "addGs 澶辫触"));
+ }
+ gs.setPlatformGsId(parseAddGsId(addResp.getData()));
+ if (gs.getPlatformGsId() == null) {
+ throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "addGs 鏈繑鍥炲叕鍙� ID");
+ }
+ }
+
+ CompanyGsManageRequest changeReq = new CompanyGsManageRequest();
+ changeReq.fillSessionDefaults();
+ changeReq.setId(gs.getPlatformGsId());
+ changeReq.setGs_name(companyReq.getGs_name());
+ changeReq.setIs_pwr(companyReq.getIs_pwr());
+ changeReq.setIs_rest_stop(companyReq.getIs_rest_stop());
+ changeReq.setGs_bz(companyReq.getGs_bz());
+ changeReq.setStop_money(gs.getStopMoney());
+ changeReq.setLi_dev(liDev);
+ changeReq.setD_dev(dDev);
+ if (gs.getLeftMoney() != null) {
+ changeReq.setLeft_money(gs.getLeftMoney());
+ }
+ ConditionerBaseResponse<Object> changeResp = ConditionerUtil.changeGs(changeReq);
+ if (changeResp == null || !changeResp.isSuccess()) {
+ throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(changeResp, "changeGs 澶辫触"));
+ }
+
+ refreshGsLeftMoney(gs);
+ if (gs.getId() == null) {
+ ywCustomerGsMapper.insert(gs);
+ } else {
+ ywCustomerGsMapper.updateById(gs);
+ }
+
+ ywCustomerConditionerMapper.update(null, new UpdateWrapper<YwCustomerConditioner>().lambda()
+ .set(YwCustomerConditioner::getIsdeleted, Constants.ONE)
+ .set(YwCustomerConditioner::getEditDate, new Date())
+ .set(YwCustomerConditioner::getEditor, user.getId())
+ .eq(YwCustomerConditioner::getCustomerId, dto.getCustomerId())
+ .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO));
+
+ for (YwCustomerGsConfigDTO.ConditionerItem item : dto.getConditioners()) {
+ YwCustomerConditioner rel = new YwCustomerConditioner();
+ rel.setCreator(user.getId());
+ rel.setCreateDate(new Date());
+ rel.setEditor(user.getId());
+ rel.setEditDate(new Date());
+ rel.setIsdeleted(Constants.ZERO);
+ rel.setCustomerId(dto.getCustomerId());
+ rel.setConditionerId(item.getConditionerId());
+ rel.setDevRatio(item.getDevRatio() != null ? item.getDevRatio() : 100);
+ ywCustomerConditionerMapper.insert(rel);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String rechargeElectrical(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user) {
+ requireCustomer(dto.getCustomerId());
+ assertElectricalBound(dto.getCustomerId(), dto.getElectricalId());
+ YwElectricalOperateDTO op = new YwElectricalOperateDTO();
+ op.setElectricalId(dto.getElectricalId());
+ op.setAction("recharge");
+ op.setMoney(dto.getMoney());
+ op.setRemark(dto.getRemark());
+ op.setCustomerId(dto.getCustomerId());
+ return ywElectricalBizService.operate(op, user);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String resetElectricalAccount(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user) {
+ requireCustomer(dto.getCustomerId());
+ assertElectricalBound(dto.getCustomerId(), dto.getElectricalId());
+ String action = StringUtils.defaultIfBlank(dto.getResetAction(), "resetPrepay");
+ YwElectricalOperateDTO op = new YwElectricalOperateDTO();
+ op.setElectricalId(dto.getElectricalId());
+ op.setAction(action);
+ op.setCustomerId(dto.getCustomerId());
+ return ywElectricalBizService.operate(op, user);
+ }
+
+ @Override
+ public Map<String, Object> getElectricalRemoteInfo(Integer electricalId) {
+ return ywElectricalBizService.getRemoteInfo(electricalId);
+ }
+
+ @Override
+ public Map<String, Object> readMeterAndRefresh(Integer customerId, Integer electricalId, LoginUserInfo user) {
+ assertElectricalBound(customerId, electricalId);
+ YwElectricalOperateDTO op = new YwElectricalOperateDTO();
+ op.setElectricalId(electricalId);
+ op.setAction("readMeter");
+ op.setCustomerId(customerId);
+ String msg = ywElectricalBizService.operate(op, user);
+ Map<String, Object> info = ywElectricalBizService.getRemoteInfo(electricalId);
+ info.put("message", msg);
+ return info;
+ }
+
+ @Override
+ public Map<String, Object> getConditionerRechargeInfo(Integer customerId) {
+ YwCustomerGs gs = requireGsConfig(customerId);
+ conditionerBizService.ensureLogin();
+ refreshGsLeftMoney(gs);
+ ywCustomerGsMapper.updateById(gs);
+
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("gsConfig", gs);
+ map.put("customerName", requireCustomer(customerId).getName());
+ CompanyGsManageRequest req = new CompanyGsManageRequest();
+ req.fillSessionDefaults();
+ req.setId(gs.getPlatformGsId());
+ ConditionerBaseResponse<List<CompanyGsInfoResponse>> resp = ConditionerUtil.getGs(req);
+ if (resp != null && resp.isSuccess() && !CollectionUtils.isEmpty(resp.getData())) {
+ CompanyGsInfoResponse info = resp.getData().get(0);
+ map.put("platformInfo", info);
+ }
+ return map;
+ }
+
+ @Override
+ public String rechargeConditioner(YwCustomerRechargeConditionerDTO dto, LoginUserInfo user) {
+ YwCustomerGs gs = requireGsConfig(dto.getCustomerId());
+ if (dto.getMoney() == null || dto.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鍏呭�奸噾棰濋』澶т簬 0");
+ }
+ conditionerBizService.ensureLogin();
+ AddMoneyRequest req = new AddMoneyRequest();
+ req.fillSessionDefaults();
+ req.setId(gs.getPlatformGsId());
+ req.setCz_money(dto.getMoney().toPlainString());
+ ConditionerBaseResponse<Object> resp = ConditionerUtil.addMoney(req);
+ YwElectricalCharge charge = buildConditionerCharge(dto, gs, user);
+ if (resp != null && resp.isSuccess()) {
+ refreshGsLeftMoney(gs);
+ ywCustomerGsMapper.updateById(gs);
+ charge.setStatus(Constants.ONE);
+ charge.setStatusInfo("鍏呭�兼垚鍔�");
+ charge.setBalanceAfter(gs.getLeftMoney());
+ ywElectricalChargeMapper.insert(charge);
+ return "鍏呭�兼垚鍔�";
+ }
+ charge.setStatus(Constants.TWO);
+ charge.setStatusInfo(apiMsg(resp, "鍏呭�煎け璐�"));
+ ywElectricalChargeMapper.insert(charge);
+ throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), charge.getStatusInfo());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String cleanConditionerAccount(Integer customerId, LoginUserInfo user) {
+ YwCustomerGs gs = requireGsConfig(customerId);
+ conditionerBizService.ensureLogin();
+ CompanyGsManageRequest req = new CompanyGsManageRequest();
+ req.fillSessionDefaults();
+ req.setId(gs.getPlatformGsId());
+ ConditionerBaseResponse<Object> resp = ConditionerUtil.cleanMoney(req);
+ if (resp == null || !resp.isSuccess()) {
+ throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "娓呴浂澶辫触"));
+ }
+ refreshGsLeftMoney(gs);
+ gs.setEditor(user.getId());
+ gs.setEditDate(new Date());
+ ywCustomerGsMapper.updateById(gs);
+ return "娓呴浂鎴愬姛";
+ }
+
+ @Override
+ public PageData<YwCustomerRechargeRecordVO> findRechargeRecordPage(PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap) {
+ Utils.MP.blankToNull(pageWrap.getModel());
+ YwCustomerRechargeRecordQueryDTO query = pageWrap.getModel() != null ? pageWrap.getModel() : new YwCustomerRechargeRecordQueryDTO();
+ IPage<YwCustomerRechargeRecordVO> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+ MPJLambdaWrapper<YwElectricalCharge> wrapper = new MPJLambdaWrapper<YwElectricalCharge>()
+ .selectAll(YwElectricalCharge.class)
+ .selectAs(YwCustomer::getName, YwCustomerRechargeRecordVO::getCustomerName)
+ .leftJoin(YwCustomer.class, YwCustomer::getId, YwElectricalCharge::getCustomerId)
+ .isNotNull(YwElectricalCharge::getCustomerId)
+ .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO)
+ .eq(query.getType() != null, YwElectricalCharge::getType, query.getType())
+ .eq(query.getStatus() != null, YwElectricalCharge::getStatus, query.getStatus())
+ .like(StringUtils.isNotBlank(query.getCustomerName()), YwCustomer::getName, query.getCustomerName())
+ .ge(query.getCreateTimeBegin() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeBegin())
+ .le(query.getCreateTimeEnd() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeEnd())
+ .orderByDesc(YwElectricalCharge::getCreateDate);
+ IPage<YwCustomerRechargeRecordVO> result = ywElectricalChargeMapper.selectJoinPage(page, YwCustomerRechargeRecordVO.class, wrapper);
+ result.getRecords().forEach(this::fillRecordText);
+ return PageData.from(result);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String retryRecharge(Integer id, LoginUserInfo user) {
+ YwElectricalCharge charge = requireCharge(id);
+ if (!Objects.equals(charge.getStatus(), Constants.TWO)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呭け璐ヨ褰曞彲鍐嶆鎻愪氦");
+ }
+ if (Objects.equals(charge.getType(), Constants.ZERO)) {
+ YwCustomerRechargeElectricalDTO dto = new YwCustomerRechargeElectricalDTO();
+ dto.setCustomerId(charge.getCustomerId());
+ dto.setElectricalId(charge.getObjId());
+ dto.setMoney(charge.getMoney());
+ dto.setRemark(charge.getRemark());
+ return rechargeElectrical(dto, user);
+ }
+ if (Objects.equals(charge.getType(), Constants.ONE)) {
+ YwCustomerRechargeConditionerDTO dto = new YwCustomerRechargeConditionerDTO();
+ dto.setCustomerId(charge.getCustomerId());
+ dto.setMoney(charge.getMoney());
+ dto.setRemark(charge.getRemark());
+ return rechargeConditioner(dto, user);
+ }
+ throw new BusinessException(ResponseStatus.BAD_REQUEST);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String syncRechargeStatus(Integer id, LoginUserInfo user) {
+ YwElectricalCharge charge = requireCharge(id);
+ if (!Objects.equals(charge.getStatus(), Constants.ZERO)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呭厖鍊间腑璁板綍鍙悓姝�");
+ }
+ if (Objects.equals(charge.getType(), Constants.ZERO)) {
+ return syncElectricalChargeStatus(charge, user);
+ }
+ if (Objects.equals(charge.getType(), Constants.ONE)) {
+ return syncConditionerChargeStatus(charge, user);
+ }
+ throw new BusinessException(ResponseStatus.BAD_REQUEST);
+ }
+
+ @Override
+ public void exportRechargeRecord(PageWrap<YwCustomerRechargeRecordQueryDTO> pageWrap, HttpServletResponse response) {
+ pageWrap.setPage(1);
+ pageWrap.setCapacity(Integer.MAX_VALUE);
+ List<YwCustomerRechargeRecordVO> records = findRechargeRecordPage(pageWrap).getRecords();
+ ExcelExporter.build(YwCustomerRechargeRecordVO.class).export(records, "鍟嗘埛鍏呭�艰褰�", response);
+ }
+
+ private String syncElectricalChargeStatus(YwElectricalCharge charge, LoginUserInfo user) {
+ return ywElectricalBizService.syncAsyncActionStatus(charge.getOprId());
+ }
+
+ private String syncConditionerChargeStatus(YwElectricalCharge charge, LoginUserInfo user) {
+ YwCustomerGs gs = requireGsConfig(charge.getCustomerId());
+ conditionerBizService.ensureLogin();
+ LogQueryRequest req = new LogQueryRequest();
+ req.fillSessionDefaults();
+ req.setPage(1);
+ req.setPageSize(50);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ if (charge.getCreateDate() != null) {
+ String day = sdf.format(charge.getCreateDate());
+ req.setStart_time(day);
+ req.setEnd_time(day);
+ }
+ ConditionerBaseResponse<List<Object>> resp = ConditionerUtil.getCzLog(req);
+ if (resp == null || !resp.isSuccess() || CollectionUtils.isEmpty(resp.getData())) {
+ return "鏈尮閰嶅埌骞冲彴鍏呭�兼棩蹇楋紝浠嶄负鍏呭�间腑";
+ }
+ for (Object row : resp.getData()) {
+ JSONObject o = (JSONObject) JSON.toJSON(row);
+ if (!matchCzLog(o, gs.getPlatformGsId(), charge)) {
+ continue;
+ }
+ refreshGsLeftMoney(gs);
+ ywCustomerGsMapper.updateById(gs);
+ updateChargeStatus(charge.getId(), Constants.ONE, "鍏呭�兼垚鍔�", gs.getLeftMoney());
+ return "宸插悓姝ヤ负鍏呭�兼垚鍔�";
+ }
+ return "鏈尮閰嶅埌骞冲彴鍏呭�兼棩蹇楋紝浠嶄负鍏呭�间腑";
+ }
+
+ private boolean matchCzLog(JSONObject o, Integer gsId, YwElectricalCharge charge) {
+ Integer logGsId = o.getInteger("gs_id");
+ if (logGsId == null) {
+ logGsId = o.getInteger("id");
+ }
+ if (!Objects.equals(logGsId, gsId)) {
+ return false;
+ }
+ String money = o.getString("cz_money");
+ if (money == null) {
+ money = o.getString("money");
+ }
+ if (charge.getMoney() != null && money != null) {
+ try {
+ return charge.getMoney().compareTo(new BigDecimal(money)) == 0;
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ return true;
+ }
+
+ private void updateChargeStatus(Integer id, int status, String statusInfo, BigDecimal balanceAfter) {
+ UpdateWrapper<YwElectricalCharge> uw = new UpdateWrapper<>();
+ uw.lambda()
+ .set(YwElectricalCharge::getStatus, status)
+ .set(YwElectricalCharge::getStatusInfo, statusInfo)
+ .set(YwElectricalCharge::getStatusTime, new Date())
+ .set(YwElectricalCharge::getEditDate, new Date())
+ .eq(YwElectricalCharge::getId, id);
+ if (balanceAfter != null) {
+ uw.lambda().set(YwElectricalCharge::getBalanceAfter, balanceAfter);
+ }
+ ywElectricalChargeMapper.update(null, uw);
+ }
+
+ private YwElectricalCharge buildConditionerCharge(YwCustomerRechargeConditionerDTO dto, YwCustomerGs gs, LoginUserInfo user) {
+ YwCustomer customer = requireCustomer(dto.getCustomerId());
+ YwElectricalCharge charge = new YwElectricalCharge();
+ charge.setCreator(user.getId());
+ charge.setCreateDate(new Date());
+ charge.setEditor(user.getId());
+ charge.setEditDate(new Date());
+ charge.setIsdeleted(Constants.ZERO);
+ charge.setType(Constants.ONE);
+ charge.setCustomerId(dto.getCustomerId());
+ charge.setObjId(gs.getId());
+ charge.setName(customer.getName());
+ charge.setMoney(dto.getMoney());
+ charge.setRemark(dto.getRemark());
+ charge.setBanlance(gs.getLeftMoney());
+ charge.setStatus(Constants.ZERO);
+ charge.setStatusTime(new Date());
+ charge.setStatusInfo("鍏呭�间腑");
+ charge.setDeviceInfo("GS-" + gs.getPlatformGsId() + " " + customer.getName());
+ return charge;
+ }
+
+ private void fillRecordText(YwCustomerRechargeRecordVO vo) {
+ if (StringUtils.isBlank(vo.getDeviceInfo())) {
+ if (StringUtils.isNotBlank(vo.getAddress()) || StringUtils.isNotBlank(vo.getName())) {
+ vo.setDeviceInfo(StringUtils.defaultString(vo.getAddress()) + " " + StringUtils.defaultString(vo.getName()));
+ }
+ }
+ vo.setTypeText(Objects.equals(vo.getType(), Constants.ONE) ? "绌鸿皟" : "鐢佃〃");
+ if (Objects.equals(vo.getStatus(), Constants.ZERO)) {
+ vo.setStatusText("鍏呭�间腑");
+ } else if (Objects.equals(vo.getStatus(), Constants.ONE)) {
+ vo.setStatusText("鍏呭�兼垚鍔�");
+ } else if (Objects.equals(vo.getStatus(), Constants.TWO)) {
+ vo.setStatusText("鍏呭�煎け璐�");
+ }
+ }
+
+ private YwElectricalCharge requireCharge(Integer id) {
+ YwElectricalCharge charge = ywElectricalChargeMapper.selectById(id);
+ if (charge == null || Objects.equals(charge.getIsdeleted(), Constants.ONE) || charge.getCustomerId() == null) {
+ throw new BusinessException(ResponseStatus.DATA_EMPTY);
+ }
+ return charge;
+ }
+
+ private void refreshGsLeftMoney(YwCustomerGs gs) {
+ if (gs.getPlatformGsId() == null) {
+ return;
+ }
+ CompanyGsManageRequest req = new CompanyGsManageRequest();
+ req.fillSessionDefaults();
+ req.setId(gs.getPlatformGsId());
+ ConditionerBaseResponse<List<CompanyGsInfoResponse>> resp = ConditionerUtil.getGs(req);
+ if (resp == null || !resp.isSuccess() || CollectionUtils.isEmpty(resp.getData())) {
+ return;
+ }
+ CompanyGsInfoResponse info = resp.getData().stream()
+ .filter(i -> Objects.equals(i.getId(), gs.getPlatformGsId()))
+ .findFirst().orElse(resp.getData().get(0));
+ gs.setLeftMoney(toBigDecimal(info.getLeft_money()));
+ gs.setSyncDate(new Date());
+ }
+
+ private Integer parseAddGsId(Object data) {
+ if (data == null) {
+ return null;
+ }
+ if (data instanceof Number) {
+ return ((Number) data).intValue();
+ }
+ JSONObject obj = (JSONObject) JSON.toJSON(data);
+ if (obj.containsKey("id")) {
+ return obj.getInteger("id");
+ }
+ return null;
+ }
+
+ private BigDecimal toBigDecimal(Object val) {
+ if (val == null) {
+ return null;
+ }
+ if (val instanceof BigDecimal) {
+ return (BigDecimal) val;
+ }
+ if (val instanceof Number) {
+ return BigDecimal.valueOf(((Number) val).doubleValue());
+ }
+ try {
+ return new BigDecimal(String.valueOf(val));
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ private String apiMsg(ConditionerBaseResponse<?> resp, String def) {
+ return resp != null && StringUtils.isNotBlank(resp.getMessage()) ? resp.getMessage() : def;
+ }
+
+ private YwCustomer requireCustomer(Integer customerId) {
+ YwCustomer c = ywCustomerMapper.selectById(customerId);
+ if (c == null || Objects.equals(c.getIsdeleted(), Constants.ONE)) {
+ throw new BusinessException(ResponseStatus.DATA_EMPTY);
+ }
+ return c;
+ }
+
+ private YwCustomerGs requireGsConfig(Integer customerId) {
+ YwCustomerGs gs = getCustomerGsConfig(customerId);
+ if (gs == null || gs.getPlatformGsId() == null) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇峰厛閰嶇疆骞朵繚瀛樼┖璋冨叧鑱�");
+ }
+ return gs;
+ }
+
+ private void assertElectricalBound(Integer customerId, Integer electricalId) {
+ Long cnt = ywCustomerElectricalMapper.selectCount(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getCustomerId, customerId)
+ .eq(YwCustomerElectrical::getElectricalId, electricalId)
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO));
+ if (cnt == null || cnt == 0) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐢佃〃鏈叧鑱旇鍟嗘埛");
+ }
+ }
+
+ private List<Integer> listBoundElectricalIds(Integer customerId) {
+ return ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getCustomerId, customerId)
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO))
+ .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toList());
+ }
+
+ private Set<Integer> listAllBoundElectricalIds() {
+ return ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO))
+ .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet());
+ }
+
+ private Set<Integer> listAllBoundElectricalIdsExcept(Integer customerId) {
+ return ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
+ .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)
+ .ne(YwCustomerElectrical::getCustomerId, customerId))
+ .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet());
+ }
+
+ private List<YwElectrical> loadCustomerElectricalList(Integer customerId) {
+ List<Integer> ids = listBoundElectricalIds(customerId);
+ if (ids.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<YwElectrical> list = ywElectricalMapper.selectBatchIds(ids);
+ list = list.stream().filter(e -> !Objects.equals(e.getIsdeleted(), Constants.ONE)).collect(Collectors.toList());
+ ywElectricalBizService.enrichList(list);
+ return list;
+ }
+
+ private List<YwConditioner> loadCustomerConditionerList(Integer customerId) {
+ List<YwCustomerConditioner> rels = ywCustomerConditionerMapper.selectList(new QueryWrapper<YwCustomerConditioner>().lambda()
+ .eq(YwCustomerConditioner::getCustomerId, customerId)
+ .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO));
+ if (rels.isEmpty()) {
+ return Collections.emptyList();
+ }
+ Map<Integer, Integer> ratioMap = rels.stream()
+ .collect(Collectors.toMap(YwCustomerConditioner::getConditionerId, YwCustomerConditioner::getDevRatio, (a, b) -> a));
+ List<YwConditioner> list = ywConditionerMapper.selectBatchIds(ratioMap.keySet());
+ list = list.stream().filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE)).collect(Collectors.toList());
+ for (YwConditioner c : list) {
+ c.setDevRatio(ratioMap.get(c.getId()));
+ }
+ return list;
+ }
+
+ private PageData<YwElectrical> pageElectricalByIds(PageWrap<YwElectrical> pageWrap, List<Integer> ids) {
+ IPage<YwElectrical> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+ YwElectrical model = pageWrap.getModel();
+ QueryWrapper<YwElectrical> qw = new QueryWrapper<>();
+ qw.lambda()
+ .in(YwElectrical::getId, ids)
+ .eq(YwElectrical::getIsdeleted, Constants.ZERO)
+ .and(model != null && StringUtils.isNotBlank(model.getName()), w -> w
+ .like(YwElectrical::getName, model.getName())
+ .or().like(YwElectrical::getAddress, model.getName()))
+ .orderByDesc(YwElectrical::getCreateDate);
+ IPage<YwElectrical> result = ywElectricalMapper.selectPage(page, qw);
+ ywElectricalBizService.enrichList(result.getRecords());
+ return PageData.from(result);
+ }
+
+ private <T> PageData<T> emptyPage(PageWrap<?> pageWrap) {
+ PageData<T> data = new PageData<>();
+ data.setRecords(Collections.emptyList());
+ data.setTotal(0);
+ data.setPage(pageWrap.getPage());
+ data.setCapacity(pageWrap.getCapacity());
+ return data;
+ }
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalActionsServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalActionsServiceImpl.java
index 999a070..3eb58fd 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalActionsServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalActionsServiceImpl.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
@@ -10,9 +12,13 @@
import com.doumee.dao.business.model.YwElectrical;
import com.doumee.dao.business.model.YwElectricalActions;
import com.doumee.service.business.YwElectricalActionsService;
+import com.doumee.service.business.YwElectricalBizService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+
+import java.util.Objects;
/**
* 鐢佃〃杩滅▼鎿嶄綔璁板綍 Service 瀹炵幇
@@ -22,6 +28,8 @@
@Autowired
private YwElectricalActionsMapper ywElectricalActionsMapper;
+ @Autowired
+ private YwElectricalBizService ywElectricalBizService;
@Override
public PageData<YwElectricalActions> findPage(PageWrap<YwElectricalActions> pageWrap) {
@@ -50,4 +58,22 @@
IPage<YwElectricalActions> result = ywElectricalActionsMapper.selectJoinPage(page, YwElectricalActions.class, queryWrapper);
return PageData.from(result);
}
+
+ @Override
+ public String queryAsyncResult(Integer id) {
+ if (id == null) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST);
+ }
+ YwElectricalActions act = ywElectricalActionsMapper.selectById(id);
+ if (act == null || Objects.equals(act.getIsdeleted(), Constants.ONE)) {
+ throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "鎿嶄綔璁板綍涓嶅瓨鍦�");
+ }
+ if (!Objects.equals(act.getStatus(), Constants.ZERO)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呭鐞嗕腑璁板綍鍙煡璇�");
+ }
+ if (StringUtils.isBlank(act.getOprId())) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "缂哄皯浠诲姟 ID");
+ }
+ return ywElectricalBizService.syncAsyncActionStatus(act.getOprId().trim());
+ }
}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalBizServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalBizServiceImpl.java
index c873faf..c9911dd 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalBizServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalBizServiceImpl.java
@@ -12,6 +12,7 @@
import com.doumee.core.device.model.request.*;
import com.doumee.core.device.model.response.ElectronicBaseResponse;
import com.doumee.core.device.model.response.ElectronicDataResponse;
+import com.doumee.core.device.model.response.MeterDealResponse;
import com.doumee.core.device.model.response.QueryDataInfoResponse;
import com.doumee.core.device.model.response.QueryDataV2Response;
import com.doumee.core.exception.BusinessException;
@@ -51,6 +52,11 @@
public static final int ACTION_OPEN = 6;
public static final int ACTION_RECHARGE = 7;
public static final int ACTION_READ = 8;
+
+ private static final long FIRST_STATUS_QUERY_DELAY_MS = 30_000L;
+ private static final long STATUS_QUERY_MIN_INTERVAL_MS = 3_600_000L;
+ private static final int STATUS_QUERY_BATCH_SIZE = 50;
+ private static final int STATUS_QUERY_MAX_PENDING = 100;
/** ele_read 鎶勭數琛ㄦ暟鎹搷浣滅被鍨嬶紙涓� queryData functionids=253 涓嶅悓锛� */
private static final int ELE_READ_TYPE_METER = 3;
@@ -170,6 +176,7 @@
}
private String doSecurityReset(YwElectrical e, String paymentMode, int actionType, LoginUserInfo user) {
+ assertNoPendingAsyncAction(e.getId(), actionType);
String oprId = newOprId();
SecurityResetRequest req = new SecurityResetRequest();
req.setOpr_id(oprId);
@@ -188,6 +195,7 @@
}
private String doEleControl(YwElectrical e, int type, int actionType, LoginUserInfo user) {
+ assertNoPendingAsyncAction(e.getId(), actionType);
String oprId = newOprId();
EleControlApiRequest req = new EleControlApiRequest();
req.setOpr_id(oprId);
@@ -205,6 +213,7 @@
}
private String doOpenAccount(YwElectrical e, YwElectricalOperateDTO dto, LoginUserInfo user) {
+ assertNoPendingAsyncAction(e.getId(), ACTION_OPEN);
String oprId = newOprId();
OpenAccountRequest req = buildOpenAccountRequest(e, oprId, dto.getMoney(), dto.getRemark());
String reqJson = JSON.toJSONString(Collections.singletonList(req));
@@ -216,6 +225,7 @@
if (!Objects.equals(e.getAccountStatus(), Constants.ONE)) {
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐢佃〃鏈紑鎴凤紝璇峰厛寮�鎴�");
}
+ assertNoPendingAsyncAction(e.getId(), ACTION_RECHARGE);
String oprId = newOprId();
OpenAccountRequest req = buildOpenAccountRequest(e, oprId, dto.getMoney(), dto.getRemark());
String reqJson = JSON.toJSONString(Collections.singletonList(req));
@@ -228,6 +238,7 @@
}
private String doReadMeter(YwElectrical e, LoginUserInfo user) {
+ assertNoPendingAsyncAction(e.getId(), ACTION_READ);
String oprId = newOprId();
EleReadRequest req = new EleReadRequest();
req.setOpr_id(oprId);
@@ -244,7 +255,7 @@
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), msg);
}
boolean synced = syncMeterDataForElectrical(e);
- refreshBalanceFromData(e);
+ refreshBalanceFromData(e, null, true);
return synced ? "鎶勮〃鎴愬姛锛岀敤閲忎綑棰濆凡鏇存柊" : "鎶勮〃璇锋眰宸叉彁浜わ紝鏆傛棤鏂版妱琛ㄦ暟鎹紝璇风◢鍚庡埛鏂版煡鐪�";
}
@@ -288,6 +299,21 @@
}
ywElectricalActionsMapper.insert(act);
return isSuccess(resp) ? "鎻愪氦鎴愬姛锛岃绋嶅悗鍦ㄦ搷浣滆褰曟垨鍏呭�艰褰曚腑鏌ョ湅缁撴灉" : act.getResultMsg();
+ }
+
+ /** 鍚屼竴鐢佃〃銆佺浉鍚屾搷浣滅被鍨嬪瓨鍦ㄥ鐞嗕腑璁板綍鏃讹紝绂佹閲嶅鎻愪氦寮傛浠诲姟 */
+ private void assertNoPendingAsyncAction(Integer electricalId, int actionType) {
+ if (electricalId == null) {
+ return;
+ }
+ Long pending = ywElectricalActionsMapper.selectCount(new QueryWrapper<YwElectricalActions>().lambda()
+ .eq(YwElectricalActions::getElectricalId, electricalId)
+ .eq(YwElectricalActions::getActionType, actionType)
+ .eq(YwElectricalActions::getStatus, Constants.ZERO)
+ .eq(YwElectricalActions::getIsdeleted, Constants.ZERO));
+ if (pending != null && pending > 0) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "闇�瑕佺瓑寰呬笂涓�娆℃搷浣滅粨鏋滄墽琛岀粨鏉�");
+ }
}
private void saveLog(YwElectrical e, String apiName, String reqJson, ElectronicBaseResponse resp, LoginUserInfo user) {
@@ -336,26 +362,32 @@
}
private void applyNotifyItem(JSONObject item) {
- if (item == null) return;
- String oprId = item.getString("opr_id");
- if (StringUtils.isBlank(oprId)) return;
- YwElectricalActions act = ywElectricalActionsMapper.selectOne(new QueryWrapper<YwElectricalActions>().lambda()
- .eq(YwElectricalActions::getOprId, oprId)
- .eq(YwElectricalActions::getIsdeleted, Constants.ZERO)
- .orderByDesc(YwElectricalActions::getCreateDate)
- .last("limit 1"));
- if (act == null) {
- log.info("electricalNotify no action for opr_id={}", oprId);
+ if (item == null) {
return;
}
- ElectronicNotifyStatus ns = ElectronicNotifyStatus.fromCode(item.getString("status"));
+ String oprId = item.getString("opr_id");
+ String status = item.getString("status");
String errMsg = item.get("error_msg") != null ? String.valueOf(item.get("error_msg")) : null;
+ applyActionStatusItem(oprId, status, errMsg, item.toJSONString(), true);
+ }
+
+ private void applyActionStatusItem(String oprId, String platformStatus, String errMsg, String responseBody,
+ boolean fromNotify) {
+ if (StringUtils.isBlank(oprId)) {
+ return;
+ }
+ YwElectricalActions act = findActionByOprId(oprId);
+ if (act == null) {
+ log.info("electrical action not found for opr_id={}", oprId);
+ return;
+ }
+ ElectronicNotifyStatus ns = ElectronicNotifyStatus.fromCode(platformStatus);
String resultMsg = ns.getLabel() + (StringUtils.isNotBlank(errMsg) ? "锛�" + errMsg : "");
YwElectricalActions upd = new YwElectricalActions();
upd.setId(act.getId());
upd.setEditDate(new Date());
- upd.setResponseBody(item.toJSONString());
+ upd.setResponseBody(responseBody);
upd.setResultMsg(resultMsg);
if (ns.isTerminalSuccess()) {
upd.setStatus(Constants.ONE);
@@ -367,8 +399,12 @@
ywElectricalActionsMapper.updateById(upd);
YwElectrical e = ywElectricalMapper.selectById(act.getElectricalId());
- if (e == null) return;
- saveNotifyLog(e, item, ns);
+ if (e == null) {
+ return;
+ }
+ if (fromNotify) {
+ saveNotifyLog(e, JSON.parseObject(responseBody), ns);
+ }
if (ns.isTerminalSuccess()) {
applyNotifySideEffect(e, act.getActionType());
if (Objects.equals(act.getActionType(), ACTION_RECHARGE)) {
@@ -377,6 +413,183 @@
} else if (ns.isTerminalFail() && Objects.equals(act.getActionType(), ACTION_RECHARGE)) {
updateChargeByNotify(oprId, Constants.TWO, resultMsg);
}
+ }
+
+ private YwElectricalActions findActionByOprId(String oprId) {
+ return ywElectricalActionsMapper.selectOne(new QueryWrapper<YwElectricalActions>().lambda()
+ .eq(YwElectricalActions::getOprId, oprId)
+ .eq(YwElectricalActions::getIsdeleted, Constants.ZERO)
+ .orderByDesc(YwElectricalActions::getCreateDate)
+ .last("limit 1"));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String syncAsyncActionStatus(String oprId) {
+ if (StringUtils.isBlank(oprId)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "缂哄皯浠诲姟 ID");
+ }
+ String trimmed = oprId.trim();
+ if (findActionByOprId(trimmed) == null) {
+ throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "鏈壘鍒板搴旀搷浣滆褰�");
+ }
+ ElectronicBaseResponse resp = ElectronicToolUtil.requestStatus(trimmed);
+ return handleStatusQueryResponse(resp, trimmed);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public String syncChargeStatusById(Integer chargeId) {
+ if (chargeId == null) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST);
+ }
+ YwElectricalCharge charge = ywElectricalChargeMapper.selectById(chargeId);
+ if (charge == null || !Objects.equals(charge.getIsdeleted(), Constants.ZERO)) {
+ throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "鍏呭�艰褰曚笉瀛樺湪");
+ }
+ if (!Objects.equals(charge.getStatus(), Constants.ZERO)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呭厖鍊间腑璁板綍鍙悓姝�");
+ }
+ if (!Objects.equals(charge.getType(), Constants.ZERO)) {
+ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呯數琛ㄥ厖鍊艰褰曞彲鍚屾");
+ }
+ return syncAsyncActionStatus(charge.getOprId());
+ }
+
+ @Override
+ public void syncPendingAsyncActionsScheduled() {
+ try {
+ Date minCreateTime = new Date(System.currentTimeMillis() - FIRST_STATUS_QUERY_DELAY_MS);
+ List<YwElectricalActions> pending = ywElectricalActionsMapper.selectList(
+ new QueryWrapper<YwElectricalActions>().lambda()
+ .eq(YwElectricalActions::getStatus, Constants.ZERO)
+ .eq(YwElectricalActions::getIsdeleted, Constants.ZERO)
+ .isNotNull(YwElectricalActions::getOprId)
+ .le(YwElectricalActions::getCreateDate, minCreateTime)
+ .orderByAsc(YwElectricalActions::getCreateDate)
+ .last("limit " + STATUS_QUERY_MAX_PENDING));
+ if (CollectionUtils.isEmpty(pending)) {
+ return;
+ }
+ long nowMs = System.currentTimeMillis();
+ List<String> oprIds = pending.stream()
+ .filter(act -> shouldPollAction(act, nowMs))
+ .map(YwElectricalActions::getOprId)
+ .filter(StringUtils::isNotBlank)
+ .distinct()
+ .collect(Collectors.toList());
+ if (oprIds.isEmpty()) {
+ return;
+ }
+ int updated = 0;
+ for (int i = 0; i < oprIds.size(); i += STATUS_QUERY_BATCH_SIZE) {
+ List<String> batch = oprIds.subList(i, Math.min(i + STATUS_QUERY_BATCH_SIZE, oprIds.size()));
+ ElectronicBaseResponse resp = ElectronicToolUtil.requestStatusByOprIds(batch);
+ updated += applyStatusQueryBatch(resp);
+ }
+ log.info("syncPendingAsyncActionsScheduled queried={}, updated={}", oprIds.size(), updated);
+ } catch (Exception e) {
+ log.warn("syncPendingAsyncActionsScheduled failed", e);
+ }
+ }
+
+ private int applyStatusQueryBatch(ElectronicBaseResponse resp) {
+ if (resp == null || !"SUCCESS".equalsIgnoreCase(resp.getStatus())) {
+ return 0;
+ }
+ List<MeterDealResponse> items = extractMeterDealList(resp);
+ if (CollectionUtils.isEmpty(items)) {
+ return 0;
+ }
+ int updated = 0;
+ for (MeterDealResponse item : items) {
+ if (item == null || StringUtils.isBlank(item.getOpr_id())) {
+ continue;
+ }
+ YwElectricalActions before = findActionByOprId(item.getOpr_id());
+ if (before == null || !Objects.equals(before.getStatus(), Constants.ZERO)) {
+ continue;
+ }
+ applyActionStatusItem(item.getOpr_id(), item.getStatus(), item.getError_msg(),
+ JSON.toJSONString(item), false);
+ YwElectricalActions after = findActionByOprId(item.getOpr_id());
+ if (after != null && !Objects.equals(before.getStatus(), after.getStatus())) {
+ updated++;
+ }
+ }
+ return updated;
+ }
+
+ private String handleStatusQueryResponse(ElectronicBaseResponse resp, String oprId) {
+ if (resp == null) {
+ return "骞冲彴鏃犲搷搴旓紝璇风◢鍚庨噸璇�";
+ }
+ if (!"SUCCESS".equalsIgnoreCase(resp.getStatus())) {
+ return "鏌ヨ澶辫触锛�" + StringUtils.defaultIfBlank(resp.getError_msg(), resp.getStatus());
+ }
+ List<MeterDealResponse> items = extractMeterDealList(resp);
+ MeterDealResponse item = items.stream()
+ .filter(i -> i != null && oprId.equals(i.getOpr_id()))
+ .findFirst()
+ .orElse(CollectionUtils.isEmpty(items) ? null : items.get(0));
+ if (item == null) {
+ return "鏈煡璇㈠埌浠诲姟缁撴灉锛岃绋嶅悗閲嶈瘯";
+ }
+ applyActionStatusItem(oprId, item.getStatus(), item.getError_msg(), JSON.toJSONString(item), false);
+
+ YwElectricalActions act = findActionByOprId(oprId);
+ if (act == null) {
+ return "鏈壘鍒板搴旀搷浣滆褰�";
+ }
+ if (Objects.equals(act.getStatus(), Constants.ONE)) {
+ return Objects.equals(act.getActionType(), ACTION_RECHARGE) ? "宸插悓姝ヤ负鍏呭�兼垚鍔�" : "鎿嶄綔宸叉垚鍔�";
+ }
+ if (Objects.equals(act.getStatus(), Constants.TWO)) {
+ return Objects.equals(act.getActionType(), ACTION_RECHARGE)
+ ? "宸插悓姝ヤ负鍏呭�煎け璐ワ細" + StringUtils.defaultString(act.getResultMsg())
+ : "鎿嶄綔宸插け璐ワ細" + StringUtils.defaultString(act.getResultMsg());
+ }
+ if (ElectronicToolUtil.isAsyncStatusFinal(item.getStatus())) {
+ return "骞冲彴鐘舵�侊細" + item.getStatus();
+ }
+ return "浠诲姟澶勭悊涓紝璇风◢鍚庨噸璇�";
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<MeterDealResponse> extractMeterDealList(ElectronicBaseResponse resp) {
+ Object content = resp.getResponse_content();
+ if (content == null) {
+ return Collections.emptyList();
+ }
+ if (content instanceof List) {
+ List<?> list = (List<?>) content;
+ List<MeterDealResponse> result = new ArrayList<>();
+ for (Object o : list) {
+ if (o instanceof MeterDealResponse) {
+ result.add((MeterDealResponse) o);
+ } else {
+ result.add(JSON.parseObject(JSON.toJSONString(o), MeterDealResponse.class));
+ }
+ }
+ return result;
+ }
+ return JSON.parseArray(JSON.toJSONString(content), MeterDealResponse.class);
+ }
+
+ private boolean shouldPollAction(YwElectricalActions act, long nowMs) {
+ Date create = act.getCreateDate();
+ if (create == null || StringUtils.isBlank(act.getOprId())) {
+ return false;
+ }
+ long createMs = create.getTime();
+ if (nowMs - createMs < FIRST_STATUS_QUERY_DELAY_MS) {
+ return false;
+ }
+ long editMs = act.getEditDate() != null ? act.getEditDate().getTime() : createMs;
+ if (editMs - createMs < 5_000L) {
+ return true;
+ }
+ return nowMs - editMs >= STATUS_QUERY_MIN_INTERVAL_MS;
}
private void saveChargeRecord(YwElectrical e, String oprId, YwElectricalOperateDTO dto, LoginUserInfo user) {
@@ -400,6 +613,12 @@
charge.setStatusInfo("鍏呭�间腑");
charge.setBanlance(e.getBalance());
charge.setRoomNames(e.getRoomNames());
+ if (dto.getCustomerId() != null) {
+ charge.setCustomerId(dto.getCustomerId());
+ }
+ if (StringUtils.isNotBlank(e.getAddress()) || StringUtils.isNotBlank(e.getName())) {
+ charge.setDeviceInfo(StringUtils.defaultString(e.getAddress()) + " " + StringUtils.defaultString(e.getName()));
+ }
if (StringUtils.isNotBlank(e.getParamId())) {
try {
charge.setParamId(Integer.parseInt(e.getParamId()));
@@ -410,13 +629,29 @@
}
private void updateChargeByNotify(String oprId, int status, String statusInfo) {
- ywElectricalChargeMapper.update(null, new UpdateWrapper<YwElectricalCharge>().lambda()
+ YwElectricalCharge charge = ywElectricalChargeMapper.selectOne(new QueryWrapper<YwElectricalCharge>().lambda()
+ .eq(YwElectricalCharge::getOprId, oprId)
+ .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO)
+ .last("limit 1"));
+ BigDecimal balanceAfter = null;
+ if (charge != null && status == Constants.ONE) {
+ balanceAfter = calcBalanceAfterRecharge(charge);
+ if (charge.getObjId() != null) {
+ updateElectricalBalance(charge.getObjId(), balanceAfter);
+ }
+ }
+ UpdateWrapper<YwElectricalCharge> uw = new UpdateWrapper<>();
+ uw.lambda()
.set(YwElectricalCharge::getStatus, status)
.set(YwElectricalCharge::getStatusTime, new Date())
.set(YwElectricalCharge::getStatusInfo, statusInfo)
.set(YwElectricalCharge::getEditDate, new Date())
.eq(YwElectricalCharge::getOprId, oprId)
- .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO));
+ .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO);
+ if (balanceAfter != null) {
+ uw.lambda().set(YwElectricalCharge::getBalanceAfter, balanceAfter);
+ }
+ ywElectricalChargeMapper.update(null, uw);
}
private void saveNotifyLog(YwElectrical e, JSONObject item, ElectronicNotifyStatus ns) {
@@ -454,34 +689,128 @@
ywElectricalMapper.update(null, uw);
break;
case ACTION_RECHARGE:
+ // 鍏呭�兼垚鍔熷悗浣欓鐢� updateChargeByNotify 鎸夈�屽厖鍊煎墠+鍏呭�奸噾棰濄�嶇疮璁★紝寰呭畾鏃舵妱琛ㄥ悗鍐嶅垏鍥炴妱琛ㄤ綑棰�
+ break;
case ACTION_READ:
syncMeterDataForElectrical(e);
- refreshBalanceFromData(e);
+ refreshBalanceFromData(e, null, true);
break;
default:
break;
}
}
+ /** 鍏呭�煎悗绱浣欓 = 鍏呭�煎墠浣欓 + 鍏呭�奸噾棰� */
+ private BigDecimal calcBalanceAfterRecharge(YwElectricalCharge charge) {
+ BigDecimal before = charge.getBanlance() != null ? charge.getBanlance() : BigDecimal.ZERO;
+ BigDecimal money = charge.getMoney() != null ? charge.getMoney() : BigDecimal.ZERO;
+ return before.add(money);
+ }
+
+ private void updateElectricalBalance(Integer electricalId, BigDecimal balance) {
+ if (electricalId == null || balance == null) {
+ return;
+ }
+ UpdateWrapper<YwElectrical> uw = new UpdateWrapper<>();
+ uw.lambda()
+ .eq(YwElectrical::getId, electricalId)
+ .set(YwElectrical::getBalance, balance)
+ .set(YwElectrical::getBalanceTime, new Date())
+ .set(YwElectrical::getEditDate, new Date());
+ ywElectricalMapper.update(null, uw);
+ }
+
+ private YwElectricalCharge findLastSuccessfulRecharge(Integer electricalId) {
+ if (electricalId == null) {
+ return null;
+ }
+ return ywElectricalChargeMapper.selectOne(new QueryWrapper<YwElectricalCharge>().lambda()
+ .eq(YwElectricalCharge::getObjId, electricalId)
+ .eq(YwElectricalCharge::getType, Constants.ZERO)
+ .eq(YwElectricalCharge::getStatus, Constants.ONE)
+ .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO)
+ .orderByDesc(YwElectricalCharge::getStatusTime)
+ .orderByDesc(YwElectricalCharge::getId)
+ .last("limit 1"));
+ }
+
+ private Date parseDataTime(YwElectricalData data) {
+ if (data == null) {
+ return null;
+ }
+ if (StringUtils.isNotBlank(data.getAddTime())) {
+ try {
+ return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(data.getAddTime().trim());
+ } catch (Exception ignored) {
+ }
+ }
+ return data.getCreateDate();
+ }
+
+ /**
+ * 鏈�杩戜竴娆″厖鍊兼垚鍔熷悗锛岃嫢鎶勮〃鏃堕棿浠嶆棭浜庡厖鍊兼垚鍔熸椂闂达紝鍒欐殏涓嶄互鎶勮〃浣欓瑕嗙洊绱浣欓銆�
+ */
+ private boolean shouldUseMeterBalance(Integer electricalId, YwElectricalData data) {
+ YwElectricalCharge lastRecharge = findLastSuccessfulRecharge(electricalId);
+ if (lastRecharge == null || lastRecharge.getStatusTime() == null) {
+ return true;
+ }
+ Date dataTime = parseDataTime(data);
+ if (dataTime == null) {
+ return true;
+ }
+ return !dataTime.before(lastRecharge.getStatusTime());
+ }
+
private void refreshBalanceFromData(YwElectrical e) {
- YwElectricalData data = findLatestData(e.getId(), e.getAddress());
- if (data == null) return;
+ refreshBalanceFromData(e, null, false);
+ }
+
+ private void refreshBalanceFromData(YwElectrical e, YwElectricalData data, boolean forceFromMeter) {
+ if (e == null) {
+ return;
+ }
+ if (data == null) {
+ data = findLatestData(e.getId(), e.getAddress());
+ }
+ if (data == null) {
+ return;
+ }
UpdateWrapper<YwElectrical> uw = new UpdateWrapper<>();
uw.lambda().eq(YwElectrical::getId, e.getId());
if (StringUtils.isNotBlank(data.getZhygzdl())) {
uw.lambda().set(YwElectrical::getBalanceBattery, data.getZhygzdl());
}
- if (StringUtils.isNotBlank(data.getYe())) {
+ boolean useMeterBalance = forceFromMeter || shouldUseMeterBalance(e.getId(), data);
+ if (useMeterBalance && StringUtils.isNotBlank(data.getYe())) {
try {
uw.lambda().set(YwElectrical::getBalance, new BigDecimal(data.getYe()));
} catch (Exception ignored) {
}
}
- uw.lambda().set(YwElectrical::getBalanceTime, new Date());
+ if (isPurchaseCountPositive(data.getCountnum())) {
+ uw.lambda().set(YwElectrical::getAccountStatus, Constants.ONE);
+ }
+ if (useMeterBalance) {
+ Date dataTime = parseDataTime(data);
+ uw.lambda().set(YwElectrical::getBalanceTime, dataTime != null ? dataTime : new Date());
+ }
uw.lambda().set(YwElectrical::getEditDate, new Date());
ywElectricalMapper.update(null, uw);
}
+ /** 璐拱娆℃暟澶т簬 0 瑙嗕负宸插紑鎴� */
+ private static boolean isPurchaseCountPositive(String purchaseCount) {
+ if (StringUtils.isBlank(purchaseCount)) {
+ return false;
+ }
+ try {
+ return new BigDecimal(purchaseCount.trim()).compareTo(BigDecimal.ZERO) > 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
private YwElectricalData findLatestData(Integer electricalId, String address) {
QueryWrapper<YwElectricalData> q = new QueryWrapper<>();
q.lambda().eq(YwElectricalData::getIsdeleted, Constants.ZERO)
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalServiceImpl.java
index 911f9ce..da8d93c 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwElectricalServiceImpl.java
@@ -37,6 +37,7 @@
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.doumee.core.model.LoginUserInfo;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -360,7 +361,6 @@
model.setName(door.getDescription());
model.setCId(door.getCid());
model.setDId(door.getId());
- model.setAccountStatus(Constants.TWO);
model.setPriceid(door.getPriceid());
model.setParamId(door.getParam_id());
model.setDeviceType(door.getDevice_type());
@@ -370,9 +370,23 @@
model.setType(door.getType());
model.setRelayStatus(door.getRelay_state());
model.setCsq(door.getCsq());
+ model.setAccountStatus(resolveAccountStatusByPurchaseCount(door.getCount()));
model.setRemark(JSONObject.toJSONString(device));
return model;
}
+
+ /** 璐拱娆℃暟澶т簬 0 瑙嗕负宸插紑鎴� */
+ private Integer resolveAccountStatusByPurchaseCount(String purchaseCount) {
+ if (StringUtils.isBlank(purchaseCount)) {
+ return Constants.ZERO;
+ }
+ try {
+ return new BigDecimal(purchaseCount.trim()).compareTo(BigDecimal.ZERO) > 0
+ ? Constants.ONE : Constants.ZERO;
+ } catch (NumberFormatException e) {
+ return Constants.ZERO;
+ }
+ }
private MeterInfoResponse getDeviceByid(String indexCode, List<MeterInfoResponse> allHkList ) {
if(allHkList!=null && allHkList.size()>0){
for(MeterInfoResponse info : allHkList){
--
Gitblit v1.9.3