稽核脚本1022
// ==UserScript==
// @name 稽核脚本1022
// @version 3.2.6
// @description 该脚本辅助三费系统进行稽核异常操作
// @match http://10.217.240.219:8090/NCMS/welcome
// @require http://192.168.100.150:31628/sevenfeeProvince/pluginCDN/vue.js
// @require http://192.168.100.150:31628/sevenfeeProvince/pluginCDN/eleJs.js
// @require http://192.168.100.150:31628/sevenfeeProvince/pluginCDN/qs.js
// @require http://192.168.100.150:31628/sevenfeeProvince/pluginCDN/jsencrypt.js
// @grant GM_xmlhttpRequest
// @connect 192.168.100.150
// ==/UserScript==
;(function () {
'use strict'
console.log('稽核脚本执行')
const linkElem = document.createElement('link')
linkElem.rel = 'stylesheet'
linkElem.href = 'http://192.168.100.150:31628/sevenfeeProvince/pluginCDN/eleCss.css'
document.head.appendChild(linkElem)
// html骨架
const html = `
<div id="TMapp">
<el-card v-if="viewShow" class="TMbox-card">
<div slot="header" class="clearfix">
<span style="font-weight: bold;">稽核插件</span>
<el-button @click="startAudit(true)" style="float: right;" type="primary" size="mini">
检测稽核异常
</el-button>
<el-button @click="logOut" size="mini">退出插件</el-button>
<el-button @click="toggleView" size="mini">最小化</el-button>
</div>
<!-- 插件内容 -->
<div>
<!-- 查询界面 -->
<div v-if="isSearchPageShow">
<div v-if="isAbnormalNewsShow">
<el-card shadow="always" :body-style="{ padding: '10px' }">
<div slot="header">
<span>异常提示</span>
</div>
<el-table :data="tableData" @selection-change="selectionChange" border stripe style="width: 100%; height:100% ">
<el-table-column v-if="isAuditpage" type="selection" width="40"></el-table-column>
<el-table-column v-for="col in tableHeads" :formatter="col.formatter" :prop="col.prop" :key="col.label" :label="col.label" width="110"></el-table-column>
</el-table>
</el-card>
</div>
</div>
<!-- 审核界面 -->
<div v-if="isAuditpage">
<div v-if="isAuditButtonAndTextareaShow" style="margin: 0 0 5px 0;">
<div style="margin: 5px 0 5px 0;">关闭异常的原因:</div> <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="abnormalTextarea"></el-input>
</div>
<div v-if="isAuditButtonAndTextareaShow">
<el-button type="primary" size="mini" :disabled="!loginState" @click="closeAbnormal">关闭异常</el-button>
<el-button v-if="!loginState" size="mini" @click="isLoginShow = true; isAuditButtonAndTextareaShow = false">打开登录</el-button>
<span style="float: right;"> 登录状态: <span style="font-weight: bold;">{{ loginState ? '已登录':'未登录' }}</span></span>
</div>
<div v-if="isLoginShow" style="margin: 5px 0 0 0;">
<el-form ref="form" :model="loginForm" label-width="60px">
<el-form-item label="用户名">
<el-input v-model="loginForm.username"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" show-password v-model="loginForm.password"></el-input>
</el-form-item>
<el-button type="primary" size="mini" @click="login">登录</el-button>
<el-button size="mini" @click="isLoginShow = false; isAuditButtonAndTextareaShow = true">取消登录</el-button>
</el-form>
</div>
</div>
</div>
</el-card>
<div v-else>
<el-button type="text" @click="toggleView">稽核插件</el-button>
</div>
</div>
`
// 创建容器元素 + 将容器添加到页面的 body 元素中
const containerEl = document.createElement('div')
containerEl.className = 'TMContainer'
containerEl.setAttribute('id', 'TMContainer')
document.body.appendChild(containerEl)
containerEl.innerHTML = html
// ============== 插件拖拽 ===============
containerEl.onmousedown = function (event) {
containerEl.style.cursor = 'move'
// 获取元素的初始位置
let startX = containerEl.offsetLeft
let startY = containerEl.offsetTop
// 获取鼠标按下的位置
const mouseX = event.pageX
const mouseY = event.pageY
// 监听鼠标移动 事件
window.onmousemove = function (event) {
// 计算鼠标移动距离
let disX = event.pageX - mouseX
let disY = event.pageY - mouseY
containerEl.style.left = startX + disX + 'px'
containerEl.style.top = startY + disY + 'px'
}
// 监听鼠标 松开
containerEl.onmouseup = function () {
// 移除鼠标移动事件
window.onmousemove = null
containerEl.style.cursor = ''
}
}
/*
业务类别(0:电费、1:租费、2:铁塔 )
缴费类型 1 报账点 2 缴费单
*/
let feeType_G = 0
let paymentType_G = 1
let nowPageName_G = '' // 当前激活的 nav 的名字
let collectEncodeType_G = '' // 查询时 需要收集页面上的编码, 一般为 报账点编码/缴费单编码 但是租费不一样需要特殊处理
let currentPageNum_G = 1 // 当前的分页器所在的页数
let activeNavIndex_G = 0 // 当前ifream在第几页, "首页"从1开始
let abnormalTableIndexList_G = [] // 存储: 账单异常的表格行的下标, 从0开始
let checkTableIndexList_G = []
let isLatestVersion_G = false // 检测当前插件是否是最新版本
// 属性 type = 0: 查询界面 , 1: 审核界面
// encodeType : 需要收集table中的参数
let matchNavList_G = [
{ type: 0, navName: '电费报账点查询', feeType: 0, paymentType: 1, encodeType: '报账点编码' },
{ type: 0, navName: '报账点电费查询', feeType: 0, paymentType: 2, encodeType: '缴费单编码' },
{
type: 0,
navName: '租费报账点信息查询',
feeType: 1,
paymentType: 1,
encodeType: '报账点编码',
},
{ type: 0, navName: '报账点租费查询', feeType: 1, paymentType: 2, encodeType: '缴费单编码' },
{ type: 0, navName: '费用汇总', feeType: 2, paymentType: 5, encodeType: '汇总单号' },
{
type: 0,
navName: '批量起租表',
feeType: 2,
paymentType: 2,
encodeType: ['站址编码', '业务确认单号', '需求单号', '起租表账期'],
},
{ type: 1, navName: '报账点电费审核', feeType: 0, paymentType: 2, encodeType: '缴费单编码' },
{ type: 1, navName: '报账点租费审核', feeType: 0, paymentType: 1, encodeType: '报账点编码' },
{ type: 1, navName: '费用审核', feeType: 2, paymentType: 5, encodeType: '汇总单号' },
]
// 插件接口汇总
const baseURL_G = 'http://192.168.100.150:31628'
const urlList_G = [
{ name: '登录插件', type: 0, url: '/uaa/authentication/jwt' },
{ name: '退出插件', type: 1, url: '/uaa/logout' },
{ name: '手动关闭异常', type: 2, url: '/cpa/pluginUpdate/updateAuditState' },
{ name: '查询异常详细', type: 3, url: '/cpa/plugin/queryAuditErrorList' },
{ name: '批量查询是否异常', type: 4, url: '/cpa/plugin/queryPaymentState' },
{ name: '获取登录加密密钥', type: 5, url: '/uaa/config' },
]
// 用户信息
const userInfoObj_G = {
oldFeeSystemName: '',
browserName: '',
plugVersion: 'V3.2.6',
}
/**
* 检测当前插件版本是否是最新
*/
async function checkVersion() {
const versionId = userInfoObj_G.plugVersion
const QS = Qs
GM_xmlhttpRequest({
url: `${baseURL_G}/cpa/plugin/checkCatVersion`,
method: 'post',
anonymous: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
data: QS.stringify({ versionId }),
onload: (res) => {
console.log('res==>', JSON.parse(res.response))
const { isUpdate, url } = JSON.parse(res.response).data
if (isUpdate) {
isLatestVersion_G = false
window.open(url) // 打开更新的链接
ELEMENT.Message.warning('当前插件版本不是最新版本,请更新或者 刷新浏览器')
} else {
isLatestVersion_G = true
console.log('当前版本是最新')
}
},
onerror: (e) => reject(e),
})
}
checkVersion()
/**
* 获取当前客户端信息
*/
function getUserInfo() {
// 获取当前账户名
userInfoObj_G.oldFeeSystemName = document.querySelector(
'.layout-header .header-bar #userName'
).textContent
// 获取当前浏览器信息( 浏览器版本/名称 ), 由后台解析。
userInfoObj_G.browserName = navigator.userAgent
}
getUserInfo()
/**
* 获取当前的 业务类别 和 缴费类型 , 以及当前页面
*/
function setFeeTypeAndPayMentType() {
const aEls = document.querySelectorAll('.layout-main-tab .tab-nav .tab-nav-content a')
const activeAElements = Array.from(aEls).find((aEl) => {
return aEl.classList.contains('active')
})
const nowNavName = activeAElements.textContent.replace(/[^\u4e00-\u9fa5]/gi, '')
//console.log('nowNavName==>', nowNavName);
// 请求前匹配 参数使用的 业务类别:feeType_G 和 缴费类型:paymentType_G
let temp = false
matchNavList_G.forEach((item) => {
if (item.navName === nowNavName) {
temp = true
feeType_G = item.feeType
paymentType_G = item.paymentType
collectEncodeType_G = item.encodeType
nowPageName_G = item.navName
}
})
// 当temp为false时, 则说明未匹配到稽核页面, 执行下面, 获取当前所在页
if (!temp) {
nowPageName_G = nowNavName
}
}
/**
* 封装请求函数
*/
function A_X(url, data) {
setFeeTypeAndPayMentType()
// 确定操作类型
const operationType = urlList_G.find((item) => item.url === url)?.type
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
if (operationType === 3 || operationType === 4) {
headers['Content-Type'] = 'application/json'
} else if (operationType === 0 || operationType === 5) {
headers['X-Requested-With'] = 'XMLHttpRequest'
}
// 后台人员要求: 每一次请求前都要请求一下日志接口
async function setLog() {
let setLogURL = '/cpa/plugin/setLog'
// 收集关闭异常单据的参数: 异常数据编码, 关闭的异常编码, 关闭原因
let documentsCode = ''
let documentsCodeClosed = ''
let closeReason = ''
// 当前操作类型调用的日志接口 需要携带token
if (operationType === 0 || operationType === 1 || operationType === 2) {
setLogURL = '/cpa/pluginUpdate/setLog'
}
// 手动关闭异常
if (operationType === 2) {
const auditToken = localStorage.getItem('auditToken')
headers['Authorization'] = `${auditToken}`
const QS = Qs
const updateAuditParams = QS.parse(data)
console.log('updateAuditParams==>', updateAuditParams)
documentsCode = updateAuditParams.documentsCode
documentsCodeClosed = updateAuditParams.id
closeReason = updateAuditParams.describe
}
// 查询异常详细
if (operationType === 3) {
documentsCode = JSON.parse(data).paymentCode
}
const setLogParams = {
...userInfoObj_G,
logType: operationType,
documentsCode,
documentsCodeClosed,
closeReason,
}
await GM_xmlhttpRequest({
url: `${baseURL_G}${setLogURL}`,
method: 'post',
anonymous: true,
headers: {
'Content-Type': 'application/json',
Authorization: `${localStorage.getItem('auditToken')}`,
},
data: JSON.stringify(setLogParams),
})
}
setLog()
console.log('headers==>', headers)
console.log('url==>', url)
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: `${baseURL_G}${url}`,
method: 'post',
data,
headers,
anonymous: true,
onload: (res) => {
console.log('res==>', res)
if (res.status === 200) {
if (operationType === 0) {
console.log('url==>', url)
// 使用正则表达式匹配
const tokenRegex = /authorization:\s*(.*)/
const match = res.responseHeaders.match(tokenRegex)
const token = match ? match[1] : null
localStorage.setItem('auditToken', token)
// 登录之后得到token, 再次调用一下日志接口.
setLog()
return resolve(res)
}
return resolve(JSON.parse(res.response))
} else if (res.status === 302) {
ELEMENT.Message.error('登录信息过期')
return resolve(res.status)
} else {
if (!res.finalUrl.includes('logout')) {
ELEMENT.Message.error(JSON.parse(res.responseText).msg)
resolve(res.status)
}
// 退出接口, 删除token
localStorage.removeItem('auditToken')
}
},
onerror: (e) => reject(e),
})
})
}
var TMApp = new Vue({
el: '#TMapp',
data() {
return {
loginForm: {
username: 'admin',
password: '1qaz2WSX3edc',
},
tableHeads: [
// { label: '异常编码', prop: 'account' },
{ label: '稽核规则名称', prop: 'auditRuleCn' },
{ label: '异常产生时间', prop: 'lastModifyTime' }, // 后台加 最后更新时间
{ label: '异常描述', prop: 'actualValue' },
{
label: '是否强制稽核',
prop: 'isMandatoryAudit',
formatter: (row) => ['否', '是'][row.isMandatoryAudit],
},
{ label: '责任人', prop: 'responsible' },
{ label: '异常状态', prop: 'isDelete' },
],
stateList: [],
tableData: [],
// 收集审核界面 和 查询界面的 nameList, 用于后续判断
queryPageNameList: matchNavList_G
.filter(({ type }) => type === 0)
.map(({ navName }) => navName),
auditPageNameList: matchNavList_G
.filter(({ type }) => type === 1)
.map(({ navName }) => navName),
abnormalCode: '', // 点击查看具有异常的单号
checkedParams: { state: 0 }, // 消除异常参数 1关闭异常, 0不关闭
abnormalTextarea: '',
isLoginShow: false, // 登录界面是否展示
loginState: false, // 是否已经登录
isSearchPageShow: true, // 插件界面功能区切换
isAuditpage: false, // 当前是否是审核界面
isAbnormalNewsShow: false, // 异常提示的表格是否显示
isAuditButtonAndTextareaShow: false,
publicKey: '', // 登录加密公钥
jsEncrypt: '', // 加密
viewShow: true, // 界面的总开关
isDisAbledSaveBtn: null, // 是否禁用审核二级界面的保存按钮,
monitorLoadingList: [], // 存储监听的loading的 observe 对象
}
},
created() {
this.monitorTabNav()
},
methods: {
/**
* 判断稽核状态
*/
async startAudit(first) {
// 判断当前插件是否登录
this.loginState = localStorage.getItem('auditToken') ? true : false
// 确实使用的是最新版本
if (!isLatestVersion_G) {
this.$message({ message: '请升级到最新版本', type: 'warning' })
return
}
// 判断当前被激活的导航index
activeNavIndex_G = this.findActiveTabIndex()
// 在发出查询状态的接口前, 需要判断当前要收集的数据
setFeeTypeAndPayMentType()
// 稽核之前要判断当前是否是 可以稽核的界面
const navNameList = matchNavList_G.map((item) => item.navName)
if (!navNameList.includes(nowPageName_G)) {
this.$message({
message: '当前不是可以稽核的界面',
type: 'warning',
})
return
}
// 获取当前所在页数
currentPageNum_G = this.getcurrentPageNum()
// 当处于审核界面时, 开启checkbox 的监听
if (this.auditPageNameList.includes(nowPageName_G)) {
this.monitorCheckboxClick()
}
// 当前已经存在'异常状态' 这个表头, 则清除重新生成
if (this.isHasAbnormalStateHeader()) {
console.log('当前存在异常状态表头, 清除重新生成')
this.clearTableHeader('异常状态')
}
// 开启监听 "loading", 当处于查询界面 , 换页/查询后 自动进行稽核
if (first && this.queryPageNameList.includes(nowPageName_G)) {
if (!this.monitorLoadingList[activeNavIndex_G]) {
// 使用list+当前激活的nav 的下标来区分当前界面是否存在 observe
this.monitorLoadingList[activeNavIndex_G] = this.monitorLoading()
}
}
// 审核界面是否可以通过 审核
if (this.auditPageNameList.includes(nowPageName_G)) {
console.log('当前是可以审核的界面')
this.monitorAuditSelect()
} else {
console.log('当前不是可以审核的界面')
}
let encodeList = []
// 如果是服务费则要传递的参数
if (feeType_G === 2 && paymentType_G === 2) {
const addressEncodeList = this.getEncodeList('站址编码')
const businessOddList = this.getEncodeList('业务确认单号')
const needOddList = this.getEncodeList('需求单号')
const startTimeList = this.getEncodeList('起租表账期')
const ListLength = startTimeList.length
for (let i = 0; i < ListLength; i++) {
const temp =
addressEncodeList[i] +
'_' +
businessOddList[i] +
'_' +
needOddList[i] +
'_' +
startTimeList[i]
encodeList.push(temp)
}
//console.log('encodeList==>', encodeList)
} else {
//console.log('collectEncodeType_G==>', collectEncodeType_G)
encodeList = this.getEncodeList(collectEncodeType_G)
//console.log('encodeList==>', encodeList)
}
if (!encodeList?.length) {
this.$message.warning('当前界面不存在数据')
return
}
const params = {
businessCategory: feeType_G,
paymentCode: 'string',
paymentCodeList: encodeList,
paymentType: paymentType_G,
}
// console.log('params==>', params)
const res = await A_X('/cpa/plugin/queryPaymentState', JSON.stringify(params))
console.log('res==>', res)
// res.data.list[0].state = '异常'
this.stateList = res.data.list
abnormalTableIndexList_G = []
checkTableIndexList_G = []
// 重新检测稽核异常后, 关闭清空表格数据并关闭异常的展示
this.tableData = []
this.isAbnormalNewsShow = false
this.isAuditButtonAndTextareaShow = false
this.isAuditpage = false
// 收集当前异常列表中的的 index
res.data.list.forEach((item, index) => {
if (item.state !== '正常') {
abnormalTableIndexList_G.push(index)
}
})
//console.log('abnormalTableIndexList_G==>', abnormalTableIndexList_G)
// 将稽核状态插入表格中, 此时 active 在第几个 a 标签上, 就选中第几个 ifream
const thead_tr_Els = window.frames[activeNavIndex_G].document.querySelectorAll(
'.fixed-table-body #tb thead tr'
)
const tbody_tr_Els = window.frames[activeNavIndex_G].document.querySelectorAll(
'.fixed-table-body #tb tbody tr'
)
// 当前已经存在'异常状态' 这个表头, 则清除重新生成
if (this.isHasAbnormalStateHeader()) {
console.log('当前存在异常状态表头, 清除重新生成')
this.clearTableHeader('异常状态')
}
thead_tr_Els.forEach((trElement) => {
const thEl = document.createElement('th')
thEl.textContent = '异常状态' // 设置表头
const towChildElement = trElement.children[1]
trElement.insertBefore(thEl, towChildElement)
})
// 根据返回的状态, 去渲染异常的按钮
tbody_tr_Els.forEach((trElement, index) => {
const tdEl = document.createElement('td')
if (this.stateList[index].state === '正常') {
const spanElement = document.createElement('span')
spanElement.textContent = '稽核正常'
tdEl.appendChild(spanElement)
} else if (this.stateList[index].state === '暂未同步') {
const spanElement = document.createElement('span')
spanElement.textContent = '暂未同步'
tdEl.appendChild(spanElement)
} else {
const buttonElement = document.createElement('button')
buttonElement.addEventListener('click', this.handleAbnormal)
buttonElement.textContent = '稽核异常'
tdEl.appendChild(buttonElement)
}
const towChildElement = trElement.children[1]
trElement.insertBefore(tdEl, towChildElement)
})
},
/**
* 点击: 查看异常, 请求接口传递编码 id , 打开异常提示界面
*/
async handleAbnormal(event) {
// 判断当前插件是否登录
this.loginState = localStorage.getItem('auditToken') ? true : false
// 每次点击按钮之前 都要调用一下这两个函数, 防止页面数据出乱
setFeeTypeAndPayMentType()
activeNavIndex_G = this.findActiveTabIndex()
// 如果是审核界面, 则显示勾选框
if (['报账点电费审核', '报账点租费审核', '费用审核'].includes(nowPageName_G)) {
this.isAuditpage = true
} else {
this.isAuditpage = false
}
this.isLoginShow = false
const td = event.target.parentElement
const tr = td.parentElement
const cells = tr.getElementsByTagName('td') // 获取当前行中的所有单元格(td)
// 获取当前 collectEncodeType_G 所在的下标, 服务费的情况为数组
const nowRowEncodeIndex = this.getNowRowEncodeIndex()
// 点击处理异常, 获取当前的编码 collectEncodeType_G , 发起请求
let encodeParams = []
if (Array.isArray(nowRowEncodeIndex)) {
nowRowEncodeIndex.forEach((item) => {
encodeParams.push(cells[item].textContent)
})
encodeParams = encodeParams.join('_')
} else {
encodeParams = cells[nowRowEncodeIndex].textContent
}
console.log('处理异常的编码encodeParams==>', encodeParams)
this.abnormalCode = encodeParams // 存储异常单号
const params = {
businessCategory: feeType_G,
paymentCode: encodeParams,
paymentCodeList: [],
paymentType: paymentType_G,
}
const res = await A_X('/cpa/plugin/queryAuditErrorList', JSON.stringify(params))
this.tableData = res.data
this.isAbnormalNewsShow = true
},
/**
* 获取 当前行的 collectEncodeType_G 对应的 所在头部的下标, 用来去获取查询异常情况的参数。
* 一般来说,返回一个数字 ,当是服务费时, 返回数组
*/
getNowRowEncodeIndex() {
const table =
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-body #tb')
const headerRow = table.querySelector('thead tr')
let codeCellIndex = []
//console.log('collectEncodeType_G==>', collectEncodeType_G)
if (feeType_G === 2) {
// 此时返回一个数组,
collectEncodeType_G.forEach((item) => {
Array.from(headerRow.cells).forEach((cell, indexCell) => {
if (cell.textContent === item) {
codeCellIndex.push(indexCell)
}
})
})
} else {
Array.from(headerRow.cells).forEach((cell, indexCell) => {
if (cell.textContent === collectEncodeType_G) {
codeCellIndex = indexCell
}
})
}
return codeCellIndex
},
/**
* @param {String} headName 想要收集的数据列的表头
* @return {Array} 数据组成的数组
*/
getEncodeList(headName) {
const table =
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-body #tb')
// 获取表头中"headName"所在的列索引
const headerRow = table.rows[0]
let columnIndex = -1
for (let i = 0; i < headerRow.cells.length; i++) {
if (headerRow.cells[i].textContent === headName) {
columnIndex = i
break
}
}
// 获取headName列下的所有数据
const dataList = []
try {
if (columnIndex !== -1) {
const bodyRows = table.tBodies[0].rows
for (let j = 0; j < bodyRows.length; j++) {
const cell = bodyRows[j].cells[columnIndex]
dataList.push(cell.textContent)
}
}
return dataList
} catch (error) {
// this.$message.error(error)
}
},
/**
* 获取加密公钥
*/
async getPublicKey() {
const url = '/uaa/config'
const params = ''
const res = await A_X(url, params)
this.publicKey = res.data.publicKey
this.jsEncrypt = new JSEncrypt()
this.jsEncrypt.setPublicKey(this.publicKey)
console.log('getPublicKey res==>', res)
},
/**
* 登录, 成功之后关闭登录,打开
*/
async login() {
// 先去获取公钥, 然后再发送登录请求
await this.getPublicKey()
// 如果登录成功 , 1. 关闭登陆界面 2. 设置登陆状态已登录 3. 展示审核按钮和输入框
const params = {
...this.loginForm,
password: this.jsEncrypt.encrypt(this.loginForm.password),
}
try {
const QS = Qs
const res = await A_X('/uaa/authentication/jwt', QS.stringify(params))
this.isLoginShow = false
this.loginState = true
this.isAuditButtonAndTextareaShow = true
} catch {
this.$message({
message: '用户名或密码错误',
type: 'warning',
})
}
},
/**
* 开始审核,修改异常.
*/
async closeAbnormal() {
//console.log('this.checkedParams==>', this.checkedParams)
if (!this.checkedParams.id) {
this.$message({
message: '请至少选择一个异常',
type: 'warning',
})
return
}
if (!localStorage.getItem('auditToken')) {
// 未登录则打开登陆界面, 关闭审核界面, 节省插件空间
this.$message({
message: '审核前, 请先登录',
type: 'warning',
})
this.isLoginShow = true
this.isAuditButtonAndTextareaShow = false
return
}
this.checkedParams.describe = this.abnormalTextarea
this.checkedParams.documentsCode = this.abnormalCode
console.log('this.checkedParams==>', this.checkedParams)
const QS = Qs
const status = await A_X(
'/cpa/pluginUpdate/updateAuditState',
QS.stringify(this.checkedParams)
)
if (status === 302) {
this.isLoginShow = true
this.isAuditButtonAndTextareaShow = false
return
}
this.startAudit()
},
/**
* 收集勾选的参数
*/
selectionChange(selection) {
const ids = selection.map((item) => item.id).join(',')
this.checkedParams.id = ids
this.isAuditButtonAndTextareaShow = this.checkedParams.id ? true : false
},
/**
* 监听当前的 checkbox 的点击事件, 来禁用审核按钮
* 这个东西可以放在 '检测稽核异常' 按钮里面
*/
monitorCheckboxClick() {
console.log('开始监听', activeNavIndex_G)
const checkboxes = window.frames[activeNavIndex_G].document.querySelectorAll(
'.fixed-table-body #tb input[name="btSelectItem"]'
)
const that = this
// 监听所有 btSelectItem 复选框的点击事件
checkboxes.forEach((checkbox) => {
checkbox.addEventListener('change', function (event) {
// 获取勾选的数组, 去和 abnormalTableIndexList_G 比较是否有交集, 有则是存在异常
const nowRowIndex = Number(event.target.getAttribute('data-index'))
console.log('abnormalTableIndexList_G==>', abnormalTableIndexList_G)
const index = checkTableIndexList_G.indexOf(nowRowIndex)
if (index !== -1) {
checkTableIndexList_G.splice(index, 1) // 如果存在则删除
} else {
checkTableIndexList_G.push(nowRowIndex) // 如果不存在则添加
}
console.log('checkTableIndexList_G==>', checkTableIndexList_G)
// 是否禁用审核通过按钮
function isBanFn(arr1, arr2) {
console.log('that.stateList==>', that.stateList)
const isForceLock = that.stateList[checkTableIndexList_G[0]].isForceLock || 1
console.log('isForceLock==>', isForceLock)
return Number(isForceLock) ? true : false
}
const isBan = isBanFn(checkTableIndexList_G, abnormalTableIndexList_G)
that.isDisAbledSaveBtn = isBan
console.log('that.isDisAbledSaveBtn==>', that.isDisAbledSaveBtn)
})
})
},
/**
* 判断当前 导航栏 哪一个被激活了, 返回当前激活的导航栏的下标
*/
findActiveTabIndex() {
const tabNavContent = document.querySelector('.tab-nav-content')
const links = tabNavContent.getElementsByTagName('a')
for (let i = 0; i < links.length; i++) {
if (links[i].classList.contains('active')) {
return i + 1 // 返回索引加一,因为索引是从 0 开始的
}
}
return -1
},
/**
* 获取当前分页器所在的页数 currentPageNum_G
* 并和之前的进行比较,, 判断是否发生变化, 若发生变化则去除"异常状态" 这一个表头
*/
getcurrentPageNum() {
// 获取具有 "active" 类名的 <li> 标签
// 注意: 即便只有一页, 界面中分页器未展示,但还是有分页器的
console.log('activeNavIndex_G==>', activeNavIndex_G)
const activeListItem = window.frames[activeNavIndex_G].document.querySelector(
'.pull-right.pagination .page-number.active'
)
console.log('activeListItem==>', activeListItem)
// 获取 <a> 标签的文本内容
const activeContent =
activeListItem.querySelector('a')?.textContent ||
activeListItem.querySelector('span')?.textContent
if (activeContent !== currentPageNum_G) {
this.clearOnlyTableHeader('异常状态')
}
return activeContent
},
/**
* 清除插件添加的 '异常状态' 这一列数据
*/
clearTableHeader(colName) {
const table =
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-body #tb')
const headerRow = table.querySelector('thead tr')
// 查找表头中对应列的索引
let columnIndex = -1
Array.from(headerRow.children).forEach((th, index) => {
if (th.textContent.trim() === colName) {
columnIndex = index
}
})
if (columnIndex !== -1) {
// 删除表头中的对应列
headerRow.deleteCell(columnIndex)
// 删除每个数据行中的对应列
const dataRows = table.querySelectorAll('tbody tr')
dataRows.forEach((row) => {
row.deleteCell(columnIndex)
})
} else {
console.log('列名未找到')
}
},
/**
* 删除'异常状态'表头, 用于点击下一页时, 系统会自动清除数据去重新加载, 所以说此时只要删除表头即可
*/
clearOnlyTableHeader(colName) {
const table =
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-body #tb')
const headerRow = table.querySelector('thead tr')
// 查找表头中对应列的索引
let columnIndex = -1
Array.from(headerRow.children).forEach((th, index) => {
if (th.textContent.trim() === colName) {
columnIndex = index
}
})
if (columnIndex !== -1) {
// 删除表头中的对应列
headerRow.deleteCell(columnIndex)
} else {
console.log('列名未找到')
}
},
/**
* 查询当前界面是否含有 '异常状态' 表头
*/
isHasAbnormalStateHeader() {
const table =
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-body #tb')
const headerRow = table.querySelector('thead tr')
const hasAbnormalHeader = Array.from(headerRow.children).some(
(cell) => cell.innerText.trim() === '异常状态'
)
return hasAbnormalHeader
},
/**
* 退出插件登录
*/
async logOut() {
if (!localStorage.getItem('auditToken')) {
this.$message.warning('当前已经退出成功')
return
}
this.$message.success('退出登录成功')
// 界面恢复成初始的样子
this.tableData = []
this.isAbnormalNewsShow = false
this.isAuditButtonAndTextareaShow = false
this.isAuditpage = false
// 接口报500报错, 但是无所谓了, 退出的功能和日志记录已经实现
await A_X(urlList_G[1].url, '')
},
/**
* 放大 和 缩小 界面
*/
expandAndShrinkView() {
const card = document.querySelector('.el-card.TMbox-card')
if (card.classList.contains('is-zoomed')) {
card.classList.remove('is-zoomed')
} else {
card.classList.add('is-zoomed')
}
},
/**
* 展开和关闭界面
*/
toggleView() {
this.viewShow = !this.viewShow
},
/**
* 检测当前表格是否有数据
* @returns {boolean}
*/
checkTableData() {
const noTrEl = window.frames[activeNavIndex_G].document.querySelector(
'.fixed-table-body #tb tbody .no-records-found'
)
const trEls = window.frames[activeNavIndex_G].document.querySelectorAll(
'.fixed-table-body #tb tbody tr'
)
console.log('noTrEl==>', noTrEl)
console.log('trEls==>', trEls)
if ((trEls.length === 1 && noTrEl) || !trEls) {
return false
}
return true
},
/**
* 监听 "正在加载", 达到换页后自动稽核的效果
*/
monitorLoading() {
console.log('生成一个 observe 对象')
// 1. 先获取当前的ifream 中的 "ui_loading_progressBar"
activeNavIndex_G = this.findActiveTabIndex()
// 获取要监听的目标元素
const loadingEl =
window.frames[activeNavIndex_G].document.querySelector('#ui_loading_progressBar') ||
window.frames[activeNavIndex_G].document.querySelector('.fixed-table-loading')
console.log('loadingEl==>', loadingEl)
// 2. 开始监听: 创建一个 MutationObserver 实例
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
const styleValueList = [
'left: 50%; top: 50%; display: none;',
'top: 42px; display: none;',
]
if (styleValueList.includes(loadingEl.getAttribute(mutation.attributeName))) {
setTimeout(() => {
this.startAudit()
console.log(`检测到style变为:${loadingEl.getAttribute(mutation.attributeName)}`)
}, 800)
}
}
}
})
// 配置观察选项
const config = { attributes: true, attributeOldValue: true }
// 开始观察目标节点
observer.observe(loadingEl, config)
return observer
},
/**
* 判断只有当是审核界面的时候, 且点击 审核按钮后, 开始监听 select
*/
monitorAuditSelect() {
const auditBtnEl = window.frames[activeNavIndex_G].document.querySelector(
'.btn-toolbar .btn.btn-primary'
) // # id="saveSet"
const that = this
function handleAuditBtnClick() {
console.log('监听点击了审批按钮')
// 点击审批后, 给界面一点加载的时间, 防止查询不到 标签
// TODO : 请求加载完成之后加载. 方案: 通过使用定时执行器, 当所需dom未加载出来时, 一直循环
// const timer = setInterval(() => {
// if('el元素不存在'){
// return
// }
// clearInterval(timer)
// }, 1000)
setTimeout(() => {
const auditSelectEl =
window.frames[activeNavIndex_G].document.querySelector(
'.list-group.addReburseStyle .col-md-4 #checkState'
) ||
window.frames[activeNavIndex_G].document.querySelector(
'.list-group .col-md-4 #auditState'
)
const saveBtnEl =
window.frames[activeNavIndex_G].document.querySelector('.btn-toolbar #saveSet') ||
window.frames[activeNavIndex_G].document.querySelector('.btn-toolbar .btn-primary')
console.log('saveBtnEl==>', saveBtnEl)
console.log('auditSelectEl==>', auditSelectEl)
// 一开始直接选择的就是 "通过", 一开始选择的通过也得禁止
if (that.isDisAbledSaveBtn) {
let index = auditSelectEl.selectedIndex
let value = auditSelectEl.options[index].value
saveBtnEl.disabled = value === '0' ? true : false
console.log('saveBtnEl.disabled==>', saveBtnEl.disabled)
}
function handleSelectChange() {
console.log('开启监听 审核界面的 select')
let index = auditSelectEl.selectedIndex
let value = auditSelectEl.options[index].value
console.log('value==>', value)
saveBtnEl.disabled = value === '0' ? true : false
// 当 select 选中 "通过" 时候, 禁用当前界面的 保存按钮
console.log('saveBtnEl===>', saveBtnEl)
}
// 当勾选到了具有异常的单据,也就是 isDisAbledSaveBtn = ture 时,则开启监听 select
console.log('that.isDisAbledSaveBtn===>', that.isDisAbledSaveBtn)
if (that.isDisAbledSaveBtn) {
auditSelectEl.addEventListener('change', handleSelectChange)
}
// 当点击 "取消" 后,回来再次触发自动稽核
const cancelBtnEl = window.frames[activeNavIndex_G].document.querySelector(
'.btn-toolbar .btn.btn-default'
)
console.log('cancelBtnEl==>', cancelBtnEl)
function monitorCancelBtn() {
console.log('点击了取消按钮')
const timer = setInterval(() => {
const trEls = window.frames[activeNavIndex_G].document.querySelectorAll(
'.fixed-table-body #tb tbody tr'
)
console.log('trEls==>', trEls)
if (trEls.length >= 1) {
that.startAudit(true)
console.log('关闭定时器')
clearInterval(timer)
}
}, 1000)
}
cancelBtnEl.addEventListener('click', monitorCancelBtn)
}, 2000)
}
auditBtnEl.addEventListener('click', handleAuditBtnClick)
},
/**
* 监听 nav-tab 中的 active 所在的 nav-tab 是否时可以稽核的界面
*/
monitorTabNav() {
const that = this
// 获取要监听的元素
const navTabEl = document.querySelector('.layout-main-tab .tab-nav .tab-nav-content')
// 观察器的配置
const config = { attributes: true, childList: true, subtree: true }
// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {
// 遍历每一个变动
for (var mutation of mutationsList) {
// 如果是子节点的 class 变化
if (mutation.type === 'childList') {
// 遍历每一个子节点
mutation.addedNodes.forEach(function (node) {
// 检查类名是否发生变化
if (node.classList.contains('active')) {
// 获取当前界面()
setFeeTypeAndPayMentType()
if (matchNavList_G.map((item) => item.navName).includes(nowPageName_G)) {
let count = 0
const timer = setInterval(async function () {
count++
// 当是 报账点电费查询 界面时 查询速度较慢, 则定为 15s
let timing = nowPageName_G === '报账点电费查询' ? 15 : 5
if (count >= timing) {
// 当5/15秒后数据还未加载出来, 则判断未为无数据, 关闭定时器
clearInterval(timer)
console.log('定时器已关闭')
that.$message.warning('数据超时,请手动点击稽核按钮.')
}
const isHaveTableData = that.checkTableData()
console.log('isHaveTableData==>', isHaveTableData)
// 审核界面无数据时
if (!isHaveTableData && that.auditPageNameList.includes(nowPageName_G)) {
that.$message.warning('当前界面无数据')
console.log('无数据')
clearInterval(timer)
}
console.log('执行 startAudit')
await that.startAudit(true)
console.log('关闭定时器')
clearInterval(timer)
}, 1000)
}
}
})
}
}
}
// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback)
// 以上述配置开始观察目标节点
observer.observe(navTabEl, config)
},
},
})
/**
* 样式: 防止类名可能冲突, 前面加上TM
*/
// 注入样式
let style = document.createElement('style')
style.innerText = `
.TMContainer{
position: fixed;
top: 25%;
left: 70px;
background-color: aliceblue;
border-radius: 10px;
padding: 15px;
z-index: 99999;
padding: 7px;
border: 2px solid gray;
}
.TMbox-card {
width: 500px;
}
.el-card__body{
padding: 5px !important;
}
.el-card__header{
padding:5px !important;
}
.is-zoomed{
width: 100px;
height: 100px;
}
.el-table .el-table__cell{
padding: 3px 0 !important;
}
.el-table__header .has-gutter{
font-size:12px;
}
.el-table__body-wrapper .el-table__body tbody{
font-size:12px;
}
`
document.head.appendChild(style)
// Your code here...
})()