联调app

This commit is contained in:
guanj
2026-03-30 08:43:13 +08:00
parent 00e34c168f
commit 66cee2922d
64 changed files with 6112 additions and 2987 deletions

View File

@@ -24,7 +24,7 @@
<!-- <view class="content-item-header-right-des">暂态类型{{ item.showName }}</view> -->
<!-- <view class="content-item-header-right-des">{{ item.subTitle }}</view> -->
</view>
<view class="ml10" v-if="type === '0' || item.status != '1'">🔍</view>
<view class="ml10" v-if="type === '0' || item.status != '1'"> <uni-icons type="search" size="25"></uni-icons></view>
</view>
<view class="content-item-footer">{{ item.subTitle }}</view>
</view>

View File

@@ -3,16 +3,9 @@
<template slot="body">
<view class="device">
<view class="nav" :style="{ top: navTabHeight + 'px' }">
<view
class="nav-menu"
:class="{ 'nav-menu-active': select.engineeringName }"
@click="selectEngineering"
<view class="nav-menu" @click="selectEngineering"
>{{ select.engineeringName || '全部工程' }}
<uni-icons
type="bottom"
size="14"
:color="select.engineeringName ? '#376cf3' : '#666'"
></uni-icons>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<picker
@change="projectNameChange"
@@ -22,30 +15,16 @@
range-key="text"
v-if="select.engineeringId"
>
<view
class="nav-menu"
:class="{ 'nav-menu-active': select.projectName }"
@click="select.selectProject = true"
>
<view class="nav-menu" @click="select.selectProject = true">
{{
select.projectName
? select.projectName.length > 6
? select.projectName.substring(0, 6) + '...'
? select.projectName.substring(0, 12) + '...'
: select.projectName
: '全部项目'
}}
<uni-icons
type="top"
size="14"
:color="select.projectName ? '#376cf3' : '#666'"
v-if="select.selectProject"
></uni-icons>
<uni-icons
type="bottom"
size="14"
:color="select.projectName ? '#376cf3' : '#666'"
v-else
></uni-icons>
<uni-icons type="top" size="14" v-if="select.selectProject"></uni-icons>
<uni-icons type="bottom" size="14" v-else></uni-icons>
</view>
</picker>
<picker
@@ -55,30 +34,16 @@
:range="projectType"
range-key="text"
>
<view
class="nav-menu"
:class="{ 'nav-menu-active': select.runStatusName }"
@click="select.runStatusSelect = true"
>
<view class="nav-menu" @click="select.runStatusSelect = true">
{{
select.runStatusName
? select.runStatusName.length > 4
? select.runStatusName.substring(0, 4) + '...'
? select.runStatusName.length > 12
? select.runStatusName.substring(0, 12) + '...'
: select.runStatusName
: '全部状态'
}}
<uni-icons
type="top"
size="14"
:color="select.runStatusName ? '#376cf3' : '#666'"
v-if="select.runStatusSelect"
></uni-icons>
<uni-icons
type="bottom"
size="14"
:color="select.runStatusName ? '#376cf3' : '#666'"
v-else
></uni-icons>
<uni-icons type="top" size="14" v-if="select.runStatusSelect"></uni-icons>
<uni-icons type="bottom" size="14" v-else></uni-icons>
</view>
</picker>
</view>
@@ -108,26 +73,30 @@
</view>
<view class="content device" :style="{ minHeight: minHeight }">
<Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<uni-swipe-action>
<uni-swipe-action-item
v-for="(item, index) in store.data"
:threshold="0"
:right-options="item.isTop == 0 ? options1 : options12"
@click="bindClick($event, item)"
>
<Cn-device-card :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
style="transform: scale(0.8); position: relative; left: 20rpx"
@change="switchChange(item)"
/>
<view class="star-icon" v-else @click="toggleStar(item)">
<uni-icons
custom-prefix="custom-icon"
:type="item.isTop == 1 ? 'star-filled' : 'star'"
:color="item.isTop == 1 ? '#ffcc00' : ''"
size="25"
></uni-icons>
</view>
</template>
</Cn-device-card>
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
style="transform: scale(0.8); position: relative; left: 20rpx"
@change="switchChange(item)"
/>
<view class="star-icon" v-else>
<uni-icons type="search" size="25"></uni-icons>
</view>
</template>
</Cn-device-card>
</uni-swipe-action-item>
</uni-swipe-action>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
@@ -181,6 +150,22 @@ export default {
},
],
pageOptions: {},
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
}
},
watch: {
@@ -250,10 +235,26 @@ export default {
this.select.engineeringId = engineering.id
this.select.engineeringName = engineering.name
this.select.projectNameIndex = 0
this.select.projectName = ''
this.getProjectList()
}
this.store && this.store.reload()
},
methods: {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.equipmentId,
targetType: 1,
userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.store.search()
} else {
this.$util.toast(res.message)
}
})
},
selectEngineering() {
uni.navigateTo({
url: '/pages/home/selectEngineering?from=once',
@@ -459,22 +460,11 @@ export default {
this.checkList.push(e.equipmentId)
}
},
toggleStar(item) {
engineeringPinToTop({
targetId: item.equipmentId,
targetType: 1,
userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.store.search()
}else{
this.$util.toast(res.message)
}
})
},
},
}
</script>
<style lang="scss"></style>
<style lang="scss">
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -201,6 +201,7 @@ export default {
this.echartsDataA1 = this.initEcharts('#DAA520', 1, 'A相(A)')
this.echartsDataA2 = this.initEcharts('#2E8B57', 1, 'B相(A)')
this.echartsDataA3 = this.initEcharts('#A52a2a', 1, 'C相(A)')
this.loading = false
this.$nextTick(() => {
this.setMqtt(0)
this.initMqtt()
@@ -224,7 +225,7 @@ export default {
}
})
clearInterval(this.timer)
this.client.end()
this.client && this.client.end()
},
methods: {
@@ -590,7 +591,7 @@ export default {
// 刷新
handleRefresh() {
this.disabled = true
this.client.end()
this.client && this.client.end()
this.setMqtt(1)
this.initMqtt()
if (this.numTimer) {
@@ -611,7 +612,12 @@ export default {
}, 1000)
},
async setMqtt(e) {
uni.showLoading({
title: '连接中,请稍等...',
mask: true,
})
this.clear()
await getBaseRealData(this.lineId)
.then((res) => {
if (res.code == 'A0000') {
@@ -620,7 +626,7 @@ export default {
clearInterval(this.timer)
this.timer = null
}
this.loading = false
this.timer = setInterval(() => {
getBaseRealData(this.lineId).then((res) => {
console.log(res, '获取基础实时数据')
@@ -629,12 +635,9 @@ export default {
} else {
this.countdown = 60 // 重置倒计时
this.disabled = false
this.loading = false
}
})
.catch(() => {
this.loading = false
})
.catch(() => {})
},
initMqtt() {
@@ -852,13 +855,13 @@ export default {
})
},
// 监测点变化
lineChange(e) {
this.clear()
async lineChange(e) {
await this.clear()
this.lineKey = e.detail.value
this.lineId = this.lineList[e.detail.value].lineId
this.client.end()
this.setMqtt(0)
this.initMqtt()
await (this.client && this.client.end())
await this.setMqtt(0)
await this.initMqtt()
},
},
@@ -957,6 +960,7 @@ export default {
display: flex;
position: relative;
height: 600rpx;
margin: 0 10rpx;
flex: 1;
.echart1 {
position: absolute;
@@ -967,6 +971,7 @@ export default {
.chart {
width: 170rpx;
height: 200rpx;
margin-bottom: 5rpx;
}
.text {
text-align: center;

View File

@@ -1,273 +1,273 @@
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body">
<view class="detail">
<view class="header">
<view class="header-title"
>{{ engineering.name }}
<!-- <view class="header-title-extra">用能</view> -->
</view>
<view class="header-des-mini mb10"
>{{ engineering.provinceName + engineering.cityName }} {{ engineering.createTime }}</view
>
<view class="header-des">工程描述{{ engineering.description }} </view>
</view>
<view class="nav">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
</view>
</view>
<view class="content" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0">
<uni-card
:title="item.name"
extra="🔍"
@click="jumpProject(item)"
v-for="(item, index) in store.data"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>设备个数</view>
<view>{{ item.devNum }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
<view style="padding: 0 20rpx" v-show="navMenuActive == 2">
<image
class="gplot gplot-box"
mode="aspectFill"
src="/static/test2.pic.png"
v-for="(item, key) in 3"
:key="key"
/>
</view>
</view>
<uni-fab
ref="fab"
direction="vertical"
horizontal="right"
vertical="bottom"
:content="content"
@trigger="trigger"
v-if="content.length"
/>
<uni-popup ref="share" type="share" background-color="#fff">
<uni-popup-share title="分享到"></uni-popup-share>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import list from '../../common/js/list'
import { deleteEngineering } from '../../common/api/engineering'
export default {
mixins: [list],
data() {
return {
loading: false,
engineering: '',
navMenuList: [
{
text: '项目',
},
// {
// text: '拓扑图',
// },
],
content: [
// {
// iconPath: '/static/share.png',
// text: '编辑',
// },
// {
// iconPath: '/static/delate.png',
// text: '删除',
// },
],
navHeight: 0,
navMenuActive: 0,
}
},
methods: {
trigger(e) {
console.log(this.$refs)
if (e.item.text == '移交') {
uni.navigateTo({
url: '/pages/gc/transfer',
})
} else if (e.item.text == '分享') {
this.$refs.share.open()
} else if (e.item.text == '编辑') {
uni.navigateTo({
url: '/pages/engineering/new?engineering=' + encodeURIComponent(JSON.stringify(this.engineering)),
})
} else if (e.item.text == '删除') {
uni.showModal({
title: '提示',
content: '删除工程后不可恢复,是否继续?',
success: (res) => {
if (res.confirm) {
deleteEngineering(this.engineering.id).then((res) => {
this.$util.toast('删除成功')
this.$util.refreshPrePage()
})
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
}
},
navMenuClick(index) {
this.navMenuActive = index
},
goUserDetail() {
uni.navigateTo({
url: '/pages/mine/userDetail',
})
},
del() {
console.log('del')
uni.showModal({
title: '提示',
content: '确定要移除该成员吗?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
},
goDevice() {
uni.navigateTo({
url: '/pages/device/APF/detail',
})
},
jumpProject(item) {
uni.navigateTo({
url: '/pages/project/detail?project=' + encodeURIComponent(JSON.stringify(item)),
})
},
init() {
this.store = this.DataSource('/cs-device-boot/project/queryProject')
this.store.params.engineeringId = this.engineering.id
this.store.reload()
},
},
onLoad(option) {
this.engineering = JSON.parse(decodeURIComponent(option.engineering))
let userInfo = uni.getStorageSync('userInfo')
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
this.content.push(
{
iconPath: '/static/share.png',
text: '编辑',
},
{
iconPath: '/static/delate.png',
text: '删除',
},
)
}
setTimeout(() => {
// 获取nav高度
uni.createSelectorQuery()
.select('.nav')
.boundingClientRect((rect) => {
this.navHeight = rect.height
})
.exec()
}, 1000)
this.init()
// uni.setNavigationBarTitle({ title: this.engineering })
},
}
</script>
<style lang="scss">
.detail {
.content {
box-sizing: border-box;
padding-bottom: 20rpx;
}
.header {
padding: 20rpx 20rpx 0;
.header-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 40rpx;
margin-bottom: 10rpx;
.header-title-extra {
font-size: 24rpx;
color: #666;
padding-right: 10rpx;
}
}
.header-des {
font-size: 28rpx;
color: #666;
}
.header-des-mini {
font-size: 24rpx;
color: #999;
}
}
.footer-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
}
.gplot {
position: relative;
width: 100%;
border: 8rpx solid #ccc;
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body">
<view class="detail">
<view class="header">
<view class="header-title"
>{{ engineering.name }}
<!-- <view class="header-title-extra">用能</view> -->
</view>
<view class="header-des-mini mb10"
>{{ engineering.provinceName + engineering.cityName }} {{ engineering.createTime }}</view
>
<view class="header-des">工程描述{{ engineering.description }} </view>
</view>
<view class="nav">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
</view>
</view>
<view class="content" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0">
<uni-card
:title="item.name"
extra="🔍"
@click="jumpProject(item)"
v-for="(item, index) in store.data"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>设备个数</view>
<view>{{ item.devNum }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
<view style="padding: 0 20rpx" v-show="navMenuActive == 2">
<image
class="gplot gplot-box"
mode="aspectFill"
src="/static/test2.pic.png"
v-for="(item, key) in 3"
:key="key"
/>
</view>
</view>
<uni-fab
ref="fab"
direction="vertical"
horizontal="right"
vertical="bottom"
:content="content"
@trigger="trigger"
v-if="content.length"
/>
<uni-popup ref="share" type="share" background-color="#fff">
<uni-popup-share title="分享到"></uni-popup-share>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import list from '../../common/js/list'
import { deleteEngineering } from '../../common/api/engineering'
export default {
mixins: [list],
data() {
return {
loading: false,
engineering: '',
navMenuList: [
{
text: '项目',
},
// {
// text: '拓扑图',
// },
],
content: [
// {
// iconPath: '/static/share.png',
// text: '编辑',
// },
// {
// iconPath: '/static/delate.png',
// text: '删除',
// },
],
navHeight: 0,
navMenuActive: 0,
}
},
methods: {
trigger(e) {
console.log(this.$refs)
if (e.item.text == '移交') {
uni.navigateTo({
url: '/pages/gc/transfer',
})
} else if (e.item.text == '分享') {
this.$refs.share.open()
} else if (e.item.text == '编辑') {
uni.navigateTo({
url: '/pages/engineering/new?engineering=' + encodeURIComponent(JSON.stringify(this.engineering)),
})
} else if (e.item.text == '删除') {
uni.showModal({
title: '提示',
content: '删除工程后不可恢复,是否继续?',
success: (res) => {
if (res.confirm) {
deleteEngineering(this.engineering.id).then((res) => {
this.$util.toast('删除成功')
this.$util.refreshPrePage()
})
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
}
},
navMenuClick(index) {
this.navMenuActive = index
},
goUserDetail() {
uni.navigateTo({
url: '/pages/mine/userDetail',
})
},
del() {
console.log('del')
uni.showModal({
title: '提示',
content: '确定要移除该成员吗?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
},
goDevice() {
uni.navigateTo({
url: '/pages/device/APF/detail',
})
},
jumpProject(item) {
uni.navigateTo({
url: '/pages/project/detail?project=' + encodeURIComponent(JSON.stringify(item)),
})
},
init() {
this.store = this.DataSource('/cs-device-boot/project/queryProject')
this.store.params.engineeringId = this.engineering.id
this.store.reload()
},
},
onLoad(option) {
this.engineering = JSON.parse(decodeURIComponent(option.engineering))
let userInfo = uni.getStorageSync('userInfo')
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
this.content.push(
{
iconPath: '/static/share.png',
text: '编辑',
},
{
iconPath: '/static/delate.png',
text: '删除',
},
)
}
setTimeout(() => {
// 获取nav高度
uni.createSelectorQuery()
.select('.nav')
.boundingClientRect((rect) => {
this.navHeight = rect.height
})
.exec()
}, 1000)
this.init()
// uni.setNavigationBarTitle({ title: this.engineering })
},
}
</script>
<style lang="scss">
.detail {
.content {
box-sizing: border-box;
padding-bottom: 20rpx;
}
.header {
padding: 20rpx 20rpx 0;
.header-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 40rpx;
margin-bottom: 10rpx;
.header-title-extra {
font-size: 24rpx;
color: #666;
padding-right: 10rpx;
}
}
.header-des {
font-size: 28rpx;
color: #666;
}
.header-des-mini {
font-size: 24rpx;
color: #999;
}
}
.footer-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
}
.gplot {
position: relative;
width: 100%;
border: 8rpx solid #ccc;
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>

View File

@@ -1,188 +1,188 @@
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="工程管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.name"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
extra="🔍"
@click="jump(item)"
v-for="(item, index) in store.data"
:style="{ marginTop: index === 0 ? '0' : '' }"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>区域</view>
<view>{{ item.provinceName + item.cityName }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
</view>
</template>
<script>
import list from '../../common/js/list'
export default {
mixins: [list],
data() {
return {
loading: true,
userInfo: {},
}
},
methods: {
init() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.store = this.DataSource('/cs-device-boot/engineering/queryEngineeringPage')
this.store.params.name = ''
this.store.reload()
this.store.firstCallBack = (res) => {
let engineering = uni.getStorageSync('engineering')
if (!engineering) {
uni.setStorageSync('engineering', this.store.data[0])
} else {
this.store.data.forEach((item) => {
if (item.id == engineering.id) {
uni.setStorageSync('engineering', item)
}
})
}
}
},
back() {
uni.navigateBack()
},
add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
uni.navigateTo({
url: `/pages/engineering/new`,
})
}
},
upgrade(code) {
console.log(code)
uni.showToast({
title: '升级成功',
icon: 'none',
})
},
jump(engineering) {
uni.navigateTo({
url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`,
})
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.message {
.message-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.message-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
.tag {
margin-top: 10rpx;
font-size: 24rpx;
color: #aaa;
}
}
}
.message-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="工程管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.name"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
extra="🔍"
@click="jump(item)"
v-for="(item, index) in store.data"
:style="{ marginTop: index === 0 ? '0' : '' }"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>区域</view>
<view>{{ item.provinceName + item.cityName }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
</view>
</template>
<script>
import list from '../../common/js/list'
export default {
mixins: [list],
data() {
return {
loading: true,
userInfo: {},
}
},
methods: {
init() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.store = this.DataSource('/cs-device-boot/engineering/queryEngineeringPage')
this.store.params.name = ''
this.store.reload()
this.store.firstCallBack = (res) => {
let engineering = uni.getStorageSync('engineering')
if (!engineering) {
uni.setStorageSync('engineering', this.store.data[0])
} else {
this.store.data.forEach((item) => {
if (item.id == engineering.id) {
uni.setStorageSync('engineering', item)
}
})
}
}
},
back() {
uni.navigateBack()
},
add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
uni.navigateTo({
url: `/pages/engineering/new`,
})
}
},
upgrade(code) {
console.log(code)
uni.showToast({
title: '升级成功',
icon: 'none',
})
},
jump(engineering) {
uni.navigateTo({
url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`,
})
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.message {
.message-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.message-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
.tag {
margin-top: 10rpx;
font-size: 24rpx;
color: #aaa;
}
}
}
.message-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>

View File

@@ -34,7 +34,7 @@ export default {
this.engineeringList.forEach((item) => {
let arr = pinyin(item.name[0], { toneType: 'none', type: 'array' })
let letter = arr[0][0].toUpperCase()
console.log(letter)
// console.log(letter)
let index = result.findIndex((item) => item.letter === letter)
if (index === -1) {
result.push({
@@ -67,7 +67,16 @@ export default {
onShow() {
queryEngineering().then((res) => {
this.engineeringList = res.data.sort((a, b) => {
return a.name.localeCompare(b.name, 'zh', { sensitivity: 'accent' })
const nameA = a.name
const nameB = b.name
const isANumber = /^\d/.test(nameA)
const isBNumber = /^\d/.test(nameB)
if (isANumber !== isBNumber) {
return isANumber ? 1 : -1
}
return nameA.localeCompare(nameB, 'zh', { sensitivity: 'accent' })
})
})
},

View File

@@ -2,14 +2,14 @@
<view>
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :showDatetime="false"> </Cn-filterCriteria>
<Cn-filterCriteria @select="select" :singleChoice="true" :showDatetime="true"> </Cn-filterCriteria>
<view class="choose1">
<view>
<checkbox-group @change="changeBox"
><checkbox value="true" :checked="checkedAll" />全选
</checkbox-group></view
>
<view class="nav-menu nav-menu-btn" @click="selectDevice('transfer')">申请报 </view>
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报 </view>
</view>
</view>
<view class="smallLabel mt20">
@@ -24,11 +24,15 @@
</view>
</view>
<!-- 卡片 -->
<view class="event-list" :style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }">
<scroll-view
scroll-y="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
:class="judgment(item.showName)"
:class="judgment(item.showName).type"
v-for="(item, index) in store.data"
:key="index"
@click="clackCard(item)"
@@ -39,27 +43,17 @@
<!-- 动态图标根据类型切换 -->
<uni-icons
:custom-prefix="judgment(item.showName) == 'interrupt' ? 'custom-icon' : 'iconfont'"
:type="
judgment(item.showName) == 'sag'
? 'icon-xiajiang'
: judgment(item.showName) == 'swell'
? 'icon-shangsheng'
: 'minus'
"
:color="
judgment(item.showName) == 'sag'
? '#2563eb '
: judgment(item.showName) == 'swell'
? '#e6a23c'
: '#909399'
"
:size="judgment(item.showName) == 'interrupt' ? '50' : '25'"
:type="judgment(item.showName).icon"
:color="judgment(item.showName).color"
:size="judgment(item.showName).size"
></uni-icons>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.equipmentName }}</text>
<text class="event-tag" :class="`${judgment(item.showName)}-tag`">{{ item.showName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName
}}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
@@ -88,11 +82,12 @@
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</view>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { applicationReport } from '@/common/api/report.js'
export default {
components: {},
props: {
@@ -112,20 +107,21 @@ export default {
array: ['发生时间', '暂降深度', '持续时间'],
}
},
mounted() {},
mounted() {
this.setHeight()
},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
console.log('🚀 ~ rect:', rect)
//
// #ifdef H5
this.height = rect?.height + 100 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 100 || 0
this.height = rect?.height + 90 || 0
// #endif
})
.exec()
@@ -144,8 +140,11 @@ export default {
this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.startTime = this.selectValue.range[0]
this.store.params.endTime = this.selectValue.range[1]
this.store.params.target = ['Evt_Sys_DipStr']
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
// this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {
this.checkedTotal = 0
this.store.data = this.store.data.map((item) => {
@@ -184,16 +183,89 @@ export default {
this.sort = e.detail.value
this.init()
},
judgment(val) {
judgment(val, key) {
switch (val) {
case '电压暂降':
return 'sag'
return {
type: 'sag',
icon: 'icon-a-svg4',
color: '#2563eb',
size: '25',
}
case '电压暂升':
return 'swell'
return {
type: 'swell',
icon: 'icon-a-svg5',
color: '#e6a23c',
size: '25',
}
case '电压中断':
return 'interrupt'
return {
type: 'interrupt',
icon: 'icon-zhongduan2',
color: '#6b7280',
size: '35',
}
case '瞬态':
return {
type: 'transient',
icon: 'icon-shuntaishijian',
color: '#8b5cf6',
size: '40',
}
case '未知':
return {
type: 'unknown',
icon: 'icon-wenhao',
color: '#6b7280',
size: '45',
}
}
},
// 申请
selectDevice() {
if (this.checkedTotal == 0) {
return uni.showToast({
title: '请选择事件!',
icon: 'none',
})
} else {
uni.showLoading({
title: '申请中,请稍等...',
mask: true,
})
let list = this.store.data.filter((item) => item.checked === true)
applicationReport({
list: list.map((item) => item.id),
lineId: list[0].lineId,
startTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay,
endTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay,
}).then((res) => {
this.store.reload()
uni.showToast({
icon: 'success',
mask: true,
title: '申请暂态报告,成功!',
duration: 1000,
})
})
}
},
isAllLineIdSame(data) {
// 获取第一个元素的lineId作为基准
const baseLineId = data[0].lineId
// 遍历数组检查每个元素的lineId是否和基准一致
for (let item of data) {
// 兼容元素可能没有lineId的情况
if (!item || item.lineId !== baseLineId) {
return false
}
}
return true
},
},
computed: {},
@@ -220,9 +292,11 @@ export default {
}
}
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
margin-left: 20rpx;
margin-bottom: 20rpx;
line-height: 40rpx;
font-size: 24rpx;
border-radius: 8rpx;
background: #ebeaec;

View File

@@ -60,26 +60,28 @@
</picker> -->
</view>
<view class="content device" :style="{ minHeight: minHeight }">
<Cn-device-card v-for="(item, index) in deviceListFilter" :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
style="transform: scale(0.8); position: relative; left: 20rpx"
@change="switchChange(item)"
/>
<view class="star-icon" v-else @click="toggleStar(item)">
<uni-icons
custom-prefix="custom-icon"
:type="item.isTop == 1 ? 'star-filled' : 'star'"
:color="item.isTop == 1 ? '#ffcc00' : ''"
size="25"
></uni-icons>
</view>
</template>
</Cn-device-card>
<uni-swipe-action>
<uni-swipe-action-item
v-for="(item, index) in deviceListFilter"
:threshold="0"
:right-options="item.isTop == 0 ? options1 : options12"
@click="bindClick($event, item)"
>
<Cn-device-card :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
style="transform: scale(0.8); position: relative; left: 20rpx"
@change="switchChange(item)"
/>
<view class="star-icon" v-else> <uni-icons type="search" size="25"></uni-icons> </view>
</template>
</Cn-device-card>
</uni-swipe-action-item>
</uni-swipe-action>
<uni-load-more
v-if="store.status == 'loading' || deviceListFilter.length > 0"
:status="store.status"
@@ -118,6 +120,22 @@ export default {
projectType: [],
userInfo: {},
selectProject: false,
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
}
},
computed: {
@@ -148,7 +166,7 @@ export default {
},
mounted() {},
methods: {
toggleStar(item) {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.equipmentId,
targetType: 1,
@@ -162,6 +180,7 @@ export default {
}
})
},
selectDevice(type) {
if (this.deviceListFilter.findIndex((item) => item.isPrimaryUser === '1') === -1) {
this.$util.toast('没有可操作的设备')
@@ -351,4 +370,9 @@ export default {
.nav-menu {
}
}
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
</style>

View File

@@ -2,42 +2,49 @@
<view class="index-device">
<view class="nav" :style="{ top: navTabHeight + 'px' }"> </view>
<view class="content device project-list" :style="{ minHeight: minHeight }">
<uni-card v-for="(item, index) in store.data" :key="index">
<view class="card-header">
<view class="project-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" color="#2563eb" size="45"></uni-icons>
</view>
<view class="project-info">
<view class="project-name">{{ item.engineeringName }}</view>
<view class="project-stats">
<view class="stat-item" @click="jump('nowEngineering', item)">
<text class="stat-value blue">{{ item.devTotal }}</text>
<text class="stat-label">设备总数</text>
<uni-swipe-action>
<uni-swipe-action-item
v-for="(item, index) in store.data"
:threshold="0"
:right-options="item.isTop == 0 ? options1 : options12"
@click="bindClick($event, item)"
>
<uni-card :key="index">
<view class="card-header">
<view class="project-icon">
<uni-icons
custom-prefix="iconfont"
type="icon-gongcheng"
color="#2563eb"
size="45"
></uni-icons>
</view>
<view class="stat-item" @click="jump('currentOnLineDevs', item)">
<text class="stat-value green">{{ item.onlineDevTotal }}</text>
<text class="stat-label">在线设备</text>
</view>
<view class="stat-item" @click="jump('currentOffLineDevs', item)">
<text class="stat-value red">{{ item.offlineDevTotal }}</text>
<text class="stat-label">离线设备</text>
</view>
<view class="stat-item" @click="jump('event', item)">
<text class="stat-value red">{{ item.alarmTotal }}</text>
<text class="stat-label">告警数量</text>
<view class="project-info">
<view class="project-name">{{ item.engineeringName }}</view>
<view class="project-stats">
<view class="stat-item" @click="jump('nowEngineering', item)">
<text class="stat-value blue">{{ item.devTotal }}</text>
<text class="stat-label">设备总数</text>
</view>
<view class="stat-item" @click="jump('currentOnLineDevs', item)">
<text class="stat-value green">{{ item.onlineDevTotal }}</text>
<text class="stat-label">在线设备</text>
</view>
<view class="stat-item" @click="jump('currentOffLineDevs', item)">
<text class="stat-value red">{{ item.offlineDevTotal }}</text>
<text class="stat-label">离线设备</text>
</view>
<view class="stat-item" @click="jump('event', item)">
<text class="stat-value red">{{ item.alarmTotal }}</text>
<text class="stat-label">告警数量</text>
</view>
</view>
</view>
</view>
</view>
<view class="star-icon" @click="toggleStar(item)">
<uni-icons
custom-prefix="custom-icon"
:type="item.isTop == 1 ? 'star-filled' : 'star'"
:color="item.isTop == 1 ? '#ffcc00' : ''"
size="25"
></uni-icons>
</view>
</view>
</uni-card>
<view class="pinToTop" v-if="item.isTop == 1"> 置顶 </view>
</uni-card>
</uni-swipe-action-item>
</uni-swipe-action>
<uni-load-more
v-if="store.status == 'loading' || deviceListFilter.length > 0"
:status="store.status"
@@ -61,6 +68,22 @@ export default {
minHeight: 0,
navTabHeight: 0,
userInfo: {},
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
}
},
computed: {
@@ -77,7 +100,7 @@ export default {
console.log(12333, this.store)
},
methods: {
toggleStar(item) {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.engineeringId,
targetType: 2,
@@ -85,12 +108,13 @@ export default {
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.$emit('refresh')
this.store.search()
} else {
this.$util.toast(res.message)
}
})
},
getDeviceList() {
this.store.params.pageSize = 50
this.store.firstCallBack = (res) => {
@@ -124,6 +148,11 @@ export default {
jump(type, item) {
if (type == 'event') {
// 存储参数
uni.setStorageSync('messageParams', {
name: item.engineeringName,
id: item.engineeringId,
})
uni.switchTab({
url: '/pages/index/message1',
})
@@ -171,8 +200,9 @@ export default {
}
.project-name {
font-size: 15px;
color: #3a3a3a;
font-size: 28rpx;
font-weight: 700;
color: #333333;
margin-bottom: 10rpx;
}
@@ -193,13 +223,13 @@ export default {
}
.stat-value {
font-size: 30rpx;
font-size: 32rpx;
font-weight: 700;
}
.stat-label {
font-size: 24rpx;
color: #6a6a6a;
font-size: 26rpx;
color: #666666;
}
.blue {
@@ -221,4 +251,26 @@ export default {
/deep/ .uni-card {
padding: 0 !important;
}
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
height: 60rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
position: absolute;
top: 0;
right: 0;
/* 核心:旋转成斜三角效果 */
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1">
<template v-if="devCount.engineeringListLength > 0">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
@@ -53,7 +53,7 @@
<view style="padding: 20rpx 20rpx 0">
<Cn-grid title="" :auto-fill="false">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice(4)"></Cn-grid-item>
<!-- <Cn-grid-item
<Cn-grid-item
src="/static/device2.png"
text="功能调试"
@click="registerDevice(2)"
@@ -64,12 +64,12 @@
text="出厂调试"
@click="registerDevice(3)"
v-if="config.factory"
></Cn-grid-item> -->
<!-- <Cn-grid-item background="#fff" v-if="!config.feature"></Cn-grid-item>
<Cn-grid-item background="#fff" v-if="!config.factory"></Cn-grid-item> -->
<Cn-grid-item background="#fff"></Cn-grid-item>
<Cn-grid-item background="#fff"></Cn-grid-item>
></Cn-grid-item>
<Cn-grid-item background="#fff" v-if="!config.feature"></Cn-grid-item>
<Cn-grid-item background="#fff" v-if="!config.factory"></Cn-grid-item>
<Cn-grid-item background="#fff"></Cn-grid-item>
<!-- <Cn-grid-item background="#fff"></Cn-grid-item>
<Cn-grid-item background="#fff"></Cn-grid-item> -->
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
<!-- <Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>-->
</Cn-grid>
@@ -156,15 +156,15 @@ export default {
this.$refs.popup.close()
},
confirm(value) {
if (this.devCount.engineeringListLength > 0) {
uni.navigateTo({
url: '/pages/device/new?type=' + this.type,
})
} else {
uni.navigateTo({
url: '/pages/engineering/new?from=index&type=' + this.type,
})
}
// if (this.devCount.engineeringListLength > 0) {
uni.navigateTo({
url: '/pages/device/new?type=' + this.type,
})
// } else {
// uni.navigateTo({
// url: '/pages/engineering/new?from=index&type=' + this.type,
// })
// }
this.$refs.popup.close()
},

View File

@@ -1,143 +1,140 @@
<template>
<view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
</view>
<view class="mt20"></view>
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item-value"
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
</view>
<view class="canneng-index-title mt20">常用功能</view>
<view style="padding: 20rpx 20rpx 0">
<Cn-grid title="">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item>
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>
</Cn-grid>
</view>
<uni-popup ref="popup" type="dialog" @maskClick='maskClick'>
<uni-popup-dialog
mode="base"
type="info"
content="请选择设备类型"
:duration="0"
confirmText="直连设备"
cancelText="网关接入"
cancelColor= '#007aff'
@close="close"
@confirm="confirm"
></uni-popup-dialog>
</uni-popup>
</view>
<view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
</view>
<view class="mt20"></view>
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item-value"
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
</view>
<view class="canneng-index-title mt20">常用功能</view>
<view style="padding: 20rpx 20rpx 0">
<Cn-grid title="">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item>
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>
</Cn-grid>
</view>
<uni-popup ref="popup" type="dialog" @maskClick="maskClick">
<uni-popup-dialog
mode="base"
type="info"
content="请选择设备类型"
:duration="0"
confirmText="直连设备"
cancelText="网关接入"
cancelColor="#007aff"
@close="close"
@confirm="confirm"
></uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
loading: false,
}
},
props: {
devCount: {
type: Object,
default: {},
},
},
methods: {
submitFeedBack() {
uni.navigateTo({ url: '/pages/home/feedback' })
},
registerDevice() {
this.$refs.popup.open()
// uni.showModal({
// title: '提示',
// content: '请选择设备类型',
// confirmText: '直连设备',
// cancelText: '网关接入',
// cancelColor: '#007aff',
// success: ({confirm, cancel}) => {
// if (confirm) {
// if (this.devCount.engineeringListLength > 0) {
// uni.navigateTo({
// url: '/pages/device/new?type=4',
// })
// } else {
// uni.navigateTo({
// url: '/pages/engineering/new?from=index'
// })
// }
data() {
return {
loading: false,
}
},
props: {
devCount: {
type: Object,
default: {},
},
},
methods: {
submitFeedBack() {
uni.navigateTo({ url: '/pages/home/feedback' })
},
registerDevice() {
this.$refs.popup.open()
// uni.showModal({
// title: '提示',
// content: '请选择设备类型',
// confirmText: '直连设备',
// cancelText: '网关接入',
// cancelColor: '#007aff',
// success: ({confirm, cancel}) => {
// if (confirm) {
// if (this.devCount.engineeringListLength > 0) {
// uni.navigateTo({
// url: '/pages/device/new?type=4',
// })
// } else {
// uni.navigateTo({
// url: '/pages/engineering/new?from=index'
// })
// }
// } else if (cancel) {
// // uni.navigateTo({
// // url: '/pages/gateway/list',
// // })
// this.$util.toast('功能正在开发,敬请期待')
// }
// },
// })
},
maskClick(){
this.$refs.popup.close()
},
close() {
this.$util.toast('功能正在开发,敬请期待')
this.$refs.popup.close()
},
confirm(value) {
if (this.devCount.engineeringListLength > 0) {
uni.navigateTo({
url: '/pages/device/new?type=4',
})
} else {
uni.navigateTo({
url: '/pages/engineering/new?from=index'
})
}
this.$refs.popup.close()
},
registerGateway() {
uni.navigateTo({
url: '/pages/gateway/new',
})
},
jump(type) {
uni.navigateTo({
url: '/pages/device/list?type=' + type,
})
},
},
// } else if (cancel) {
// // uni.navigateTo({
// // url: '/pages/gateway/list',
// // })
// this.$util.toast('功能正在开发,敬请期待')
// }
// },
// })
},
maskClick() {
this.$refs.popup.close()
},
close() {
this.$util.toast('功能正在开发,敬请期待')
this.$refs.popup.close()
},
confirm(value) {
// if (this.devCount.engineeringListLength > 0) {
uni.navigateTo({
url: '/pages/device/new?type=4',
})
// } else {
// uni.navigateTo({
// url: '/pages/engineering/new?from=index',
// })
// }
this.$refs.popup.close()
},
registerGateway() {
uni.navigateTo({
url: '/pages/gateway/new',
})
},
jump(type) {
uni.navigateTo({
url: '/pages/device/list?type=' + type,
})
},
},
}
</script>
<style lang="scss"></style>

View File

@@ -1,6 +1,6 @@
<template>
<view class="dateReport">
<view class="pd20">
<!-- <view class="pd20">
<uni-segmented-control
:current="curSub"
class="subsection"
@@ -8,42 +8,58 @@
:values="subsectionList"
@clickItem="sectionChange"
/>
</view> -->
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :singleChoice="true" :report="true"> </Cn-filterCriteria>
</view>
<!-- 卡片 -->
<view
class="event-list"
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list mt20"
v-if="eventList.length != 0"
:style="{ height: 'calc(100vh - ' + (navHeight + 56) + 'px)', overflow: 'auto' }"
:style="{ height: 'calc(100vh - ' + height + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card class="event-item" :class="item.type" v-for="(item, index) in eventList" :key="index">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-info">
<view class="event-title">
<text class="event-id" >{{ item.id }}</text>
<text class="event-tags">{{ item.tag }}</text>
<text class="event-id">{{ item.lineName }}</text>
<view class="event-tags"
>{{ selectValue.report == 0 ? item.startTime : item.startTime + '至' + item.endTime }}
<view class="iconText ml10" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
</view>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>频率偏差越限111次</text>
<text>不平衡度越限3次</text>
<text>电压畸变率越限5次</text>
<text>偶次电压越限5次</text>
<text>{{ item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc }}</text>
</view>
<view class="downloadReport">
<!-- <view class="downloadReport" @click="download">
<uni-icons type="download" size="16" color="#376cf3"></uni-icons>下载报告
</view>
</view> -->
</uni-card>
<uni-load-more :status="status"></uni-load-more>
</view>
<Cn-empty v-else></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { downloadHarmonicReport } from '@/common/api/report.js'
export default {
components: {},
props: {
@@ -60,6 +76,7 @@ export default {
default: 0,
},
},
mixins: [list],
data() {
return {
status: 'noMore',
@@ -73,20 +90,133 @@ export default {
status: '1',
},
],
thisSelectValue: {},
triggered: true,
height: 0,
}
},
created() {},
mounted() {
this.setHeight()
},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 130 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 75 || 0
// #endif
})
.exec()
},
sectionChange(index) {
this.curSub = index.currentIndex
},
scrolltolower() {
if (this.total != this.indexList.length) {
this.$emit('scrolltolower')
} else {
// this.status = 'noMore'
}
init() {
if (this.selectValue.lineId == '') return
this.store = this.DataSource('/cs-report-boot/csAppReport/reportList')
this.store.params.pageSize = 10000
this.store.params.timeType = this.selectValue.report
this.store.params.engineerId = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.devId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.time = this.selectValue.date
// this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {}
this.store.reload()
},
select(value) {
this.selectValue = value
this.init()
setTimeout(() => {
this.setHeight()
}, 100)
},
// 下载
download(item) {
uni.showLoading({
title: '下载中,请稍等...',
mask: true,
})
downloadHarmonicReport({
devId: this.selectValue.deviceId,
endTime: item.endTime,
engineerId: this.selectValue.engineeringId,
lineId: this.selectValue.lineId,
list: [],
projectId: this.selectValue.projectId,
startTime: item.startTime,
time: '',
timeType: this.selectValue.report,
}).then((res) => {
// 下载文件资源到本地
uni.downloadFile({
url: res.data, // 后端返回的线上文件路径
success: function (res) {
if (res.statusCode === 200) {
// 文件到本地
uni.saveFile({
tempFilePath: res.tempFilePath, //临时路径
success: function (data) {
var savedFilePath = data.savedFilePath
// 在app端执行
// #ifdef APP-PLUS
let osname = plus.os.name
// 如果是安卓的话弹出提示
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
// #endif
//ios手机直接打开文件手动存储文件到手机Android手机从根目录创建文件夹保存文件并改名
setTimeout(() => {
//打开文档查看
uni.openDocument({
filePath: data.savedFilePath,
success: function (ress) {
console.log('成功打开文件')
},
fail() {
console.log('打开文件失败')
},
})
}, 500)
},
})
console.log('下载成功')
} else {
uni.showToast({
icon: 'error',
mask: true,
title: '下载失败!',
duration: 1000,
})
}
},
fail: function (res) {},
})
})
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
@@ -101,12 +231,15 @@ export default {
justify-content: space-between;
}
.event-tags {
font-size: 24rpx;
display: flex;
font-size: 27rpx !important ;
line-height: 50rpx;
}
.event-detail {
display: grid;
grid-template-columns: 1fr 1fr;
font-size: 25rpx !important;
// display: grid;
// grid-template-columns: 1fr 1fr;
}
.downloadReport {
width: 100%;
@@ -120,5 +253,31 @@ export default {
display: flex;
justify-content: center;
}
.filterCriteria {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
.iconText {
width: 45rpx;
height: 45rpx;
border-radius: 50%;
background-color: $uni-theme-color;
text-align: center;
line-height: 45rpx;
}
</style>

View File

@@ -10,57 +10,106 @@
/>
</view>
<!-- 申请报 -->
<view v-if="curSub == 0">
<!-- 申请报 -->
<view v-show="curSub == 0">
<!-- apply -->
<Apply :navHeight="navHeight"/>
<Apply :navHeight="navHeight" />
</view>
<!-- 申请记录 -->
<view v-if="curSub == 1">
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :showQianTree="false"> </Cn-filterCriteria>
</view>
<view
class="record event-list"
v-if="eventList.length != 0"
:style="{ height: 'calc(100vh - ' + (navHeight + 56) + 'px)', overflow: 'auto' }"
class="record event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card class="event-item" :class="item.type" v-for="(item, index) in eventList" :key="index">
<view class="title" :class="item.status == 1 ? 'completed' : 'incomplete'">
<view> {{ item.status == 1 ? '已完成' : '未完成' }} </view>
</view>
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view
class="event-icon"
:style="{ backgroundColor: item.isComplete == 1 ? '#10b98120' : '#FF000020' }"
>
<!-- 动态图标根据类型切换 -->
<uni-icons
custom-prefix="iconfont"
type="icon-baogaoguanli"
size="40"
:color="item.isComplete == 1 ? '#10b981' : '#FF0000'"
></uni-icons>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.id }}</text>
<text class="event-tags">{{ item.tag }}</text>
<text class="event-id">{{ item.lineName }}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>设备名称{{ item.deviceName }}</text>
<!-- <text>申请时间{{ item.time }}</text>
<text>事件数{{ item.eventNums }}</text> -->
</view>
</view>
<view class="event-action">
<view class="iconText" v-if="item.isComplete == 1" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
<view
class="nav-menu nav-menu-btn"
v-else-if="userInfo.authorities === 'operation_manager'"
@click="generate(item)"
>生成报告
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>申请人xxx</text>
<text>电话号码18888888888</text>
</view>
<view class="downloadReport">
<!-- <u-icon :name="item.status == 1 ? 'download' : 'upload'" color="#376cf3" size="40"></u-icon> -->
<uni-icons
:type="item.status == 1 ? 'download' : 'upload'"
size="16"
color="#376cf3"
></uni-icons>
<!-- <view class="device-body"> -->
<view class="device-body-item">
<text>申请人</text>
<text>{{ item.applyUser }}</text>
</view>
<view class="device-body-item">
<text>申请时间</text>
<text>{{ item.time }}</text>
</view>
<view class="device-body-item">
<text>暂降事件</text>
<text>{{ item.eventNums }}</text>
</view>
<view class="device-body-item">
<text>申请状态</text>
<text
:style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }"
style="font-weight: 700"
>{{ item.isComplete == 1 ? '已完成' : '未完成' }}</text
>
</view>
{{ item.status == 1 ? '下载报告' : '生成报告' }}
<!-- <view class="device-body-item">
<text>申请时间</text>
<text>{{ item.time }}</text>
</view> -->
</view>
<!-- </view> -->
</uni-card>
<uni-load-more :status="status"></uni-load-more>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 30%"></Cn-empty>
</view>
<Cn-empty v-else></Cn-empty>
</view>
</view>
</template>
<script>
import Apply from './apply.vue'
import list from '@/common/js/list'
import { createEventReport, downloadEventReport } from '@/common/api/report.js'
export default {
components: { Apply },
props: {
@@ -81,99 +130,205 @@ export default {
default: 0,
},
},
mixins: [list],
data() {
return {
value: ['0'],
content: 123,
curSub: 0,
subsectionList: ['申请报', '申请记录'],
subsectionList: ['申请报', '申请记录'],
form: {
type: 0,
lindId: '',
},
status: 'noMore',
eventList: [
{
id: '测试监测点',
tag: '2026-01-23至2026-01-23',
status: '1',
},
{
id: '测试监测点',
tag: '2026-01-23至2026-01-23',
status: '0',
},
],
userInfo: {},
height: 0,
selectValue: {},
}
},
created() {},
mounted() {},
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
computed: {},
methods: {
scrolltolower() {
this.$emit('scrolltolower')
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 115 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 10 || 0
// #endif
})
.exec()
},
init() {
this.store = this.DataSource('/cs-report-boot/csAppReport/getApplicationReport')
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {}
this.store.reload()
},
async select(val) {
this.selectValue = val
await this.init()
this.setHeight()
},
getHeight() {},
sectionChange(index) {
this.curSub = index.currentIndex
},
// 生成报告
generate(item) {
uni.showLoading({
title: '生成中,请稍等...',
mask: true,
})
createEventReport({
id: item.eventId,
}).then((res) => {
uni.showToast({
icon: 'success',
mask: true,
title: '生成事件报告成功!',
duration: 1000,
})
this.store.reload()
})
},
// 下载报告
download(item) {
uni.showLoading({
title: '下载中,请稍等...',
mask: true,
})
downloadEventReport({
id: item.eventId,
}).then((res) => {
// 下载文件资源到本地
uni.downloadFile({
url: res.data, // 后端返回的线上文件路径
success: function (res) {
if (res.statusCode === 200) {
// 文件到本地
uni.saveFile({
tempFilePath: res.tempFilePath, //临时路径
success: function (data) {
var savedFilePath = data.savedFilePath
// 在app端执行
// #ifdef APP-PLUS
let osname = plus.os.name
// 如果是安卓的话弹出提示
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
// #endif
//ios手机直接打开文件手动存储文件到手机Android手机从根目录创建文件夹保存文件并改名
setTimeout(() => {
//打开文档查看
uni.openDocument({
filePath: data.savedFilePath,
success: function (ress) {
console.log('成功打开文件')
},
fail() {
console.log('打开文件失败')
},
})
}, 500)
},
})
console.log('下载成功')
} else {
uni.showToast({
icon: 'error',
mask: true,
title: '下载失败!',
duration: 1000,
})
}
},
fail: function (res) {},
})
})
},
},
watch: {},
}
</script>
<style lang="scss" scoped>
@import '@/pages/message1/index.scss';
.event-title {
justify-content: space-between;
}
.event-tags {
font-size: 24rpx;
}
.event-detail {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-columns: 1fr 1.2fr;
}
.downloadReport {
width: 100%;
background: #376cf320;
height: 60rpx;
line-height: 60rpx;
color: #376cf3;
font-weight: 600;
border-radius: 15rpx;
margin-top: 10rpx;
// /deep/ .record {
// .uni-card__content {
// padding: 55rpx 20rpx 20rpx !important;
// }
// }
.filterCriteria {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
// .device-body {
// padding: 10rpx 20rpx 20rpx;
.device-body-item {
display: flex;
// justify-content: space-between;
font-size: 26rpx;
color: #666666;
line-height: 1.5;
}
// }
.iconText {
display: flex;
width: 45rpx;
height: 45rpx;
border-radius: 50%;
background-color: $uni-theme-color;
justify-content: center;
align-items: center;
}
.title {
position: absolute;
left: 0px;
width: calc(100% - 36rpx);
// margin: 0 10px;
top: 0;
border-radius: 4px 4px 0 0;
padding: 2px 10px;
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
font-size: 24rpx;
font-weight: 600px;
display: flex;
justify-content: space-between;
font-weight: 700;
}
.completed {
background: #e1f3d8;
color: #67c23a;
}
.incomplete {
background: #fde2e2;
color: #f56c6c;
}
/deep/ .record {
.uni-card__content {
padding: 55rpx 20rpx 20rpx !important;
border-radius: 8rpx;
line-height: 40rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
}
</style>

View File

@@ -33,11 +33,11 @@
<view class="index">
<!-- 运维 -->
<YunWei :devCount="devCount" v-if="userInfo.authorities === 'operation_manager'" />
<!-- 专职 -->
<!-- 营销 -->
<ZhuanZhi :devCount="devCount" v-if="userInfo.authorities === 'market_user'" />
<!-- 工程 -->
<GongCheng ref="gongCheng" :devCount="devCount" v-if="userInfo.authorities === 'engineering_user'" />
<!-- 主用户 -->
<!-- 正式 -->
<ZhuYongHu :devCount="devCount" v-if="userInfo.authorities === 'app_vip_user'" />
<!-- 游客 -->
<YouKe :devCount="devCount" v-if="userInfo.authorities === 'tourist'"></YouKe>

View File

@@ -117,13 +117,24 @@ export default {
},
onShow() {
const params = uni.getStorageSync('messageParams')
console.log('🚀 ~ params:', params)
this.getDevCount()
this.$nextTick(() => {
this.refresh()
this.$refs.cnFilterCriteria.getProjectList()
if (params.name != '') {
this.$refs.cnFilterCriteria && this.$refs.cnFilterCriteria.external(params.name, params.id)
}
// this.refresh()
this.$refs.TransientRef && this.$refs.TransientRef.getConfig()
})
},
// 页面销毁
onHide() {
uni.setStorageSync('messageParams', {
name: '',
id: '',
})
},
methods: {
setHeight() {
uni.createSelectorQuery()
@@ -132,7 +143,7 @@ export default {
this.width = rect.width
//
// #ifdef H5
this.navHeight = rect.height + 70
this.navHeight = rect.height + 75
// #endif
// #ifdef APP-PLUS
this.navHeight = rect.height + 20
@@ -144,10 +155,7 @@ export default {
refresh() {
switch (this.current) {
case 0:
// this.$refs.TransientRef.getConfig()
// this.$refs.TransientRef.filterValue = ''
this.$refs.TransientRef.store.reload()
break
case 1:
this.$refs.SteadyStateRef.store.reload()
@@ -171,7 +179,7 @@ export default {
this.setHeight()
}, 100)
},
// 设置角标
getDevCount() {
if (uni.getStorageSync('projectList')[1] != undefined) {
getDevCount(uni.getStorageSync('projectList')[1].engineeringId).then((res) => {
@@ -242,7 +250,7 @@ export default {
}
.segmented-control__text {
font-size: 27rpx !important;
font-size: 30rpx !important;
color: rgb(96, 98, 102);
}
.segmented-control__item--text {

View File

@@ -47,7 +47,7 @@ export default {
total: 6,
loading: false,
items: ['稳态报表', '暂态报表'],
items: ['稳态报表', '暂降报告'],
status: 'more', //more加载前 loading加载中 noMore加载后
navHeight: 0,
@@ -99,7 +99,7 @@ export default {
.boundingClientRect((rect) => {
//
// #ifdef H5
this.navHeight = rect.height + 60
this.navHeight = rect.height + 65
// #endif
// #ifdef APP-PLUS
this.navHeight = rect.height + 10
@@ -160,7 +160,7 @@ export default {
}
.segmented-control__text {
font-size: 27rpx !important;
font-size: 30rpx !important;
color: rgb(96, 98, 102);
}
.segmented-control__item--text {

View File

@@ -1,147 +1,147 @@
<template>
<Cn-page :loading='loading'>
<view slot='body'>
<view class='detail'>
<view class="detail-content ">
<view class="detail-content-title mb20">{{ pageData.title }}</view>
<view> {{ pageData.createTime }}</view>
<view class="mt10 mb10">{{ pageData.description }}</view>
<uni-file-picker readonly v-model="imageValue" mode="grid"/>
</view>
<view class="detail-content " style="margin-bottom:0">
<view class="detail-content-title ">
<view class="title">进度</view>
<!-- <template v-if="pageData.status === '1'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('2')">解决</view>-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>-->
<!-- <template v-if="pageData.status === '2'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>-->
<!-- <view class="title-btn" @click="open">回复</view>-->
</view>
</view>
<uni-list>
<uni-list-item :title="item.userName" :note="item.chatContent" :rightText="item.createTime"
v-for="(item, index) in pageData.csFeedbackChatPOList" :key="index"/>
<Cn-empty
v-if="pageData.csFeedbackChatPOList && pageData.csFeedbackChatPOList.length == 0"></Cn-empty>
</uni-list>
<!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog ref="inputClose" type="info" mode="input" title="输入内容"
value="对话框预置提示内容!"
placeholder="请输入内容" @confirm="dialogInputConfirm">
<uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="chatContent"
placeholder="请输入内容"></uni-easyinput>
</uni-popup-dialog>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import {queryFeedBackDetail, AddFeedbackChat, updateChatStatus, updateFeedBackStatus} from '../../common/api/feedback'
export default {
data() {
return {
loading: false,
chatContent: "",
imageValue: [
{
"name": "file.png",
"extname": "png",
"url": "/static/logo.png",
}
],
pageData: {},
pageOption: {}
}
},
onLoad(o) {
this.pageOption = o
this.init()
updateChatStatus({
id: o.id,
})
},
methods: {
updateFeedBackStatus(status) {
updateFeedBackStatus({
id: this.pageOption.id,
status: status
}).then(res => {
this.init()
})
},
init() {
this.loading = true
queryFeedBackDetail(this.pageOption.id).then(res => {
// 反转数组
res.data.csFeedbackChatPOList.reverse()
this.pageData = res.data
this.imageValue = res.data.imageUrls.map(item => {
return {
"name": item,
"extname": item.split('.')[1],
"url": this.$config.static + item,
}
})
this.loading = false
console.log(res);
})
},
dialogInputConfirm() {
AddFeedbackChat({chatContent: this.chatContent, id: this.pageOption.id}).then(res => {
console.log(res);
this.$util.toast('回复成功')
this.init()
this.chatContent = ''
})
},
open() {
this.$refs.inputDialog.open()
},
over() {
},
close() {
},
}
}
</script>
<style lang='scss'>
.detail {
padding: 0 0 20rpx;
.detail-content {
padding: 20rpx 30rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 32rpx;
color: #111;
font-weight: 700;
display: flex;
justify-content: space-between;
.title {
flex: 1;
}
.title-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
}
}
}
<template>
<Cn-page :loading='loading'>
<view slot='body'>
<view class='detail'>
<view class="detail-content ">
<view class="detail-content-title mb20">{{ pageData.title }}</view>
<view> {{ pageData.createTime }}</view>
<view class="mt10 mb10">{{ pageData.description }}</view>
<uni-file-picker readonly v-model="imageValue" mode="grid"/>
</view>
<view class="detail-content " style="margin-bottom:0">
<view class="detail-content-title ">
<view class="title">进度</view>
<!-- <template v-if="pageData.status === '1'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('2')">解决</view>-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>-->
<!-- <template v-if="pageData.status === '2'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>-->
<!-- <view class="title-btn" @click="open">回复</view>-->
</view>
</view>
<uni-list>
<uni-list-item :title="item.userName" :note="item.chatContent" :rightText="item.createTime"
v-for="(item, index) in pageData.csFeedbackChatPOList" :key="index"/>
<Cn-empty
v-if="pageData.csFeedbackChatPOList && pageData.csFeedbackChatPOList.length == 0"></Cn-empty>
</uni-list>
<!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog ref="inputClose" type="info" mode="input" title="输入内容"
value="对话框预置提示内容!"
placeholder="请输入内容" @confirm="dialogInputConfirm">
<uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="chatContent"
placeholder="请输入内容"></uni-easyinput>
</uni-popup-dialog>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import {queryFeedBackDetail, AddFeedbackChat, updateChatStatus, updateFeedBackStatus} from '../../common/api/feedback'
export default {
data() {
return {
loading: false,
chatContent: "",
imageValue: [
{
"name": "file.png",
"extname": "png",
"url": "/static/logo.png",
}
],
pageData: {},
pageOption: {}
}
},
onLoad(o) {
this.pageOption = o
this.init()
updateChatStatus({
id: o.id,
})
},
methods: {
updateFeedBackStatus(status) {
updateFeedBackStatus({
id: this.pageOption.id,
status: status
}).then(res => {
this.init()
})
},
init() {
this.loading = true
queryFeedBackDetail(this.pageOption.id).then(res => {
// 反转数组
res.data.csFeedbackChatPOList.reverse()
this.pageData = res.data
this.imageValue = res.data.imageUrls.map(item => {
return {
"name": item,
"extname": item.split('.')[1],
"url": this.$config.static + item,
}
})
this.loading = false
console.log(res);
})
},
dialogInputConfirm() {
AddFeedbackChat({chatContent: this.chatContent, id: this.pageOption.id}).then(res => {
console.log(res);
this.$util.toast('回复成功')
this.init()
this.chatContent = ''
})
},
open() {
this.$refs.inputDialog.open()
},
over() {
},
close() {
},
}
}
</script>
<style lang='scss'>
.detail {
padding: 0 0 20rpx;
.detail-content {
padding: 20rpx 30rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 28rpx;
color: #111;
font-weight: 700;
display: flex;
justify-content: space-between;
.title {
flex: 1;
}
.title-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
}
}
}
</style>

View File

@@ -28,7 +28,7 @@
>
<!-- <view class="content-item-header-right-des">{{ item.subTitle }}</view> -->
</view>
<view class="ml10" v-if="type === '0' || item.status != '1'">🔍</view>
<view class="ml10" v-if="type === '0' || item.status != '1'"> <uni-icons type="search" size="25"></uni-icons></view>
</view>
<view class="content-item-footer">{{ item.subTitle }}</view>
</view>

View File

@@ -82,7 +82,7 @@ export default {
font-size: 26rpx;
.detail-content-title {
font-size: 32rpx;
font-size: 28rpx;
color: #111;
font-weight: 700;
}

View File

@@ -3,7 +3,14 @@
<!-- 运行告警 -->
<!-- 卡片 -->
<view class="event-list" :style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
@@ -19,7 +26,7 @@
<uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="22"
size="30"
color="#FF0000"
></uni-icons>
<view class="badge1" v-if="item.isRead == 0"> </view>
@@ -29,7 +36,7 @@
<text class="event-id">{{ item.date }}发生告警终端{{ item.warnNums }}</text>
</view>
</view>
<view class="event-action"> 🔍 </view>
<view class="event-action"> <uni-icons type="search" size="25"></uni-icons> </view>
</view>
</uni-card>
<uni-load-more
@@ -37,7 +44,7 @@
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</view>
</scroll-view>
</view>
</template>
<script>
@@ -57,6 +64,7 @@ export default {
mixins: [list],
data() {
return {
triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后
}
},
@@ -74,6 +82,7 @@ export default {
this.store.loadedCallback = () => {
this.loading = false
}
this.store.reload()
},
jump(item) {
@@ -81,6 +90,14 @@ export default {
item.status = '1'
uni.navigateTo({ url: '/pages/message1/comp/alarmDetails?detail=' + encodeURIComponent(str) })
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
computed: {},
@@ -123,4 +140,7 @@ export default {
flex: 1;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -13,6 +13,9 @@ export default {
store: {
type: [Object],
},
filterValue: {
type: [String],
},
},
data() {
return {
@@ -52,9 +55,10 @@ export default {
xAxis: {
type: 'value',
splitNumber: 10,
minInterval: 3,
minInterval: 20,
position: 'top',
rotate: 90,
max: 140,
axisLabel: {
rotate: -90,
},
@@ -103,6 +107,7 @@ export default {
pointF: [],
pointFun: [],
data: [],
maxXAxis: 140,
}
},
mounted() {
@@ -129,6 +134,7 @@ export default {
this.pointF = []
this.pointFun = []
var total = 0
let dataList = [0]
total = this.data.length
if (total == 0) {
} else {
@@ -137,7 +143,7 @@ export default {
var xx = this.data[i].evtParamTm.replace(/s/g, '')
var yy = this.data[i].evtParamVVaDepth.replace(/%/g, '')
var time = this.data[i].startTime.replace('T', ' ')
dataList.push(yy)
point = [yy, xx, time, this.data[i]]
if (xx < 0.05) {
@@ -191,6 +197,20 @@ export default {
}
}
}
this.option.xAxis.max = Math.max(
140,
Math.ceil(
Math.max(
...dataList
.filter((item) => {
return item !== '-' && !isNaN(Number(item))
})
.map((item) => Number(item)),
) / 10,
) * 10,
) //this.maxXAxis
this.option.series[1].data = this.pointF
this.option.series[2].data = this.pointFun
@@ -204,7 +224,6 @@ export default {
bindChartClickEvent() {
if (!this.echartRef) return
this.echartRef.on('click', (params) => {
console.log('🚀 ~ params:', params.value[3])
// 点击查看详情
let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比')
@@ -219,12 +238,20 @@ export default {
store: {
handler(val, oldVal) {
this.status = val.status
this.data = val.data
this.data = (val.data || []).filter((k) =>
this.filterValue == '' ? k : k.showName == this.filterValue,
)
this.gongfunction()
},
deep: true,
immediate: true,
},
filterValue: {
handler(val, oldVal) {
this.data = (this.store.data || []).filter((k) => (val == '' ? k : k.showName == val))
this.gongfunction()
},
},
},
}
</script>

View File

@@ -13,6 +13,9 @@ export default {
store: {
type: [Object],
},
filterValue: {
type: [String],
},
},
data() {
return {
@@ -35,7 +38,7 @@ export default {
itemWidth: 10,
itemHeight: 10,
itemGap: 8,
padding: [5, 5 ,5 ,10],
padding: [5, 5, 5, 10],
},
color: ['#FF8C00', '#00BFFF', 'green', 'red'],
@@ -141,108 +144,6 @@ export default {
}
},
// gongfunction() {
// var standI = 0
// var unstandI = 0
// this.pointI = []
// this.pointIun = []
// var total = 0
// total = this.data.length
// if (total == 0) {
// } else {
// for (var i = 0; i < this.data.length; i++) {
// var point = []
// var xx = this.data[i].evtParamTm.replace(/s/g, '')
// var yy = this.data[i].evtParamVVaDepth.replace(/%/g, '')
// var time = this.data[i].startTime.replace('T', ' ')
// point = [yy, xx, time, this.data[i]]
// if (xx <= 0.003) {
// var line = 0
// line = 230 - 30000 * xx
// if (yy > line) {
// unstandI++
// this.pointIun.push({
// value: point,
// itemStyle: { normal: { color: 'red' } },
// })
// } else {
// standI++
// this.pointI.push({
// value: point,
// itemStyle: { normal: { color: 'green' } },
// })
// }
// } else if (xx <= 0.02) {
// if (yy > 120) {
// unstandI++
// this.pointIun.push({
// value: point,
// itemStyle: { normal: { color: 'red' } },
// })
// } else {
// standI++
// this.pointI.push({
// value: point,
// itemStyle: { normal: { color: 'green' } },
// })
// }
// } else if (xx <= 0.5) {
// if (yy > 120 || yy < 70) {
// unstandI++
// this.pointIun.push({
// value: point,
// itemStyle: { normal: { color: 'red' } },
// })
// } else {
// standI++
// this.pointI.push({
// value: point,
// itemStyle: { normal: { color: 'green' } },
// })
// }
// } else if (xx <= 10) {
// if (yy > 110 || yy < 80) {
// unstandI++
// this.pointIun.push({
// value: point,
// itemStyle: { normal: { color: 'red' } },
// })
// } else {
// standI++
// this.pointI.push({
// value: point,
// itemStyle: { normal: { color: 'green' } },
// })
// }
// } else {
// if (yy > 110 || yy < 90) {
// unstandI++
// this.pointIun.push({
// value: point,
// itemStyle: { normal: { color: 'red' } },
// })
// } else {
// standI++
// this.pointI.push({
// value: point,
// itemStyle: { normal: { color: 'green' } },
// })
// }
// }
// }
// }
// this.option.series[2].data = this.pointI
// this.option.series[3].data = this.pointIun
// if (this.echartRef) {
// this.echartRef.setOption(this.option, true)
// } else {
// this.initChart()
// }
// },
gongfunction() {
// 初始化计数与数据数组
let normalCount = 0
@@ -329,12 +230,20 @@ export default {
store: {
handler(val, oldVal) {
this.status = val.status
this.data = val.data
this.data = (val.data || []).filter((k) =>
this.filterValue == '' ? k : k.showName == this.filterValue,
)
this.gongfunction()
},
deep: true,
immediate: true,
},
filterValue: {
handler(val, oldVal) {
this.data = (this.store.data || []).filter((k) => (val == '' ? k : k.showName == val))
this.gongfunction()
},
},
},
}
</script>

View File

@@ -5,10 +5,10 @@
<!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.date }}</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">终端告警列表</view>
<view class="detail-content" style="padding: 0px">
<view class="detail-content-title mb20 pt20 pl20">终端告警列表</view>
<uni-collapse accordion>
<!-- <uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.devName" v-for="item in list">
<template v-slot:title>
<view class="collapseTop">
@@ -27,7 +27,6 @@
<view class="mb10 ml12 frequency">
<view>工程名称{{ item.engineeringName }}</view></view
>
<view class="mb10 ml12 frequency">
<view>通讯信息</view>
<view style="flex: 1">
@@ -50,7 +49,61 @@
>
</view>
</uni-collapse-item>
</uni-collapse>
</uni-collapse> -->
<view class="event-list">
<uni-card
class="event-item"
:class="item.type"
v-for="(item, index) in list"
:key="index"
@click="jump(item)"
>
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="35"
color="#FF0000"
></uni-icons>
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.devName }}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<!-- <text>事件时间{{ item.startTime }}</text> -->
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<uni-collapse accordion>
<uni-collapse-item
:title="
item.interruptCounts == 0 ? '通讯正常' : `通讯中断 ${item.interruptCounts} 次`
"
>
<view v-for="date in item.interruptDetails" class="textBox mb10">{{ date }}</view>
</uni-collapse-item>
<uni-collapse-item
:title="
item.warnCounts == 0 ? '暂无终端告警信息' : `终端告警 ${item.warnCounts} 次`
"
>
<view v-for="val in item.warnDetails" class="textBox mb10">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view>
</uni-collapse-item>
</uni-collapse>
</view>
</uni-card>
</view>
</view>
</view>
</Cn-page>
@@ -64,13 +117,13 @@ export default {
loading: true,
detail: {},
limit: '',
accordionVal: '1',
collapseValue: '0',
list: [],
}
},
onLoad(options) {
this.loading = false
this.loading = true
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.init()
if (this.detail.isRead != 1) {
@@ -81,7 +134,6 @@ export default {
},
methods: {
init() {
this.loading = false
queryAlarmDetail({
devList: this.detail.devIds,
time: this.detail.date,
@@ -97,7 +149,8 @@ export default {
},
}
</script>
<style lang="scss">
<style lang="scss" scoped>
@import '../index.scss';
.detail {
padding: 20rpx 0;
@@ -105,10 +158,10 @@ export default {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 32rpx;
font-size: 30rpx;
color: #111;
font-weight: 700;
}
@@ -117,18 +170,38 @@ export default {
padding: 10rpx 0;
margin-left: 15px;
.name {
font-size: 26rpx;
font-size: 28rpx;
font-weight: 700;
color: #333333;
}
}
.frequency {
display: flex;
font-size: 24rpx;
font-size: 26rpx;
// color: #666666;
}
}
.textBox {
border-bottom: 1px solid #eee;
font-size: 26rpx;
color: #666666;
}
.event-list {
background: #fff;
.event-icon {
width: 90rpx;
height: 90rpx;
background-color: #ff000020;
}
}
/deep/ .uni-collapse-item__title-box {
padding: 0 15px 0 0;
height: 56rpx;
line-height: 56rpx;
font-size: 26rpx !important;
color: #666666;
span {
font-size: 26rpx !important;
}
}
</style>

View File

@@ -1,15 +1,23 @@
<template>
<view class="preview-container">
<!-- 右上角关闭按钮 -->
<view class="close-btn" @click="close">
<text class="close-icon"></text>
<!-- 右上角按钮 -->
<view class="btn-group">
<!-- 缩小按钮 -->
<!-- <view class="btn zoom-out-btn" @click="zoomOut">
<text class="btn-icon"></text>
</view> -->
<!-- 放大按钮 -->
<!-- <view class="btn zoom-in-btn" @click="zoomIn">
<text class="btn-icon">+</text>
</view> -->
<!-- 下载按钮 -->
<view class="btn download-btn" @click="downloadImage">
<text class="btn-icon"></text>
</view>
</view>
<!-- 下载按钮 -->
<view class="download-btn" @click="downloadImage">
<text class="download-icon"></text>
</view>
<!-- 图片预览区域使用movable-area和movable-view实现缩放移动 -->
<movable-area class="movable-area" :style="{ width: '100vw', height: '100vh' }">
<movable-view
@@ -19,21 +27,25 @@
:scale-min="0.5"
:scale-max="3"
:scale-value="scaleValue"
@scale="onScale"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
:x="x"
:y="y"
:animation="true"
:animation-duration="300"
:style="{
width: rotatedWidth + 'px',
height: rotatedHeight + 'px'
height: rotatedHeight + 'px',
}"
>
<view
<view
class="image-wrapper"
:style="{
width: imgWidth + 'px',
height: imgHeight + 'px',
transform: 'rotate(90deg)',
transformOrigin: 'center center'
transformOrigin: 'center center',
}"
>
<image
@@ -42,7 +54,7 @@
mode="aspectFill"
:style="{
width: imgWidth + 'px',
height: imgHeight + 'px'
height: imgHeight + 'px',
}"
@load="onImageLoad"
></image>
@@ -50,10 +62,7 @@
</movable-view>
</movable-area>
<!-- 图片信息提示 -->
<view class="scale-tip" v-if="showScaleTip">
当前缩放: {{ Math.round(scaleValue * 100) }}%
</view>
</view>
</template>
@@ -62,12 +71,12 @@ export default {
onLoad(options) {
this.imageUrl = decodeURIComponent(options.url) // 接收传递的图片URL需要解码
},
data() {
return {
imageUrl: '',
// 缩放相关
scaleValue: 1,
// 缩放相关 - 默认0.5
scaleValue: 0.6,
x: 0,
y: 0,
// 图片原始尺寸
@@ -81,70 +90,132 @@ export default {
tipTimer: null,
// 屏幕尺寸
windowWidth: 0,
windowHeight: 0
windowHeight: 0,
// 缩放步长
zoomStep: 0.2,
// 动画控制
isTouching: false,
animationTimer: null
}
},
mounted() {
// 获取屏幕尺寸
const systemInfo = uni.getSystemInfoSync();
this.windowWidth = systemInfo.windowWidth;
this.windowHeight = systemInfo.windowHeight;
const systemInfo = uni.getSystemInfoSync()
this.windowWidth = systemInfo.windowWidth
this.windowHeight = systemInfo.windowHeight
},
methods: {
// 图片加载完成后获取尺寸
onImageLoad(e) {
const { width, height } = e.detail;
const { width, height } = e.detail
// 保存原始尺寸
this.imgWidth = width;
this.imgHeight = height;
this.imgWidth = width
this.imgHeight = height
// 旋转90度后宽度和高度互换
this.rotatedWidth = height; // 旋转后宽度 = 原高度
this.rotatedHeight = width; // 旋转后高度 = 原宽度
// 计算初始位置居中
this.resetPosition();
console.log('图片加载:', {width, height}, '旋转后:', {rotatedWidth: this.rotatedWidth, rotatedHeight: this.rotatedHeight});
this.rotatedWidth = height // 旋转后宽度 = 原高度
this.rotatedHeight = width // 旋转后高度 = 原宽度
// 计算初始位置居中考虑0.5缩放)
this.resetPosition()
},
// 重置位置到中心
// 重置位置到中心(考虑当前缩放比例)
resetPosition() {
// 计算居中的偏移量
this.x = (this.windowWidth - this.rotatedWidth) / 2;
this.y = (this.windowHeight - this.rotatedHeight) / 2;
console.log('重置位置:', {x: this.x, y: this.y, windowWidth: this.windowWidth, windowHeight: this.windowHeight});
// 计算居中的偏移量,考虑缩放比例
const displayWidth = this.rotatedWidth * this.scaleValue
const displayHeight = this.rotatedHeight * this.scaleValue
this.x = (this.windowWidth - displayWidth) / 2
this.y = (this.windowHeight - displayHeight) / 2
},
// 触摸开始
onTouchStart() {
this.isTouching = true
},
// 触摸结束
onTouchEnd() {
this.isTouching = false
},
// 缩放事件处理
onScale(e) {
this.scaleValue = e.detail.scale;
this.scaleValue = e.detail.scale
// 显示缩放提示
this.showScaleTip = true;
this.showScaleTip = true
if (this.tipTimer) {
clearTimeout(this.tipTimer);
clearTimeout(this.tipTimer)
}
this.tipTimer = setTimeout(() => {
this.showScaleTip = false;
}, 1500);
this.showScaleTip = false
}, 1500)
},
// 关闭预览
close() {
uni.navigateBack();
// 放大
zoomIn() {
// 计算新的缩放值,不超过最大值
const newScale = Math.min(this.scaleValue + this.zoomStep, 3)
this.setScaleWithAnimation(newScale)
},
// 缩小
zoomOut() {
// 计算新的缩放值,不低于最小值
const newScale = Math.max(this.scaleValue - this.zoomStep, 0.5)
this.setScaleWithAnimation(newScale)
},
// 带动画的设置缩放值
setScaleWithAnimation(newScale) {
// 保存旧的缩放值用于动画
const oldScale = this.scaleValue
// 计算缩放中心点(屏幕中心)
const centerX = this.windowWidth / 2
const centerY = this.windowHeight / 2
// 计算当前图片中心点
const oldDisplayWidth = this.rotatedWidth * oldScale
const oldDisplayHeight = this.rotatedHeight * oldScale
const oldCenterX = this.x + oldDisplayWidth / 2
const oldCenterY = this.y + oldDisplayHeight / 2
// 计算偏移量,使缩放后图片中心保持在屏幕中心
const newDisplayWidth = this.rotatedWidth * newScale
const newDisplayHeight = this.rotatedHeight * newScale
const newX = centerX - newDisplayWidth / 2
const newY = centerY - newDisplayHeight / 2
// 更新缩放值和位置
this.scaleValue = newScale
this.x = newX
this.y = newY
// 显示缩放提示
this.showScaleTip = true
if (this.tipTimer) {
clearTimeout(this.tipTimer)
}
this.tipTimer = setTimeout(() => {
this.showScaleTip = false
}, 1500)
console.log('缩放:', {oldScale, newScale, x: this.x, y: this.y})
},
// 下载图片
downloadImage() {
uni.showLoading({
title: '下载中...'
});
title: '下载中,请稍等...',
mask: true,
})
// 先获取图片信息(如果是网络图片需要先下载)
uni.downloadFile({
url: this.imageUrl,
@@ -154,16 +225,16 @@ export default {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.hideLoading();
uni.hideLoading()
uni.showToast({
title: '保存成功',
icon: 'success'
});
icon: 'success',
})
},
fail: (err) => {
uni.hideLoading();
console.error('保存失败', err);
uni.hideLoading()
console.error('保存失败', err)
// 处理用户拒绝权限的情况
if (err.errMsg.includes('auth deny')) {
uni.showModal({
@@ -173,52 +244,49 @@ export default {
if (res.confirm) {
uni.openSetting({
success: (settingRes) => {
console.log('打开设置页面', settingRes);
}
});
console.log('打开设置页面', settingRes)
},
})
}
}
});
},
})
} else {
uni.showToast({
title: '保存失败',
icon: 'none'
});
icon: 'none',
})
}
}
});
},
})
} else {
uni.hideLoading();
uni.hideLoading()
uni.showToast({
title: '下载失败',
icon: 'none'
});
icon: 'none',
})
}
},
fail: (err) => {
uni.hideLoading();
console.error('下载失败', err);
uni.hideLoading()
console.error('下载失败', err)
uni.showToast({
title: '下载失败',
icon: 'none'
});
}
});
icon: 'none',
})
},
})
},
// 双击重置缩放和位置(可选功能)
onDoubleTap() {
this.scaleValue = 1;
this.resetPosition();
}
},
// 页面返回前清理定时器
onUnload() {
if (this.tipTimer) {
clearTimeout(this.tipTimer);
clearTimeout(this.tipTimer)
}
}
if (this.animationTimer) {
cancelAnimationFrame(this.animationTimer)
}
},
}
</script>
@@ -241,62 +309,89 @@ export default {
display: flex;
align-items: center;
justify-content: center;
// 添加硬件加速
transform: translateZ(0);
will-change: transform;
}
.image-wrapper {
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.1s ease;
// 添加硬件加速
transform: translateZ(0) rotate(90deg);
will-change: transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.preview-img {
display: block;
// 添加硬件加速
transform: translateZ(0);
will-change: transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
// 关闭按钮
.close-btn {
// 按钮
.btn-group {
position: fixed;
top: 30rpx;
right: 30rpx;
width: 60rpx;
height: 60rpx;
display: flex;
flex-direction: row;
gap: 20rpx;
z-index: 1000;
}
// 通用按钮样式
.btn {
width: 70rpx;
height: 70rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
// 按钮不参与动画
transform: translateZ(0);
transition: background-color 0.2s ease;
.close-icon {
&:active {
background: rgba(0, 0, 0, 0.8);
transform: scale(0.95);
}
.btn-icon {
color: #fff;
font-size: 40rpx;
line-height: 1;
font-weight: bold;
}
}
// 缩小按钮
.zoom-out-btn {
.btn-icon {
font-size: 50rpx;
}
}
// 放大按钮
.zoom-in-btn {
.btn-icon {
font-size: 40rpx;
}
}
// 下载按钮
.download-btn {
position: fixed;
top: 30rpx;
right: 110rpx;
width: 60rpx;
height: 60rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
.download-icon {
color: #fff;
font-size: 40rpx;
line-height: 1;
.btn-icon {
font-size: 35rpx;
}
}
@@ -305,7 +400,7 @@ export default {
position: fixed;
bottom: 100rpx;
left: 50%;
transform: translateX(-50%);
transform: translateX(-50%) translateZ(0);
background: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 10rpx 30rpx;
@@ -315,12 +410,22 @@ export default {
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
animation: fadeInOut 1.5s ease;
// 提示不参与动画
will-change: opacity;
}
@keyframes fadeInOut {
0% { opacity: 0; }
15% { opacity: 1; }
85% { opacity: 1; }
100% { opacity: 0; }
0% {
opacity: 0;
}
15% {
opacity: 1;
}
85% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

View File

@@ -21,7 +21,7 @@
>指标越限详情<text class="prompt">仅显示较为严重的10次</text></view
>
<uni-collapse accordion>
<uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.targetName" v-for="item in list">
<view class="data-table">
<view class="table-header">
@@ -57,6 +57,7 @@ export default {
loading: true,
detail: {},
list: [],
collapseValue: '0',
}
},
onLoad(options) {
@@ -96,10 +97,10 @@ export default {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 32rpx;
font-size: 30rpx;
color: #111;
font-weight: 700;
}
@@ -130,7 +131,7 @@ export default {
text {
flex: 1;
text-align: center;
font-size: 24rpx;
font-size: 26rpx;
// color: #333;
&:first-child {
// text-align: left;
@@ -139,10 +140,14 @@ export default {
}
}
.table-header {
padding: 0rpx;
padding: 0rpx;
padding-bottom: 10rpx;
}
}
/deep/ .uni-collapse-item__title-text{
font-weight: 700;
/deep/ .uni-collapse-item__title-text {
font-weight: 700;
span {
font-size: 28rpx;
}
}
</style>

View File

@@ -83,10 +83,10 @@ export default {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 32rpx;
font-size: 30rpx;
color: #111;
font-weight: 700;
}

View File

@@ -17,6 +17,8 @@
/* 第一个盒子的特殊样式(蓝色背景) */
.box:first-child {
flex: 1.7;
}
.boxClick {
background-color: $uni-theme-color;
color: #ffffff;
}
@@ -83,7 +85,13 @@
background-color: #e6a23c20;
}
.interrupt .event-icon {
background-color: #90939920;
background-color: #00000020;
}
.transient .event-icon {
background-color: #8b5cf620;
}
.unknown .event-icon {
background-color: #6b728020;
}
.event-icon image {
width: 48rpx;
@@ -101,7 +109,7 @@
flex-wrap: wrap; /* 适配小屏,防止文字溢出 */
}
.event-id {
font-size: 15px;
font-size: 28rpx;
font-weight: 700;
color: #333333;
margin-right: 16rpx;
@@ -115,16 +123,24 @@
height: 38rpx;
}
.sag-tag {
background-color: #ecf5ff;
background-color: #2563eb20;
color: #2563eb;
}
.swell-tag {
background-color: #fdf6ec;
background-color: #e6a23c20;
color: #e6a23c;
}
.interrupt-tag {
background-color: #f4f4f5;
color: #909399;
background-color: #6b728020;
color: #6b7280;
}
.transient-tag {
background-color: #8b5cf620;
color: #8b5cf6;
}
.unknown-tag {
background-color: #6b728020;
color: #6b7280;
}
/* 描述文本 */
.event-desc {
@@ -155,7 +171,7 @@
/* 详情文本 */
.event-detail {
font-size: 24rpx;
font-size: 26rpx;
color: #666666;
line-height: 1.5;
padding-top: 10rpx;
@@ -174,7 +190,6 @@
height: 58rpx;
}
.uni-input {
font-size: 24rpx;
color: #2563eb;
margin-right: 10rpx;

View File

@@ -3,8 +3,14 @@
<!-- 运行事件 -->
<!-- 卡片 -->
<view
class="event-list" :style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
@@ -17,7 +23,7 @@
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<uni-icons custom-prefix="iconfont" type="icon-shebei" size="30" color="#10B981"></uni-icons>
<uni-icons custom-prefix="iconfont" type="icon-shebei" size="35" color="#10B981"></uni-icons>
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
@@ -27,12 +33,13 @@
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>事件时间{{ item.startTime }}</text>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text> {{ item.startTime }}发生{{ item.showName }} </text>
<text> {{ item.showName }} </text>
</view>
</uni-card>
<uni-load-more
@@ -40,7 +47,7 @@
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</view>
</scroll-view>
</view>
</template>
<script>
@@ -60,7 +67,9 @@ export default {
},
mixins: [list],
data() {
return {}
return {
triggered: true,
}
},
mounted() {},
@@ -91,6 +100,14 @@ export default {
this.$emit('getDevCount')
}
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
computed: {},
@@ -118,10 +135,13 @@ export default {
/* 图标区域(按类型区分背景色) */
.event-icon {
width: 90rpx;
height: 90rpx;
// width: 90rpx;
// height: 90rpx;
background-color: #10b98120;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -3,15 +3,21 @@
<!-- 稳态 -->
<view class="transientBox">
<view class="statistics pd20">
<view class="box" v-for="item in list">
<view class="box" :class="{ boxClick: item.label == '稳态数量' }" v-for="item in list">
<text class="num">{{ item.value }}</text>
<text class="label">{{ item.label }}</text>
</view>
</view>
</view>
<!-- 卡片 -->
<view
class="event-list" :style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }">
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
@@ -40,14 +46,16 @@
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>设备名称{{ item.devName }}</text>
<text>统计日期{{ item.statisticsDate }}</text>
<!-- <text>统计日期{{ item.statisticsDate }}</text> -->
</view>
</view>
<view class="event-action"> 🔍 </view>
<view class="event-action">
<uni-icons type="search" size="25"></uni-icons>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text> {{ item.overLimitDesc }} </text>
<text>{{ item.statisticsDate }}发生 {{ item.overLimitDesc }} </text>
</view>
</uni-card>
@@ -56,7 +64,7 @@
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</view>
</scroll-view>
</view>
</template>
<script>
@@ -82,6 +90,7 @@ export default {
{ value: 0, label: '越限天数' },
{ value: 0, label: '越限测点数' },
],
triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后
}
},
@@ -130,6 +139,14 @@ export default {
uni.navigateTo({ url: '/pages/message1/comp/steadyStateDetails?detail=' + encodeURIComponent(str) })
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
computed: {},
@@ -171,4 +188,7 @@ export default {
font-size: 24rpx;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -3,7 +3,12 @@
<!-- 暂态 -->
<view class="transientBox">
<view class="statistics pd20">
<view class="box" v-for="item in list" @click="filterValue = item.key">
<view
class="box"
:class="{ boxClick: filterValue == item.key }"
v-for="item in list"
@click="filterValue = item.key"
>
<!-- <text class="num">{{ item.value }}</text> -->
<text class="num">{{
store &&
@@ -37,7 +42,11 @@
</view>
</view>
<!-- 卡片 -->
<view
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
v-if="curSub == 0"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
@@ -45,7 +54,7 @@
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
:class="judgment(item.showName)"
:class="judgment(item.showName).type"
v-for="(item, index) in (store.data || []).filter((k) =>
filterValue == '' ? k : k.showName == filterValue,
)"
@@ -57,22 +66,10 @@
<view class="event-icon">
<!-- 动态图标:根据类型切换 -->
<uni-icons
:custom-prefix="judgment(item.showName) == 'interrupt' ? 'custom-icon' : 'iconfont'"
:type="
judgment(item.showName) == 'sag'
? 'icon-xiajiang'
: judgment(item.showName) == 'swell'
? 'icon-shangsheng'
: 'minus'
"
:color="
judgment(item.showName) == 'sag'
? '#2563eb '
: judgment(item.showName) == 'swell'
? '#e6a23c'
: '#909399'
"
:size="judgment(item.showName) == 'interrupt' ? '50' : '25'"
:custom-prefix="'iconfont'"
:type="judgment(item.showName).icon"
:color="judgment(item.showName).color"
:size="judgment(item.showName).size"
></uni-icons>
<!-- 0未读 1已读 -->
<view class="badge1" v-if="item.status == 0"> </view>
@@ -80,7 +77,9 @@
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.equipmentName }}</text>
<text class="event-tag" :class="`${judgment(item.showName)}-tag`">{{ item.showName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName
}}</text>
</view>
<view class="event-desc">
<text>工程名称:{{ item.engineeringName }}</text>
@@ -88,7 +87,7 @@
<text>监测点名称:{{ item.lineName }}</text>
</view>
</view>
<view class="event-action"> 🔍 </view>
<view class="event-action"> <uni-icons type="search" size="25" color="#376cf3"></uni-icons> </view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
@@ -104,17 +103,19 @@
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</view>
</scroll-view>
<!-- ITIC 列表 -->
<ITIC
v-if="subsectionList[curSub] == 'ITIC'"
:store="store"
:filterValue="filterValue"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
></ITIC>
<!-- F47 列表 -->
<F47
v-if="subsectionList[curSub] == 'F47'"
:store="store"
:filterValue="filterValue"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
></F47>
</view>
@@ -124,6 +125,7 @@ import list from '@/common/js/list'
import { queryUserPushConfig } from '@/common/api/mine'
import ITIC from './comp/ITIC.vue'
import F47 from './comp/F47.vue'
export default {
components: { ITIC, F47 },
props: {
@@ -151,12 +153,14 @@ export default {
subsectionList: [], //'列表', 'ITIC', 'F47'
status: 'noMore', //more加载前 loading加载中 noMore加载后
sort: 0,
triggered: true,
// config: {},
array: ['发生时间', '暂降深度', '持续时间'],
}
},
mounted() {
this.getConfig()
uni.createSelectorQuery()
.select('.transientBox')
.boundingClientRect((rect) => {
@@ -185,7 +189,6 @@ export default {
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {
this.getConfig()
this.filterValue = ''
this.loading = false
}
@@ -194,25 +197,56 @@ export default {
getConfig() {
queryUserPushConfig().then((res) => {
// this.config = res.data
this.subsectionList = [
let list = [
'列表',
res.data.iticFunction == 1 ? 'ITIC' : '',
res.data.f47Function == 1 ? 'F47' : '',
].filter((item) => item)
this.curSub = !list[this.curSub] ? 0 : this.curSub
this.subsectionList = JSON.parse(JSON.stringify(list))
})
},
judgment(val) {
judgment(val, key) {
switch (val) {
case '电压暂降':
return 'sag'
return {
type: 'sag',
icon: 'icon-a-svg4',
color: '#2563eb',
size: '25',
}
case '电压暂升':
return 'swell'
return {
type: 'swell',
icon: 'icon-a-svg5',
color: '#e6a23c',
size: '25',
}
case '电压中断':
return 'interrupt'
return {
type: 'interrupt',
icon: 'icon-zhongduan2',
color: '#6b7280',
size: '35',
}
case '瞬态':
return {
type: 'transient',
icon: 'icon-shuntaishijian',
color: '#8b5cf6',
size: '40',
}
case '未知':
return {
type: 'unknown',
icon: 'icon-wenhao',
color: '#6b7280',
size: '45',
}
}
},
// 点击查看详情
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
@@ -227,6 +261,14 @@ export default {
sectionChange(e) {
this.curSub = e.currentIndex
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
onShow() {
this.curSub = 0
@@ -248,4 +290,8 @@ export default {
<style lang="scss" scoped>
@import './index.scss';
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -1,123 +1,123 @@
<template>
<Cn-page :loading="loading">
<view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx">
<view class="mine-nav-label">功能调试</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('feature')"
:checked="config.feature"
/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">出厂调试</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('factory')"
:checked="config.factory"
/>
</view>
</view>
</Cn-page>
</template>
<script>
export default {
data() {
return {
loading: true,
config: {
feature: true,
factory: true,
},
}
},
methods: {
init() {
let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig)
serverConfig && (this.config = serverConfig)
this.loading = false
},
change(type) {
this.config[type] = !this.config[type]
let str = ''
switch (type) {
case 'feature':
str = '功能调试'
break
case 'factory':
str = '出厂调试'
break
}
this.$util.toast(`${str}首页入口${this.config[type] ? '开启' : '关闭'}`, 2500)
uni.setStorage({
key: this.$cacheKey.serverConfig,
data: this.config,
})
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.mine {
.title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
}
.mine-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.mine-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
}
}
.mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>
<template>
<Cn-page :loading="loading">
<view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx">
<view class="mine-nav-label">功能调试</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('feature')"
:checked="config.feature"
/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">出厂调试</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('factory')"
:checked="config.factory"
/>
</view>
</view>
</Cn-page>
</template>
<script>
export default {
data() {
return {
loading: true,
config: {
feature: true,
factory: true,
},
}
},
methods: {
init() {
let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig)
serverConfig && (this.config = serverConfig)
this.loading = false
},
change(type) {
this.config[type] = !this.config[type]
let str = ''
switch (type) {
case 'feature':
str = '功能调试'
break
case 'factory':
str = '出厂调试'
break
}
this.$util.toast(`${str}首页入口${this.config[type] ? '开启' : '关闭'}`, 2500)
uni.setStorage({
key: this.$cacheKey.serverConfig,
data: this.config,
})
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.mine {
.title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
}
.mine-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.mine-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
}
}
.mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>

View File

@@ -1,147 +1,170 @@
<template>
<Cn-page :loading="loading">
<view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx">
<view class="mine-nav-label">运行事件</view>
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('runInfo')" :checked="config.runInfo === 1"/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">暂态事件</view>
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('eventInfo')" :checked="config.eventInfo === 1"/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">稳态事件</view>
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('harmonicInfo')" :checked="config.harmonicInfo === 1"/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">设备告警</view>
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('alarmInfo')" :checked="config.alarmInfo === 1"/>
</view>
</view>
</Cn-page>
</template>
<script>
import {queryUserPushConfig, updatePushConfig} from '@/common/api/mine'
export default {
data() {
return {
loading: true,
config: {},
}
},
methods: {
init() {
queryUserPushConfig().then(res => {
console.log(123123,res);
this.config = res.data
console.log(this.config)
this.loading = false
})
},
change(type) {
this.config[type] = this.config[type] === 1 ? 0 : 1
updatePushConfig(this.config).then(res => {
let str = ''
switch (type){
case 'runInfo':
str = '运行事件'
break
case 'eventInfo':
str = '暂态事件'
break
case 'harmonicInfo':
str = '稳态事件'
break
case 'alarmInfo':
str = '设备告警'
break
}
this.$util.toast(`${str}推送${this.config[type] === 1 ? '开启' : '关闭'}成功`)
})
},
jump(type) {
switch (type) {
case 'changePwd':
uni.navigateTo({
url: `/pages/user/changePwd`,
})
break
case 'changePhone':
uni.navigateTo({
url: `/pages/user/changePhone`,
})
break
default:
uni.navigateTo({
url: `/pages/mine/${type}`,
})
break
}
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.mine {
.title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
}
.mine-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.mine-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
}
}
.mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>
<template>
<Cn-page :loading="loading">
<view class="mine" slot="body">
<view class="mine-nav mt20" style="border-bottom: none">
<view class="mine-nav-label">暂态事件</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('eventInfo')"
:checked="config.eventInfo === 1"
/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">稳态事件</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('harmonicInfo')"
:checked="config.harmonicInfo === 1"
/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">运行告警</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('alarmInfo')"
:checked="config.alarmInfo === 1"
/>
</view>
<view class="mine-nav" >
<view class="mine-nav-label">运行事件</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('runInfo')"
:checked="config.runInfo === 1"
/>
</view>
</view>
</Cn-page>
</template>
<script>
import { queryUserPushConfig, updatePushConfig } from '@/common/api/mine'
export default {
data() {
return {
loading: true,
config: {},
}
},
methods: {
init() {
queryUserPushConfig().then((res) => {
this.config = res.data
this.loading = false
})
},
change(type) {
this.config[type] = this.config[type] === 1 ? 0 : 1
// updatePushConfig(this.config).then((res) => {
// let str = ''
// switch (type) {
// case 'runInfo':
// str = '运行事件'
// break
// case 'eventInfo':
// str = '暂态事件'
// break
// case 'harmonicInfo':
// str = '稳态事件'
// break
// case 'alarmInfo':
// str = '设备告警'
// break
// }
// this.$util.toast(`${str}推送${this.config[type] === 1 ? '开启' : '关闭'}成功`)
// })
},
jump(type) {
switch (type) {
case 'changePwd':
uni.navigateTo({
url: `/pages/user/changePwd`,
})
break
case 'changePhone':
uni.navigateTo({
url: `/pages/user/changePhone`,
})
break
default:
uni.navigateTo({
url: `/pages/mine/${type}`,
})
break
}
},
onUnload() {
updatePushConfig(this.config).then((res) => {
// this.$util.toast(`配置修改成功!`)
})
},
},
onLoad() {
this.init()
},
}
</script>
<style lang="scss">
.mine {
.title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
}
.mine-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.mine-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
}
}
.mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>

View File

@@ -40,29 +40,33 @@ export default {
init() {
queryUserPushConfig().then((res) => {
this.config = res.data
this.loading = false
})
},
change(type) {
this.config[type] = this.config[type] === 1 ? 0 : 1
updatePushConfig(this.config).then((res) => {
let str = ''
switch (type) {
case 'iticFunction':
str = 'ITIC'
break
case 'f47Function':
str = 'F47'
break
}
this.$util.toast(`${str}配置${this.config[type] === 1 ? '开启' : '关闭'}成功`)
})
// updatePushConfig(this.config).then((res) => {
// let str = ''
// switch (type) {
// case 'iticFunction':
// str = 'ITIC'
// break
// case 'f47Function':
// str = 'F47'
// break
// }
// this.$util.toast(`${str}配置${this.config[type] === 1 ? '开启' : '关闭'}成功`)
// })
},
},
onLoad() {
this.init()
},
onUnload() {
updatePushConfig(this.config).then((res) => {
// this.$util.toast(`配置修改成功!`)
})
},
}
</script>

View File

@@ -1,183 +1,183 @@
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="项目管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
@click="jump(item)"
extra="🔍"
v-for="(item, index) in store.data"
:key="index"
:style="{ marginTop: index === 0 ? '0' : '' }"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>设备个数</view>
<view>{{ item.devNum }}</view>
</view>
<view class="term-list-bottom-item">
<view>所属工程</view>
<view>{{ item.engineeringName }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
</view>
</template>
<script>
import list from '../../common/js/list'
export default {
mixins: [list],
data() {
return {
loading: false,
userInfo: {},
}
},
methods: {
init(engineeringId) {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.store = this.DataSource('/cs-device-boot/project/queryProject')
this.store.params.searchValue = ''
this.store.params.engineeringId = engineeringId || ''
this.store.reload()
},
back() {
uni.navigateBack()
},
add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
if (!uni.getStorageSync('engineering')) {
return uni.showToast({
title: '请先创建一个工程',
icon: 'none',
})
}
uni.navigateTo({
url: `/pages/project/new`,
})
}
},
upgrade(code) {
console.log(code)
uni.showToast({
title: '升级成功',
icon: 'none',
})
},
jump(project) {
console.log(project)
uni.navigateTo({
url: `/pages/project/detail?project=${encodeURIComponent(JSON.stringify(project))}`,
})
},
},
onLoad({ engineeringId }) {
this.init(engineeringId)
},
}
</script>
<style lang="scss">
.message {
.message-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.message-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
.tag {
margin-top: 10rpx;
font-size: 24rpx;
color: #aaa;
}
}
}
.message-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="项目管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
@click="jump(item)"
extra="🔍"
v-for="(item, index) in store.data"
:key="index"
:style="{ marginTop: index === 0 ? '0' : '' }"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>设备个数</view>
<view>{{ item.devNum }}</view>
</view>
<view class="term-list-bottom-item">
<view>所属工程</view>
<view>{{ item.engineeringName }}</view>
</view>
</view>
</uni-card>
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
</view>
</template>
<script>
import list from '../../common/js/list'
export default {
mixins: [list],
data() {
return {
loading: false,
userInfo: {},
}
},
methods: {
init(engineeringId) {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.store = this.DataSource('/cs-device-boot/project/queryProject')
this.store.params.searchValue = ''
this.store.params.engineeringId = engineeringId || ''
this.store.reload()
},
back() {
uni.navigateBack()
},
add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
if (!uni.getStorageSync('engineering')) {
return uni.showToast({
title: '请先创建一个工程',
icon: 'none',
})
}
uni.navigateTo({
url: `/pages/project/new`,
})
}
},
upgrade(code) {
console.log(code)
uni.showToast({
title: '升级成功',
icon: 'none',
})
},
jump(project) {
console.log(project)
uni.navigateTo({
url: `/pages/project/detail?project=${encodeURIComponent(JSON.stringify(project))}`,
})
},
},
onLoad({ engineeringId }) {
this.init(engineeringId)
},
}
</script>
<style lang="scss">
.message {
.message-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.message-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
.tag {
margin-top: 10rpx;
font-size: 24rpx;
color: #aaa;
}
}
}
.message-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>

View File

@@ -1,249 +1,250 @@
<template>
<Cn-page :loading="loading">
<view slot="body">
<view class="index">
<template v-if="step == 1">
<uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone">
<uni-easyinput
disabled
type="text"
maxlength="11"
v-model="formData.phoneShow"
placeholder="请输入手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode(5)" size="mini">
获取验证码
</button>
</view>
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="firstSubmit">下一步</button>
</template>
<template v-else>
<uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone">
<uni-easyinput
maxlength="11"
type="number"
v-model="formData.phone2"
placeholder="请输入新手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code2" placeholder="请输入验证码" maxlength="6" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode(4)" size="mini">
获取验证码
</button>
</view>
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="secondSubmit">提交</button>
</template>
</view>
</view>
</Cn-page>
</template>
<script>
import { apiGetYms, apiComfirmCode, apiRebindPhone } from '@/common/api/user'
export default {
name: 'jiaban',
data() {
return {
step: 1,
loading: false,
waitTime: 0,
// 表单数据
formData: {
phone: '',
phoneShow: '',
code: '',
phone2: '',
code2: '',
},
rules: {
phone: {
rules: [
{
required: true,
errorMessage: '请填写手机号',
},
],
},
code: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
phone2: {
rules: [
{
required: true,
errorMessage: '请填写新手机号',
},
],
},
code2: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
},
}
},
onLoad() {
this.init()
},
methods: {
getCode(type) {
if (!this.formData.phone) {
return this.$util.toast('请输入手机号!')
}
uni.showLoading({
title: '请稍等',
})
apiGetYms({
phone: type == 5 ? this.formData.phone : this.formData.phone2,
type,
})
.then((res) => {
uni.hideLoading()
console.log(res)
this.waitTime = 60
this.inter = setInterval(() => {
if (this.waitTime == 0) {
clearInterval(this.inter)
} else {
this.waitTime--
}
}, 1000)
})
.catch((err) => {
uni.hideLoading()
console.log(err)
})
},
init() {
// 手机号中间四位隐藏
this.formData.phone = uni.getStorageSync('userInfo').user_name
this.formData.phoneShow = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
},
firstSubmit() {
apiComfirmCode({
phone: this.formData.phone,
code: this.formData.code,
})
.then((res) => {
this.step = 2
clearInterval(this.inter)
this.waitTime = 0
})
.catch((err) => {
console.log(err)
})
},
secondSubmit() {
apiRebindPhone({
phone: this.formData.phone2,
code: this.formData.code2,
})
.then((res) => {
this.$util.toast('绑定成功')
uni.clearStorageSync()
setTimeout(() => {
uni.redirectTo({
url: '/pages/user/login',
})
}, 1500)
})
.catch((err) => {
console.log(err)
})
},
},
}
</script>
<style lang="scss">
.index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color;
color: #fff;
}
.login-box-tips {
margin-top: 60rpx;
display: flex;
justify-content: center;
font-size: 20rpx;
}
.login-box-input {
display: flex;
align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx;
margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx;
flex: 1;
height: 100rpx;
line-height: 100rpx;
}
.login-box-input-btn {
padding:0 40rpx;
margin-left: 40rpx;
background: $uni-theme-color;
color: #fff;
}
.login-box-input-img {
margin-left: 40rpx;
background: skyblue;
height: 80rpx;
width: 200rpx;
}
}
}
</style>
<template>
<Cn-page :loading="loading">
<view slot="body">
<view class="index">
<template v-if="step == 1">
<uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone">
<uni-easyinput
disabled
type="text"
maxlength="11"
v-model="formData.phoneShow"
placeholder="请输入手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode(5)" size="mini">
获取验证码
</button>
</view>
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="firstSubmit">下一步</button>
</template>
<template v-else>
<uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone">
<uni-easyinput
maxlength="11"
type="number"
v-model="formData.phone2"
placeholder="请输入新手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code2" placeholder="请输入验证码" maxlength="6" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode(4)" size="mini">
获取验证码
</button>
</view>
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="secondSubmit">提交</button>
</template>
</view>
</view>
</Cn-page>
</template>
<script>
import { apiGetYms, apiComfirmCode, apiRebindPhone } from '@/common/api/user'
export default {
name: 'jiaban',
data() {
return {
step: 1,
loading: false,
waitTime: 0,
// 表单数据
formData: {
phone: '',
phoneShow: '',
code: '',
phone2: '',
code2: '',
},
rules: {
phone: {
rules: [
{
required: true,
errorMessage: '请填写手机号',
},
],
},
code: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
phone2: {
rules: [
{
required: true,
errorMessage: '请填写新手机号',
},
],
},
code2: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
},
}
},
onLoad() {
this.init()
},
methods: {
getCode(type) {
if (!this.formData.phone) {
return this.$util.toast('请输入手机号!')
}
uni.showLoading({
title: '请稍等...',
mask: true,
})
apiGetYms({
phone: type == 5 ? this.formData.phone : this.formData.phone2,
type,
})
.then((res) => {
uni.hideLoading()
console.log(res)
this.waitTime = 60
this.inter = setInterval(() => {
if (this.waitTime == 0) {
clearInterval(this.inter)
} else {
this.waitTime--
}
}, 1000)
})
.catch((err) => {
uni.hideLoading()
console.log(err)
})
},
init() {
// 手机号中间四位隐藏
this.formData.phone = uni.getStorageSync('userInfo').user_name
this.formData.phoneShow = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
},
firstSubmit() {
apiComfirmCode({
phone: this.formData.phone,
code: this.formData.code,
})
.then((res) => {
this.step = 2
clearInterval(this.inter)
this.waitTime = 0
})
.catch((err) => {
console.log(err)
})
},
secondSubmit() {
apiRebindPhone({
phone: this.formData.phone2,
code: this.formData.code2,
})
.then((res) => {
this.$util.toast('绑定成功')
uni.clearStorageSync()
setTimeout(() => {
uni.redirectTo({
url: '/pages/user/login',
})
}, 1500)
})
.catch((err) => {
console.log(err)
})
},
},
}
</script>
<style lang="scss">
.index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color;
color: #fff;
}
.login-box-tips {
margin-top: 60rpx;
display: flex;
justify-content: center;
font-size: 20rpx;
}
.login-box-input {
display: flex;
align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx;
margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx;
flex: 1;
height: 100rpx;
line-height: 100rpx;
}
.login-box-input-btn {
padding:0 40rpx;
margin-left: 40rpx;
background: $uni-theme-color;
color: #fff;
}
.login-box-input-img {
margin-left: 40rpx;
background: skyblue;
height: 80rpx;
width: 200rpx;
}
}
}
</style>

View File

@@ -1,242 +1,243 @@
<template>
<Cn-page :loading="loading">
<view slot="body">
<view class="index">
<uni-forms ref="form" :modelValue="formData" :rules="rules">
<uni-forms-item name="phone">
<uni-easyinput
maxlength="11"
disabled
type="text"
v-model="formData.showPhone"
placeholder="请输入手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="number" v-model="formData.code" placeholder="请输入手机验证码" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode" size="mini">获取验证码</button>
</view>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput type="password" v-model="formData.password" placeholder="请输入新的登录密码" />
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput type="password" v-model="formData.password2" placeholder="请再次确认密码" />
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="submit">提交</button>
<view class="login-box-tips">
<view style="color: #999">说明密码需要长度为8-16</view>
</view>
</view>
</view>
</Cn-page>
</template>
<script>
import { apiGetYms, apiModifyPsd, gongkey } from '@/common/api/user'
import { sm2, encrypt } from '@/common/js/sm2.js'
import { sm3Digest } from '@/common/js/sm3.js'
export default {
name: 'ChangePWd',
data() {
return {
loading: false,
waitTime: 0,
// 表单数据
formData: {
showPhone: '',
phone: '',
code: '',
password: '',
password2: '',
},
rules: {
phone: {
rules: [
{
required: true,
errorMessage: '请填写手机号',
},
],
},
code: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
password: {
rules: [
{
required: true,
errorMessage: '请填写新密码',
},
],
},
password2: {
rules: [
{
required: true,
errorMessage: '请填写确认密码',
},
],
},
},
}
},
onLoad() {
// 手机号中间四位隐藏
this.formData.phone = uni.getStorageSync('userInfo').user_name
this.formData.showPhone = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
},
methods: {
getCode() {
uni.showLoading({
title: '请稍等',
})
apiGetYms({
phone: this.formData.phone,
type: 2,
})
.then((res) => {
uni.hideLoading()
console.log(res)
this.waitTime = 60
this.inter = setInterval(() => {
if (this.waitTime == 0) {
clearInterval(this.inter)
} else {
this.waitTime--
}
}, 1000)
})
.catch((err) => {
uni.hideLoading()
console.log(err)
})
},
submit() {
this.$refs.form.validate((valid) => {
console.log(valid)
if (!valid) {
if (this.formData.password != this.formData.password2) {
uni.showToast({
title: '两次密码不一致',
icon: 'none',
})
} else {
// 密码需要长度为8-16
if (this.formData.password.length < 8 || this.formData.password.length > 16) {
uni.showToast({
title: '密码需要长度为8-16',
icon: 'none',
})
return
}
let loginName = encrypt(this.formData.phone)
gongkey({ loginName }).then((response) => {
let publicKey = response.data
let sm3Pwd = sm3Digest(this.formData.password)
let jiamipassword = sm2(sm3Pwd + '|' + this.formData.password, publicKey, 0)
// apiPwdLogin({
// username: loginName,
// password: jiamipassword,
// imageCode: '',
// grant_type: 'captcha',
// verifyCode: 0,
// }).then((res) => {
// this.$util.loginSuccess(res.data)
// })
apiModifyPsd({
phone: this.formData.phone,
code: this.formData.code,
password: jiamipassword,
})
.then((res) => {
console.log(res)
uni.showToast({
title: '修改成功',
icon: 'none',
})
setTimeout(() => {
uni.navigateBack({
delta: 1,
})
}, 1000)
})
.catch((err) => {
console.log(err)
})
})
}
}
})
},
},
}
</script>
<style lang="scss">
.index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color;
color: #fff;
}
.login-box-tips {
margin-top: 60rpx;
display: flex;
justify-content: center;
font-size: 20rpx;
}
.login-box-input {
display: flex;
align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx;
margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx;
flex: 1;
height: 100rpx;
line-height: 100rpx;
}
.login-box-input-btn {
padding:0 40rpx;
margin-left: 40rpx;
background: $uni-theme-color;
color: #fff;
}
.login-box-input-img {
margin-left: 40rpx;
background: skyblue;
height: 80rpx;
width: 200rpx;
}
}
}
</style>
<template>
<Cn-page :loading="loading">
<view slot="body">
<view class="index">
<uni-forms ref="form" :modelValue="formData" :rules="rules">
<uni-forms-item name="phone">
<uni-easyinput
maxlength="11"
disabled
type="text"
v-model="formData.showPhone"
placeholder="请输入手机号"
/>
</uni-forms-item>
<uni-forms-item name="code">
<view class="login-box-input">
<uni-easyinput type="number" v-model="formData.code" placeholder="请输入手机验证码" />
<view
class="ml40"
style="
margin-left: 40rpx;
font-size: 28rpx;
color: #666;
width: 200rpx;
text-align: center;
"
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view
>
<button class="login-box-input-btn" v-else @click="getCode" size="mini">获取验证码</button>
</view>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput type="password" v-model="formData.password" placeholder="请输入新的登录密码" />
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput type="password" v-model="formData.password2" placeholder="请再次确认密码" />
</uni-forms-item>
</uni-forms>
<button type="default" class="submit-btn" @click="submit">提交</button>
<view class="login-box-tips">
<view style="color: #999">说明密码需要长度为8-16</view>
</view>
</view>
</view>
</Cn-page>
</template>
<script>
import { apiGetYms, apiModifyPsd, gongkey } from '@/common/api/user'
import { sm2, encrypt } from '@/common/js/sm2.js'
import { sm3Digest } from '@/common/js/sm3.js'
export default {
name: 'ChangePWd',
data() {
return {
loading: false,
waitTime: 0,
// 表单数据
formData: {
showPhone: '',
phone: '',
code: '',
password: '',
password2: '',
},
rules: {
phone: {
rules: [
{
required: true,
errorMessage: '请填写手机号',
},
],
},
code: {
rules: [
{
required: true,
errorMessage: '请填写验证码',
},
],
},
password: {
rules: [
{
required: true,
errorMessage: '请填写新密码',
},
],
},
password2: {
rules: [
{
required: true,
errorMessage: '请填写确认密码',
},
],
},
},
}
},
onLoad() {
// 手机号中间四位隐藏
this.formData.phone = uni.getStorageSync('userInfo').user_name
this.formData.showPhone = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
},
methods: {
getCode() {
uni.showLoading({
title: '请稍等...',
mask: true,
})
apiGetYms({
phone: this.formData.phone,
type: 2,
})
.then((res) => {
uni.hideLoading()
console.log(res)
this.waitTime = 60
this.inter = setInterval(() => {
if (this.waitTime == 0) {
clearInterval(this.inter)
} else {
this.waitTime--
}
}, 1000)
})
.catch((err) => {
uni.hideLoading()
console.log(err)
})
},
submit() {
this.$refs.form.validate((valid) => {
console.log(valid)
if (!valid) {
if (this.formData.password != this.formData.password2) {
uni.showToast({
title: '两次密码不一致',
icon: 'none',
})
} else {
// 密码需要长度为8-16
if (this.formData.password.length < 8 || this.formData.password.length > 16) {
uni.showToast({
title: '密码需要长度为8-16',
icon: 'none',
})
return
}
let loginName = encrypt(this.formData.phone)
gongkey({ loginName }).then((response) => {
let publicKey = response.data
let sm3Pwd = sm3Digest(this.formData.password)
let jiamipassword = sm2(sm3Pwd + '|' + this.formData.password, publicKey, 0)
// apiPwdLogin({
// username: loginName,
// password: jiamipassword,
// imageCode: '',
// grant_type: 'captcha',
// verifyCode: 0,
// }).then((res) => {
// this.$util.loginSuccess(res.data)
// })
apiModifyPsd({
phone: this.formData.phone,
code: this.formData.code,
password: jiamipassword,
})
.then((res) => {
console.log(res)
uni.showToast({
title: '修改成功',
icon: 'none',
})
setTimeout(() => {
uni.navigateBack({
delta: 1,
})
}, 1000)
})
.catch((err) => {
console.log(err)
})
})
}
}
})
},
},
}
</script>
<style lang="scss">
.index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color;
color: #fff;
}
.login-box-tips {
margin-top: 60rpx;
display: flex;
justify-content: center;
font-size: 20rpx;
}
.login-box-input {
display: flex;
align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx;
margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx;
flex: 1;
height: 100rpx;
line-height: 100rpx;
}
.login-box-input-btn {
padding: 0 40rpx;
margin-left: 40rpx;
background: $uni-theme-color;
color: #fff;
}
.login-box-input-img {
margin-left: 40rpx;
background: skyblue;
height: 80rpx;
width: 200rpx;
}
}
}
</style>

View File

@@ -114,7 +114,8 @@ export default {
return this.$util.toast('请输入手机号!')
}
uni.showLoading({
title: '请稍等',
title: '请稍等...',
mask: true,
})
apiGetYms({
phone: this.formData.phone,

View File

@@ -121,7 +121,8 @@ export default {
return this.$util.toast('请输入手机号!')
}
uni.showLoading({
title: '请稍等',
title: '请稍等...',
mask: true,
})
apiGetYms({
phone: this.phone,

View File

@@ -135,7 +135,8 @@ export default {
return this.$util.toast('请输入手机号!')
}
uni.showLoading({
title: '请稍等',
title: '请稍等...',
mask: true,
})
apiGetYms({
phone: this.formData.phone,