This commit is contained in:
2026-04-01 14:28:09 +08:00
parent 69e199e9cc
commit ac7dd9dd30
8 changed files with 637 additions and 363 deletions

View File

@ -104,10 +104,10 @@ export function getSingleSiteBaseInfo(data) {
})
}
//单站监控 首页 总累计运行数据
export function getDzjkHomeView(siteId) {
//单站监控 首页 总累计运行数据(基于日表)
export function getDzjkHomeTotalView(siteId) {
return request({
url: `/ems/siteMonitor/homeView?siteId=${siteId}`,
url: `/ems/siteMonitor/homeTotalView?siteId=${siteId}`,
method: 'get'
})
}
@ -147,6 +147,18 @@ export function getPointData(data) {
})
}
// 点位配置-曲线数据(与管理端一致)
export function getPointConfigCurve(data) {
return request({
url: `/ems/pointConfig/curve`,
method: 'post',
data,
headers: {
repeatSubmit: false
}
})
}
// 获取站点包含的设备种类 用来判断单站监控设备监控的菜单栏展示
export function getSiteAllDeviceCategory(data) {
return request({

View File

@ -0,0 +1,69 @@
<template>
<view class="ems-site-selector">
<uni-data-picker placeholder="请选择" popup-title="业态选择" :step-searh="true" :value="siteId" :clear-icon="false"
:localdata="siteTypeOptions" :ellipsis="false" @change="handleChange">
</uni-data-picker>
</view>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['siteId', 'siteTypeOptions'])
},
methods: {
handleChange(data) {
const valueList = data?.detail?.value || []
const siteObj = valueList[1]
if (!siteObj || siteObj.value === undefined || siteObj.value === null || siteObj.value === this.siteId) return
this.$store.dispatch('SetCurrentSiteId', siteObj.value)
this.$emit('change', siteObj.value)
}
},
created() {
this.$store.dispatch('LoadSites')
}
}
</script>
<style lang="scss" scoped>
.ems-site-selector {
.uni-data-tree {
::v-deep {
.input-value {
border: none;
padding-left: 0;
.selected-area {
width: 90%;
flex: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.selected-list {
color: #fff;
}
}
.text-color {
color: #fff;
font-size: 34rpx;
line-height: 36rpx;
font-weight: bolder;
}
.arrow-area {
transform: rotate(-135deg);
.input-arrow {
border-color: #fff;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<view class="site-switch-header">
<uni-data-picker
placeholder="请选择"
popup-title="业态选择"
:step-searh="true"
:value="siteId"
:clear-icon="false"
:localdata="siteTypeOptions"
:ellipsis="false"
@change="handleChange"
/>
<view class="info">
<view class="list">
<uni-icons type="location" color="#fff" size="20"></uni-icons>
{{ siteAddress || '-' }}
</view>
<view class="list">
<uni-icons type="calendar" color="#fff" size="20"></uni-icons>
{{ runningTime || '-' }}
</view>
</view>
</view>
</template>
<script>
export default {
props: {
siteId: {
type: [String, Number],
default: ''
},
siteTypeOptions: {
type: Array,
default: () => []
},
siteAddress: {
type: String,
default: '-'
},
runningTime: {
type: String,
default: '-'
}
},
methods: {
handleChange(data) {
this.$emit('change', data)
}
}
}
</script>
<style lang="scss" scoped>
.site-switch-header {
background: linear-gradient(to right, #547ef4, #679ff5);
padding: 30rpx 30rpx;
padding-bottom: 100rpx;
color: #fff;
.info {
color: #fff;
font-size: 26rpx;
line-height: 30rpx;
vertical-align: middle;
margin-top: 20rpx;
>.list {
display: flex;
justify-content: flex-start;
align-items: center;
&:not(:last-child) {
margin-bottom: 20rpx;
}
>.uni-icons {
margin-right: 10rpx;
}
}
}
.uni-data-tree {
::v-deep {
.uni-data-tree-dialog {
color: #333;
.selected-item,
.dialog-title {
color: #333;
}
}
.input-value {
border: none;
padding-left: 0;
.selected-area {
width: 90%;
flex: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.selected-list {
color: #fff;
}
}
.text-color {
color: #fff;
font-size: 34rpx;
line-height: 36rpx;
font-weight: bolder;
}
.arrow-area {
transform: rotate(-135deg);
.input-arrow {
border-color: #fff;
}
}
}
}
}
}
</style>

View File

@ -1,20 +1,7 @@
<template>
<view class="home-container">
<view class="site-sections-list">
<uni-data-picker placeholder="请选择" popup-title="业态选择" :step-searh="true" :value="siteId" :clear-icon="false"
:localdata="siteTypeOptions" :ellipsis="false" @change="selectedSite">
</uni-data-picker>
<view class="info">
<view class="list">
<uni-icons type="location" color="#fff" size="20"></uni-icons>
{{ baseInfo.siteAddress || '-' }}
</view>
<view class="list">
<uni-icons type="calendar" color="#fff" size="20"></uni-icons>
{{ baseInfo.runningTime || '-' }}
</view>
</view>
</view>
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
:running-time="baseInfo.runningTime" @change="selectedSite" />
<view class="base-info">
<view class="map-card">
@ -63,17 +50,12 @@
import {
getAllSites,
getSingleSiteBaseInfo,
getDzjkHomeView,
getDzjkHomeTotalView,
getProjectDisplayData,
getAmmeterRevenueData
} from '@/api/ems/site.js'
export default {
data() {
return {
pageScrollTop: 0,
siteOptions: [],
siteTypeOptions: [{
import SiteSwitchHeader from '@/components/SiteSwitchHeader/index.vue'
const createSiteTypeOptions = () => ([{
text: '储能',
value: 'cn',
children: []
@ -81,16 +63,24 @@
{
text: '光能',
value: 'gn',
disable: true,
children: []
},
{
text: '岸电',
value: 'ad',
disable: true,
children: []
}
],
])
export default {
components: {
SiteSwitchHeader
},
data() {
return {
pageScrollTop: 0,
siteOptions: [],
siteTypeOptions: createSiteTypeOptions(),
siteId: '',
mapUrl: '',
baseInfo: {},
@ -251,21 +241,29 @@
getSiteList() {
getAllSites().then(response => {
const data = response?.data || []
const children = data.map(item => {
return {
const canAccessAll = !this.belongSite || this.belongSite.length === 0 || this.belongSite.includes('all')
const siteTypeOptions = createSiteTypeOptions().map(item => ({
...item,
children: []
}))
data.forEach(item => {
if (!canAccessAll && !this.belongSite.includes(item.siteId)) return
const siteType = (item.siteType || item.type || 'cn').toString().toLowerCase()
const typeOption = siteTypeOptions.find(i => i.value === siteType) || siteTypeOptions.find(i => i.value === 'cn')
if (!typeOption) return
typeOption.children.push({
text: item.siteName,
value: item.siteId,
id: item.id,
longitude: Number(item.longitude || 0),
latitude: Number(item.latitude || 0),
disable: !this.belongSite || this.belongSite.length === 0 || this.belongSite.includes('all') ? false : !this
.belongSite.includes(item.siteId)
}
latitude: Number(item.latitude || 0)
})
this.siteTypeOptions.find(i => i.value === 'cn').children = children
this.siteOptions = children
const defaultSiteId = this.isAvailableSite(this.currentSiteId) ? this.currentSiteId : (children.find(item => !item
.disable)?.value || '')
})
this.siteTypeOptions = siteTypeOptions.filter(item => (item.children || []).length > 0)
this.siteOptions = this.siteTypeOptions.reduce((result, typeItem) => {
return result.concat(typeItem.children || [])
}, [])
const defaultSiteId = this.isAvailableSite(this.currentSiteId) ? this.currentSiteId : (this.siteOptions[0]?.value || '')
if (defaultSiteId) {
this.siteId = defaultSiteId
this.$store.commit('SET_CURRENTSITEID', defaultSiteId)
@ -290,7 +288,7 @@
},
getRunningInfo() {
return Promise.all([
getDzjkHomeView(this.siteId),
getDzjkHomeTotalView(this.siteId),
getProjectDisplayData(this.siteId)
]).then(([homeResponse, displayResponse]) => {
this.runningInfo = homeResponse?.data || {}
@ -416,71 +414,6 @@
padding-top: 0;
}
.site-sections-list {
background: linear-gradient(to right, #547ef4, #679ff5);
padding: 30rpx 30rpx;
padding-bottom: 100rpx;
color: #fff;
.info {
color: #fff;
font-size: 26rpx;
line-height: 30rpx;
vertical-align: middle;
margin-top: 20rpx;
>.list {
display: flex;
justify-content: flex-start;
align-items: center;
&:not(:last-child) {
margin-bottom: 20rpx;
}
>.uni-icons {
margin-right: 10rpx;
}
}
}
.uni-data-tree {
::v-deep {
.input-value {
border: none;
padding-left: 0;
.selected-area {
width: 90%;
flex: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.selected-list {
color: #fff;
}
}
.text-color {
color: #fff;
font-size: 34rpx;
line-height: 36rpx;
font-weight: bolder;
}
.arrow-area {
transform: rotate(-135deg);
.input-arrow {
border-color: #fff;
}
}
}
}
}
}
.base-info {
margin-top: -80rpx;
border-radius: 80rpx 80rpx 0 0;

View File

@ -1,32 +1,20 @@
<template>
<view class="work-container">
<view class="site-sections-list">
<uni-data-picker placeholder="请选择" popup-title="业态选择" :step-searh="true" :value="siteId" :clear-icon="false"
:localdata="siteTypeOptions" :ellipsis="false" @change="selectedSite">
</uni-data-picker>
<view class="info">
<view class="list"> <uni-icons type="location" color="#fff" size="20"></uni-icons>
{{baseInfo.siteAddress || '-'}}
</view>
<view class="list">
<uni-icons type="calendar" color="#fff" size="20"></uni-icons>
{{baseInfo.runningTime || '-'}}
</view>
</view>
</view>
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
:running-time="baseInfo.runningTime" @change="selectedSite" />
<!-- 静态信息 -->
<view class="base-info">
<uni-group mode="card" class="install-data">
<uni-grid :column="2" :showBorder="false" :square="false" :highlight="false">
<uni-grid-item>
<view class="grid-item-box">
<view class="title">装机功率(MW)</view>
<view class="title">装机功率(MWh)</view>
<view class="text">{{baseInfo.installPower | formatNumber}}</view>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">装机容量(MW)</view>
<view class="title">装机容量(MWh)</view>
<view class="text">{{baseInfo.installCapacity | formatNumber}}</view>
</view>
</uni-grid-item>
@ -70,16 +58,34 @@
mapGetters
} from 'vuex'
import DateRangeSelect from './DateRangeSelect.vue'
import SiteSwitchHeader from '@/components/SiteSwitchHeader/index.vue'
import {
getAllSites,
getSingleSiteBaseInfo,
getSevenChargeData,
getPointData,
getProjectDisplayData,
getPointConfigCurve,
getSiteAllDeviceCategory
} from '@/api/ems/site.js'
const createSiteTypeOptions = () => ([{
text: '储能',
value: 'cn',
children: []
},
{
text: '光能',
value: 'gn',
children: []
},
{
text: '岸电',
value: 'ad',
children: []
}
])
export default {
components: {
DateRangeSelect
DateRangeSelect,
SiteSwitchHeader
},
data() {
return {
@ -88,6 +94,8 @@
activeChartTimeRange: [],
weekChartData: {},
activeChartData: {},
curveDisplayData: [],
curveDisplayLoadingPromise: null,
pageScrollTop: 0,
glqxOptions: {
padding: [10, 5, 0, 10],
@ -141,24 +149,7 @@
},
// 图表数据结束
deviceCategoryOptions: [], //当前站点包含的设备类别
siteTypeOptions: [{
text: '储能',
value: 'cn',
children: []
},
{
text: '光能',
value: 'gn',
disable: true,
children: []
},
{
text: '岸电',
value: 'ad',
disable: true,
children: []
}
],
siteTypeOptions: createSiteTypeOptions(),
siteId: '', //选择的站点ID
baseInfo: {}, //站点基本信息
gridList: [{
@ -208,7 +199,10 @@
},
methods: {
isAvailableSite(siteId) {
const site = (this.siteTypeOptions.find(i => i.value === 'cn')?.children || []).find(item => item.value === siteId)
const allSites = this.siteTypeOptions.reduce((result, typeItem) => {
return result.concat(typeItem.children || [])
}, [])
const site = allSites.find(item => item.value === siteId)
return !!(site && !site.disable)
},
// 更新一周冲放曲线时间范围 重置图表
@ -242,28 +236,144 @@
},
updateSiteInfo() {
if (!this.siteId) return
this.curveDisplayData = []
this.curveDisplayLoadingPromise = null
this.getSiteBaseInfo()
this.getWeekChartData()
this.getGVQXData()
this.getSiteDeviceCategory()
},
getFieldName(fieldCode) {
const raw = String(fieldCode || '').trim()
if (!raw) return ''
const index = raw.lastIndexOf('__')
return index >= 0 ? raw.slice(index + 2) : raw
},
normalizeDateTime(value, endOfDay) {
const raw = String(value || '').trim()
if (!raw) return ''
if (raw.includes(' ')) return raw
return `${raw} ${endOfDay ? '23:59:59' : '00:00:00'}`
},
parseToTimestamp(value) {
if (!value) return null
const timestamp = new Date(value).getTime()
return Number.isNaN(timestamp) ? null : timestamp
},
ensureCurveDisplayData() {
if (!this.siteId) return Promise.resolve([])
if (this.curveDisplayData.length > 0) return Promise.resolve(this.curveDisplayData)
if (this.curveDisplayLoadingPromise) return this.curveDisplayLoadingPromise
this.curveDisplayLoadingPromise = getProjectDisplayData(this.siteId)
.then(response => {
this.curveDisplayData = response?.data || []
return this.curveDisplayData
})
.catch(() => {
this.curveDisplayData = []
return []
})
.finally(() => {
this.curveDisplayLoadingPromise = null
})
return this.curveDisplayLoadingPromise
},
fetchCurveSeries(pointId, name, startTime, endTime) {
if (!pointId) return Promise.resolve(null)
return getPointConfigCurve({
siteId: this.siteId,
pointId,
pointType: 'data',
rangeType: 'custom',
startTime,
endTime
}).then(response => {
const list = response?.data || []
const points = list.map(item => {
const timestamp = this.parseToTimestamp(item.dataTime)
const value = Number(item.pointValue)
if (!timestamp || Number.isNaN(value)) return null
return {
timestamp,
label: item.dataTime,
value
}
}).filter(Boolean)
return {
name,
points
}
}).catch(() => null)
},
buildLineChartData(seriesList) {
const validSeries = (seriesList || []).filter(item => item && (item.points || []).length > 0)
if (validSeries.length === 0) {
return {
categories: [],
series: []
}
}
const labelByTimestamp = {}
const timestampSet = new Set()
validSeries.forEach(item => {
item.points.forEach(point => {
timestampSet.add(point.timestamp)
if (!labelByTimestamp[point.timestamp]) {
labelByTimestamp[point.timestamp] = point.label
}
})
})
const sortedTimestamps = Array.from(timestampSet).sort((a, b) => a - b)
const categories = sortedTimestamps.map(item => labelByTimestamp[item])
const series = validSeries.map(item => {
const pointMap = {}
item.points.forEach(point => {
pointMap[point.timestamp] = point.value
})
return {
name: item.name,
data: sortedTimestamps.map(timestamp => pointMap[timestamp] ?? null)
}
})
return {
categories,
series
}
},
findActiveCurveRow(sectionRows, keywords = []) {
const keywordSet = new Set((keywords || []).map(item => String(item || '').toLowerCase()))
return (sectionRows || []).find(row => {
const fieldCode = this.getFieldName(row?.fieldCode).toLowerCase()
const fieldName = String(row?.fieldName || '').toLowerCase()
if (keywordSet.has(fieldCode) || keywordSet.has(fieldName)) return true
return Array.from(keywordSet).some(keyword => fieldCode.includes(keyword) || fieldName.includes(keyword))
})
},
getSiteList() {
getAllSites().then(response => {
const data = response?.data || []
this.siteTypeOptions.find(i => i.value === 'cn').children = data.map(item => {
return {
const canAccessAll = !this.belongSite || this.belongSite.length === 0 || this.belongSite.includes('all')
const siteTypeOptions = createSiteTypeOptions().map(item => ({
...item,
children: []
}))
data.forEach(item => {
if (!canAccessAll && !this.belongSite.includes(item.siteId)) return
const siteType = (item.siteType || item.type || 'cn').toString().toLowerCase()
const typeOption = siteTypeOptions.find(i => i.value === siteType) || siteTypeOptions.find(i => i.value === 'cn')
if (!typeOption) return
typeOption.children.push({
text: item.siteName,
value: item.siteId,
id: item.id,
disable: !this.belongSite || this.belongSite.length === 0 || this
.belongSite.includes('all') ? false : !this.belongSite.includes(item
.siteId)
}
id: item.id
})
const siteChildren = this.siteTypeOptions.find(i => i.value === 'cn')?.children || []
})
this.siteTypeOptions = siteTypeOptions.filter(item => (item.children || []).length > 0)
const siteChildren = this.siteTypeOptions.reduce((result, typeItem) => {
return result.concat(typeItem.children || [])
}, [])
// 设置默认展示的站点
const defaultSiteId = this.isAvailableSite(this.currentSiteId) ? this.currentSiteId : (siteChildren.find(item =>
!item.disable)?.value || '')
const defaultSiteId = this.isAvailableSite(this.currentSiteId) ? this.currentSiteId : (siteChildren[0]?.value || '')
if (defaultSiteId) {
this.siteId = defaultSiteId
this.$store.commit('SET_CURRENTSITEID', defaultSiteId)
@ -295,91 +405,50 @@
},
getGVQXData() {
this.$refs.activeChartDateRangeSelect.showBtnLoading(true)
getPointData({
siteId: this.siteId,
startDate: this.activeChartTimeRange[0],
endDate: this.activeChartTimeRange[1]
}).then(response => {
console.log('当日功率曲线', response)
let data = response?.data || [],
categories = [],
source = [{
const startTime = this.normalizeDateTime(this.activeChartTimeRange[0], false)
const endTime = this.normalizeDateTime(this.activeChartTimeRange[1], true)
this.ensureCurveDisplayData().then(displayData => {
const sectionRows = (displayData || []).filter(item =>
item && item.sectionName === '当日功率曲线' && item.useFixedDisplay !== 1 && item.dataPoint
)
const targetRows = [{
name: '电网功率',
attr: 'gridPower',
data: []
row: this.findActiveCurveRow(sectionRows, ['gridpower', '电网功率'])
},
{
name: '负载功率',
attr: 'loadPower',
data: []
row: this.findActiveCurveRow(sectionRows, ['loadpower', '负载功率'])
},
{
name: '储能功率',
attr: 'storagePower',
data: []
},
{
name: '光伏功率',
attr: 'pvPower',
data: []
},
{
name: 'soc平均值',
attr: 'avgSoc',
data: []
},
{
name: 'soh平均值',
attr: 'avgSoh',
data: []
},
{
name: '电池平均温度平均值平均值',
attr: 'avgTemp',
data: []
},
]
data.forEach((item) => {
categories.push(item.statisDate || undefined)
source.forEach(i => i.data.push(item[i.attr]))
row: this.findActiveCurveRow(sectionRows, ['storagepower', '储能功率'])
}
].filter(item => item.row && item.row.dataPoint)
const tasks = targetRows.map(item => this.fetchCurveSeries(String(item.row.dataPoint).trim(), item.name, startTime,
endTime))
return Promise.all(tasks).then(series => {
this.activeChartData = JSON.parse(JSON.stringify(this.buildLineChartData((series || []).filter(Boolean))))
})
this.activeChartData = JSON.parse(JSON.stringify({
categories,
series: source
}))
}).finally(() => this.$refs.activeChartDateRangeSelect.showBtnLoading(false))
},
getWeekChartData() {
this.$refs.weekChartDateRangeSelect.showBtnLoading(true)
getSevenChargeData({
siteId: this.siteId,
startDate: this.weekChartTimeRange[0],
endDate: this.weekChartTimeRange[1]
}).then(response => {
console.log('一周功率曲线', response)
let data = response?.data || [],
categories = [],
chargedCap = [],
disChargedCap = []
data.forEach(item => {
categories.push(this.handleDate(item.ammeterDate) || undefined)
chargedCap.push(item.chargedCap)
disChargedCap.push(item.disChargedCap)
const startTime = this.normalizeDateTime(this.weekChartTimeRange[0], false)
const endTime = this.normalizeDateTime(this.weekChartTimeRange[1], true)
this.ensureCurveDisplayData().then(displayData => {
const sectionRows = (displayData || []).filter(item =>
item && item.sectionName === '一周充放曲线' && item.useFixedDisplay !== 1 && item.dataPoint
)
const tasks = sectionRows.map(row => {
const pointId = String(row.dataPoint || '').trim()
if (!pointId) return Promise.resolve(null)
const name = row.fieldName || this.getFieldName(row.fieldCode) || pointId
return this.fetchCurveSeries(pointId, name, startTime, endTime)
})
return Promise.all(tasks).then(series => {
this.weekChartData = JSON.parse(JSON.stringify(this.buildLineChartData((series || []).filter(Boolean))))
})
this.weekChartData = JSON.parse(JSON.stringify({
categories,
series: [{
"name": '充电量',
"data": chargedCap
},
{
"name": '放电量',
"data": disChargedCap
}
]
}))
}).finally(() => this.$refs.weekChartDateRangeSelect.showBtnLoading(false))
}
},
@ -430,77 +499,6 @@
margin-top: 10rpx;
}
// 站点选择
.site-sections-list {
background: linear-gradient(to right, #547ef4, #679ff5);
padding: 30rpx 30rpx;
padding-bottom: 100rpx;
.info {
color: #fff;
font-size: 26rpx;
line-height: 30rpx;
vertical-align: middle;
margin-top: 20rpx;
>.list {
display: flex;
justify-content: flex-start;
align-items: center;
&:not(:last-child) {
margin-bottom: 20rpx;
}
>.uni-icons {
margin-right: 10rpx;
}
}
}
.uni-data-tree {
::v-deep {
.input-value {
border: none;
padding-left: 0;
.selected-area {
width: 90%;
flex: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.selected-list {
color: #fff;
}
}
// 选择中的文字样式
.text-color {
color: #fff;
font-size: 34rpx;
line-height: 36rpx;
font-weight: bolder;
}
// 右侧箭头
.arrow-area {
transform: rotate(-135deg);
.input-arrow {
border-color: #fff;
}
}
}
}
}
}
// 基本信息
.base-info {
margin-top: -80rpx;

109
store/modules/site.js Normal file
View File

@ -0,0 +1,109 @@
import { getAllSites } from '@/api/ems/site.js'
const createSiteTypeOptions = () => ([
{
text: '储能',
value: 'cn',
children: []
},
{
text: '光能',
value: 'gn',
children: []
},
{
text: '岸电',
value: 'ad',
children: []
}
])
const site = {
state: {
siteOptions: [],
siteTypeOptions: [],
currentSiteId: '',
loaded: false
},
mutations: {
SET_SITE_OPTIONS: (state, siteOptions) => {
state.siteOptions = siteOptions || []
},
SET_SITE_TYPE_OPTIONS: (state, siteTypeOptions) => {
state.siteTypeOptions = siteTypeOptions || createSiteTypeOptions()
},
SET_CURRENT_SITE_ID: (state, siteId) => {
state.currentSiteId = siteId || ''
},
SET_SITE_LOADED: (state, loaded) => {
state.loaded = !!loaded
}
},
actions: {
LoadSites({ state, rootState, commit }, payload = {}) {
const { force = false } = payload
if (state.loaded && !force) {
return Promise.resolve({
siteOptions: state.siteOptions,
siteTypeOptions: state.siteTypeOptions,
siteId: state.currentSiteId
})
}
return getAllSites().then(response => {
const belongSite = rootState?.user?.belongSite || []
const canAccessAll = !belongSite || belongSite.length === 0 || belongSite.includes('all')
const siteOptions = (response?.data || []).filter(item => {
const siteId = item.siteId || ''
return canAccessAll || belongSite.includes(siteId)
}).map(item => {
const siteId = item.siteId || ''
const siteType = (item.siteType || item.type || 'cn').toString().toLowerCase()
return {
text: item.siteName,
value: siteId,
id: item.id,
longitude: Number(item.longitude || 0),
latitude: Number(item.latitude || 0),
siteType
}
})
const siteTypeOptions = createSiteTypeOptions().map(typeItem => ({
...typeItem,
children: []
}))
siteOptions.forEach(item => {
const typeOption = siteTypeOptions.find(i => i.value === item.siteType) || siteTypeOptions.find(i => i.value === 'cn')
if (!typeOption) return
typeOption.children.push({
text: item.text,
value: item.value,
id: item.id
})
})
const filteredSiteTypeOptions = siteTypeOptions.filter(item => (item.children || []).length > 0)
const availableSite = siteOptions[0]
const keepCurrent = siteOptions.find(item => item.value === state.currentSiteId)
commit('SET_SITE_OPTIONS', siteOptions)
commit('SET_SITE_TYPE_OPTIONS', filteredSiteTypeOptions)
commit('SET_CURRENT_SITE_ID', keepCurrent ? keepCurrent.value : (availableSite?.value || ''))
commit('SET_SITE_LOADED', true)
return {
siteOptions,
siteTypeOptions: filteredSiteTypeOptions,
siteId: keepCurrent ? keepCurrent.value : (availableSite?.value || '')
}
})
},
SetCurrentSiteId({ commit }, siteId) {
commit('SET_CURRENT_SITE_ID', siteId)
},
ClearSiteState({ commit }) {
commit('SET_SITE_OPTIONS', [])
commit('SET_SITE_TYPE_OPTIONS', [])
commit('SET_CURRENT_SITE_ID', '')
commit('SET_SITE_LOADED', false)
}
}
}
export default site

View File

@ -21,16 +21,25 @@ const request = config => {
config.url = url
}
return new Promise((resolve, reject) => {
const requestUrl = config.baseUrl || baseUrl + config.url
const requestMethod = (config.method || 'get').toUpperCase()
uni.request({
method: config.method || 'get',
timeout: config.timeout || timeout,
url: config.baseUrl || baseUrl + config.url,
url: requestUrl,
data: config.data,
header: config.header,
dataType: 'json'
}).then(response => {
let [error, res] = response
if (error) {
const errorType = error?.errMsg || error?.message || 'UNKNOWN_ERROR'
console.error('[request:error]', {
url: requestUrl,
method: requestMethod,
errorType,
rawError: error
})
toast('后端接口连接异常')
reject('后端接口连接异常')
return
@ -57,6 +66,15 @@ const request = config => {
})
.catch(error => {
let { message } = error
const rawMessage = message || ''
let errorType = 'UNKNOWN_ERROR'
if (rawMessage === 'Network Error') {
errorType = 'NETWORK_ERROR'
} else if (rawMessage.includes('timeout')) {
errorType = 'TIMEOUT'
} else if (rawMessage.includes('Request failed with status code')) {
errorType = 'HTTP_STATUS_ERROR'
}
if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
@ -64,6 +82,13 @@ const request = config => {
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
console.error('[request:catch]', {
url: requestUrl,
method: requestMethod,
errorType,
message: rawMessage,
rawError: error
})
toast(message)
reject(error)
})