初始提交
107
pages/portal/applyPortal/index.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<view class="scan-v">
|
||||
<mescroll-body ref="mescrollRef" @down="downCallback" :down="downOption" :sticky="true" @up="upCallback"
|
||||
:up="upOption" :bottombar="false" style="min-height: 100%" @init="mescrollInit">
|
||||
<view class="portal-v">
|
||||
<view v-if="formData.length">
|
||||
<view class="portal-box" v-for="(item,index) in formData" :key="index">
|
||||
<portalItem :item='item' ref="portalItem"></portalItem>
|
||||
</view>
|
||||
</view>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import portalItem from '@/pages/portal//components/index.vue'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
|
||||
import {
|
||||
getPreviewPortal,
|
||||
auth
|
||||
} from '@/api/portal/portal.js'
|
||||
export default {
|
||||
mixins: [MescrollMixin],
|
||||
components: {
|
||||
portalItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: '',
|
||||
show: false,
|
||||
formData: [],
|
||||
dataList: [],
|
||||
downOption: {
|
||||
use: true,
|
||||
auto: true
|
||||
},
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 50,
|
||||
time: null
|
||||
},
|
||||
empty: {
|
||||
use: false,
|
||||
},
|
||||
textNoMore: this.$t('app.apply.noMoreData'),
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
uni.setStorageSync('token', e.token)
|
||||
this.id = e.id
|
||||
uni.$on('refresh', () => {
|
||||
this.formData = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
upCallback(keyword) {
|
||||
this.mescroll.lockDownScroll(true);
|
||||
auth(this.id).then(res => {
|
||||
let data = res.data.formData ? JSON.parse(res.data.formData) : {};
|
||||
this.formData = data.layout ? JSON.parse(JSON.stringify(data.layout)) : [];
|
||||
this.mescroll.endSuccess(this.formData.length);
|
||||
if (!this.formData.length) return
|
||||
this.handelFormData(data)
|
||||
}).catch(() => {
|
||||
this.mescroll.endSuccess(0);
|
||||
this.mescroll.endErr();
|
||||
})
|
||||
},
|
||||
handelFormData(data) {
|
||||
const loop = (list) => {
|
||||
list.forEach(o => {
|
||||
o.allRefresh = data.refresh
|
||||
o.show = false
|
||||
if (o.visibility && o.visibility.length && o.visibility.includes('app')) o.show =
|
||||
true
|
||||
if (o.children && o.children.length) loop(o.children)
|
||||
})
|
||||
this.key = +new Date()
|
||||
}
|
||||
loop(this.formData)
|
||||
this.dataList = this.formData.filter(o => o.show)
|
||||
if (this.dataList.length < 1) {
|
||||
this.formData = this.dataList
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.portal-nodata {
|
||||
position: absolute;
|
||||
top: 450rpx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 100;
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
</style>
|
||||
145
pages/portal/components/HCard/index.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<view class="card-v">
|
||||
<uni-card padding="0px" margin="0px" spacing="0px" :border="false">
|
||||
<template #title v-if="cardData.title">
|
||||
<view class="u-flex card-content" :style="{'background-color':cardData.card.titleBgColor}">
|
||||
<view class="u-flex left"
|
||||
:style="{'justify-content':cardData.card.titleLeft==='left'?'flex-start':cardData.card.titleLeft==='right'?'flex-end':'center'}">
|
||||
<view class="u-flex">
|
||||
<view :class="cardData.card.cardIcon?cardData.card.cardIcon:'icon'"
|
||||
:style="{'color':cardData.card.cardIconColor}"></view>
|
||||
<view class="txt u-line-1"
|
||||
:style="{'color':cardData.card.titleFontColor,'font-size':cardData.card.titleFontSize*2+'rpx','font-weight':cardData.card.titleFontWeight?700:400}">
|
||||
{{cardData.title}}
|
||||
</view>
|
||||
<span v-if="cardData.viceTitle" class="u-m-l-10"
|
||||
:style="{'color':cardData.card.viceTitleFontColor,'font-size':cardData.card.viceTitleFontSize*2+'rpx'}">{{cardData.viceTitle}}</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="link" @click="jump">
|
||||
<view class="u-line-1" style="color: #2979ff;">
|
||||
{{cardData.card.cardRightBtn}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="card-actions">
|
||||
<slot name="content"></slot>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
cardData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
'title': "",
|
||||
'viceTitle': '',
|
||||
'card': {
|
||||
'titleBgColor': "#fff",
|
||||
'cardIcon': "",
|
||||
'titleFontColor': '#6a6a6a',
|
||||
'viceTitleFontColor': '#606266',
|
||||
'titleFontSize': 14,
|
||||
'viceTitleFontSize': 12,
|
||||
'titleFontWeight': false,
|
||||
'cardRightBtn': '',
|
||||
'titleLeft': 'left'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
jump() {
|
||||
if (this.cardData.platform === 'mp') return
|
||||
let url;
|
||||
if (!this.cardData.card.appLinkType) return
|
||||
if (this.cardData.card.appLinkType == 1 && this.cardData.card.appType == 8) {
|
||||
let propertyJson = JSON.parse(this.cardData.card.appPropertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId + "&protalType=1" +
|
||||
"&fullName=" + this.cardData.card.cardRightBtn || '',
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
}
|
||||
if (this.cardData.card.appLinkType == 1) {
|
||||
let data = {
|
||||
id: this.cardData.card.appModuleId,
|
||||
moduleId: this.cardData.card.appModuleId,
|
||||
urlAddress: this.cardData.card.appUrlAddress,
|
||||
...JSON.parse(this.cardData.card.appPropertyJson)
|
||||
}
|
||||
if (this.cardData.card.appType == 3) {
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
} else if (this.cardData.card.appType == 2) {
|
||||
url = this.cardData.card.appUrlAddress + '?menuId=' + this.cardData.card.appModuleId
|
||||
} else {
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(this.cardData.card.appUrlAddress)
|
||||
}
|
||||
} else {
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(this.cardData.card.appUrlAddress)
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.card-v {
|
||||
::v-deep .uni-card--shadow {
|
||||
box-shadow: none !important;
|
||||
border: 2rpx solid #f0f2f6;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 0rpx 20rpx;
|
||||
width: 100%;
|
||||
min-height: 90rpx;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2rpx solid #f0f2f6;
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.center {
|
||||
line-height: 40rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.icon {
|
||||
border-left: 4px solid #1890ff;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.txt {
|
||||
max-width: 437rpx;
|
||||
height: 100%;
|
||||
padding-left: 16rpx;
|
||||
|
||||
}
|
||||
|
||||
.link {
|
||||
min-width: 60rpx;
|
||||
max-width: 232rpx;
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
120
pages/portal/components/HCarousel/index.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<view class="dataBoard-v">
|
||||
<view class="dataBoard-box">
|
||||
<u-swiper :list="list" v-if="swiper" height="300" mode='rect'
|
||||
:indicator-pos="option.carouselIndicatorPosition" :autoplay="option.carouselAutoplay"
|
||||
:interval="option.carouselInterval" :img-mode="option.imageFillStyle" :title="true"
|
||||
:title-style="option.titleStyle" @click="swiperC" name="imageUrl" :effect3d="option.carouselType">
|
||||
</u-swiper>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import jnpf from '@/utils/jnpf'
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
propsApi: '',
|
||||
list: [],
|
||||
swiper: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.titleStyle = {
|
||||
"text-align": this.option.textLeft,
|
||||
"font-size": this.option.textFontSize * 2 + 'rpx',
|
||||
"font-weight": this.option.textFontWeight ? 700 : 400,
|
||||
'color': this.option.textFontColor,
|
||||
'background-color': this.option.textBgColor
|
||||
}
|
||||
this.option.carouselIndicatorPosition = this.option.carouselIndicatorPosition ===
|
||||
"bottomRight" ? "bottomCenter" : this.option.carouselIndicatorPosition ===
|
||||
"topLeft" ? "topCenter" : "none"
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
async initData() {
|
||||
this.swiper = false
|
||||
let val = JSON.parse(JSON.stringify(this.option.appDefaultValue));
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
let ele = val[i]
|
||||
ele.title = ele.textDefaultValue
|
||||
if (ele.dataType == 3) {
|
||||
const res = await getDataInterfaceRes(ele.propsApi, {})
|
||||
ele.imageUrl = res?.data ? res.data : ''
|
||||
}
|
||||
if (ele.dataType == 1) ele.imageUrl = jnpf.getAuthImgUrl(ele.imageUrl)
|
||||
}
|
||||
this.list = val;
|
||||
this.$nextTick(() => {
|
||||
this.swiper = true
|
||||
})
|
||||
},
|
||||
swiperC(e) {
|
||||
if (this.config.platform === 'mp') return
|
||||
let item = this.option.appDefaultValue[e]
|
||||
let url = '';
|
||||
if (item.linkType == 1 && item.type == 8) {
|
||||
let propertyJson = JSON.parse(item.propertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId + "&protalType=1" +
|
||||
"&fullName=" + item.textDefaultValue || '',
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
}
|
||||
if (item.linkType == '1') {
|
||||
let data = {
|
||||
id: item.moduleId,
|
||||
moduleId: item.moduleId,
|
||||
urlAddress: item.urlAddress,
|
||||
...JSON.parse(item.propertyJson)
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
if (item.type == '2') url = item.urlAddress
|
||||
} else {
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(item.urlAddress)
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.dataBoard-v {
|
||||
padding: 20rpx;
|
||||
|
||||
.dataBoard-box {
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
164
pages/portal/components/HCharts/charts.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<view class="charts-v">
|
||||
<view class="qiun-title-bar u-flex" :style="{'justify-content':config.option.chartTitle.titleLeft}"
|
||||
v-if="config.option.chartTitle.titleText || config.option.chartTitle.titleSubtext">
|
||||
<view class="u-flex-col titleBox" :style="{'background-color':config.option.chartTitle.titleBgColor}">
|
||||
<view class="tit"
|
||||
:style="{'margin-bottom':config.option.chartTitle.titleSubtext?'8rpx':0,'font-size':config.option.chartTitle.titleTextStyleFontSize,'font-weight':config.option.chartTitle.titleTextStyleFontWeight,'color':config.option.chartTitle.titleTextStyleColor}">
|
||||
{{config.option.chartTitle.titleText}}
|
||||
</view>
|
||||
<view class="tit2"
|
||||
:style="{'font-size':config.option.chartTitle.titleSubtextStyleFontSize,'font-weight':config.option.chartTitle.titleSubtextStyleFontWeight,'color':config.option.chartTitle.titleSubtextStyleColor}">
|
||||
{{config.option.chartTitle.titleSubtext}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="regionStep" v-if="regionStep.length >1">
|
||||
<text v-for="(item,index) in regionStep" @click="regionStepClick(item,index)" :key="index"
|
||||
:style="{'font-size':config.option.drillDownFontSize*2+'rpx','color':config.option.drillDownColor,'font-weight':config.option.drillDownFontWeight?700:400}">
|
||||
{{item.name}}
|
||||
<u-icon name="arrow-right" v-if="index!=regionStep.length-1" class="icon"></u-icon>
|
||||
</text>
|
||||
</view>
|
||||
<view class="charts-box">
|
||||
<qiun-data-charts v-if="config.option.chartData.series.length" :type="config.option.chartData.type"
|
||||
:chartData="config.option.chartData" :ontouch="true" :opts="config.option.chartData.opts"
|
||||
@complete="complete" @getIndex="getIndex" :style="{'background-color':config.option.bgColor}"
|
||||
:connectNulls="true" />
|
||||
<view class="" v-if="config.jnpfKey==='mapChart' && config.option.chartData.series.length>0 && loading"
|
||||
:key="key">
|
||||
<block v-for="(item, index) in config.option.markPoints" :key="index">
|
||||
<view :class="config.option.styleType == 2?'points-box2':'points-box'"
|
||||
:style="{top:(item.y - 5 ) + 'px',left:(item.x - 5) +'px'}"></view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
markPoints: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
regionStep: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
complete(e) {
|
||||
this.$emit('complete', e)
|
||||
},
|
||||
getIndex(e) {
|
||||
return this.$emit('getIndex', e)
|
||||
},
|
||||
regionStepClick(item, index) {
|
||||
if (index < this.regionStep.length - 1) return this.$emit('regionStepClick', item, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.charts-v {
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.qiun-title-bar {
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 40rpx;
|
||||
margin: 20rpx 0;
|
||||
|
||||
.titleBox {
|
||||
.tit {
|
||||
// margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.regionStep {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin-bottom: 60rpx;
|
||||
position: absolute;
|
||||
top: 0rpx;
|
||||
z-index: 9999;
|
||||
|
||||
.icon {
|
||||
margin: 0 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.charts-box {
|
||||
width: 100%;
|
||||
height: 660rpx;
|
||||
// margin: 0px auto 20rpx;
|
||||
position: relative;
|
||||
|
||||
.charts-legend {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 20rpx;
|
||||
font-size: 20rpx;
|
||||
|
||||
.legend-item {
|
||||
display: inline-block;
|
||||
width: 30rpx;
|
||||
height: 20rpx;
|
||||
margin-right: 10rpx;
|
||||
background-color: #0D9FD8;
|
||||
}
|
||||
}
|
||||
|
||||
.points-box {
|
||||
position: absolute;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #0D9FD8;
|
||||
animation: warn 1.5s ease-out 0s infinite;
|
||||
}
|
||||
|
||||
.points-box2 {
|
||||
position: absolute;
|
||||
box-shadow: 0 0 24rpx 28rpx rgba(13, 159, 261, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes warn {
|
||||
0% {
|
||||
transform: scale(0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.4);
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
37
pages/portal/components/HCharts/index.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<view class="charts" v-if="show">
|
||||
<charts :config="config" :key="key" @getIndex="getIndex" @complete='complete' :markPoints="markPoints"
|
||||
:regionStep="regionStep" @regionStepClick="regionStepClick" ref="charts" :loading="pointLoading"></charts>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import charts from './charts.vue'
|
||||
import chartsJs from '../chartsJs.js'
|
||||
export default {
|
||||
mixins: [chartsJs],
|
||||
components: {
|
||||
charts
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
key: +new Date(),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
complete(e) {
|
||||
if (this.config.jnpfKey === 'mapChart') this.setPoints(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.charts {
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
134
pages/portal/components/HCommonFunc/index.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<view class="HTodo-v" :key="key">
|
||||
<view class="HTodo-box u-flex">
|
||||
<view class="HTodo-list u-flex" :style="{'flex-wrap':option.appStyleType==1?'nowrap':'wrap'}">
|
||||
<view class="u-flex-col HTodo-list-item" v-for="(item,index) in option.appDefaultValue" :key="index"
|
||||
@click="jump(item)" :style="option.style">
|
||||
<view class="" style="position: relative;margin-bottom: 8rpx;">
|
||||
<view :class="item.icon" class="icon"
|
||||
:style="{'background-color':item.iconColor||item.iconBgColor || '#008cff'}"></view>
|
||||
</view>
|
||||
<view class="u-line-1 title"
|
||||
:style="{'font-size':option.labelFontSize,'color':option.labelFontColor,'font-weight':option.labelFontWeight?700:400}">
|
||||
{{item.fullName}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initData()
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.appDefaultValue.map((o) => {
|
||||
if (o.fullNameI18nCode) o.fullName = this.$t(o.fullNameI18nCode)
|
||||
})
|
||||
let style;
|
||||
style = {
|
||||
'width': '240rpx'
|
||||
}
|
||||
if (this.option.appStyleType == 2) {
|
||||
style = {
|
||||
'width': this.option.appDefaultValue.lenght < 2 ? "" : 100 / this.option.appRowNumber + '%'
|
||||
}
|
||||
if (this.option.appShowBorder) {
|
||||
style['border-right'] = '2rpx solid #f0f2f6'
|
||||
style['border-bottom'] = '2rpx solid #f0f2f6'
|
||||
}
|
||||
}
|
||||
this.option.style = style
|
||||
this.option.labelFontSize = this.option.labelFontSize * 2 + 'rpx'
|
||||
this.key = +new Date()
|
||||
},
|
||||
jump(item) {
|
||||
if (this.config.platform === 'mp') return
|
||||
let url;
|
||||
if (item.linkType == 1 && (item.type == 3 || item.type == 9)) {
|
||||
let data = {
|
||||
id: item.moduleId,
|
||||
moduleId: item.moduleId,
|
||||
urlAddress: item.urlAddress,
|
||||
type: item.type,
|
||||
fullName: item.fullName,
|
||||
...JSON.parse(item.propertyJson)
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
} else if (item.linkType == 1 && item.type == 2) {
|
||||
url = item.urlAddress
|
||||
} else if (item.linkType == 1 && item.type == 8) {
|
||||
let propertyJson = JSON.parse(item.propertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId +
|
||||
"&portalType=1&fullName=" +
|
||||
item.fullName,
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
} else {
|
||||
if (!item.urlAddress) return
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(item.urlAddress) +
|
||||
'&fullName= ' + item.fullName
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
// this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.HTodo-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.HTodo-box {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.HTodo-list {
|
||||
width: 100%;
|
||||
|
||||
.HTodo-list-item {
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
font-size: 60rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
120
pages/portal/components/HCustomeCharts/charts.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<view class="charts-v">
|
||||
<view class="charts-box">
|
||||
<qiun-data-charts :type="config.appOption.type" :chartData="config.appOption.chartData" :ontouch="true"
|
||||
:opts="config.appOption.opts"
|
||||
:style="{'background-color':config.appOption.bgColor?config.appOption.bgColor:''}"
|
||||
:connectNulls="true" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
complete(e) {
|
||||
this.$emit('complete', e)
|
||||
},
|
||||
getIndex(e) {
|
||||
return this.$emit('getIndex', e)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.charts-v {
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.qiun-title-bar {
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 40rpx;
|
||||
margin: 20rpx 0;
|
||||
|
||||
.titleBox {
|
||||
.tit {
|
||||
// margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.regionStep {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin-bottom: 60rpx;
|
||||
position: absolute;
|
||||
top: 0rpx;
|
||||
z-index: 9999;
|
||||
|
||||
.icon {
|
||||
margin: 0 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.charts-box {
|
||||
width: 100%;
|
||||
height: 660rpx;
|
||||
// margin: 0px auto 20rpx;
|
||||
position: relative;
|
||||
|
||||
.charts-legend {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 20rpx;
|
||||
font-size: 20rpx;
|
||||
|
||||
.legend-item {
|
||||
display: inline-block;
|
||||
width: 30rpx;
|
||||
height: 20rpx;
|
||||
margin-right: 10rpx;
|
||||
background-color: #0D9FD8;
|
||||
}
|
||||
}
|
||||
|
||||
.points-box {
|
||||
position: absolute;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #0D9FD8;
|
||||
animation: warn 1.5s ease-out 0s infinite;
|
||||
}
|
||||
|
||||
.points-box2 {
|
||||
position: absolute;
|
||||
box-shadow: 0 0 24rpx 28rpx rgba(13, 159, 261, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes warn {
|
||||
0% {
|
||||
transform: scale(0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.4);
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
66
pages/portal/components/HCustomeCharts/index.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<view class="charts" v-if="show">
|
||||
<charts :config="config" :key="key" ref="charts"></charts>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import charts from './charts.vue'
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
export default {
|
||||
components: {
|
||||
charts
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
key: +new Date(),
|
||||
show: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
async init() {
|
||||
// 提取视图初始化逻辑
|
||||
const initializeView = () => {
|
||||
this.show = true;
|
||||
this.key = Date.now();
|
||||
};
|
||||
if (this.config.appDataType === 'dynamic') {
|
||||
if (!this.config.appPropsApi) return;
|
||||
try {
|
||||
const res = await getDataInterfaceRes(
|
||||
this.config.appPropsApi, {
|
||||
paramList: this.config.appTemplateJson
|
||||
}
|
||||
);
|
||||
this.config.appOption = Object.assign({},
|
||||
this.config.appOption,
|
||||
res.data
|
||||
);
|
||||
initializeView();
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch app props:', error);
|
||||
}
|
||||
}
|
||||
// 静态数据类型的处理
|
||||
else {
|
||||
initializeView();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.charts {
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
172
pages/portal/components/HDataBoard/index.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="HTodo-v" :key="key">
|
||||
<view class="HTodo-box u-flex">
|
||||
<view class="HTodo-list u-flex" :style="{'flex-wrap':option.appStyleType==1?'nowrap':'wrap'}">
|
||||
<view class="u-flex-col HTodo-list-item" v-for="(item,index) in option.appDefaultValue" :key="index"
|
||||
@click="jump(item)" :style="option.style">
|
||||
<view class=" u-m-b-8">
|
||||
<view :class="item.icon" class="icon"
|
||||
:style="{'background-color':item.iconColor||item.iconBgColor || '#008cff'}"></view>
|
||||
</view>
|
||||
<view class="u-line-1 title"
|
||||
:style="{'font-size':option.labelFontSize,'color':option.labelFontColor,'font-weight':option.labelFontWeight?700:400}">
|
||||
{{item.fullName}}
|
||||
</view>
|
||||
<view class="u-line-1 title"
|
||||
:style="{'font-size':option.valueFontSize,'color':option.valueFontColor,'font-weight':option.valueFontWeight?700:400}">
|
||||
{{item.num+' '}}
|
||||
<text
|
||||
:style="{'font-size':option.unitFontSize,'color':option.unitFontColor,'font-weight':option.unitFontWeight?700:400}">{{item.unit}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
propsApi: '',
|
||||
key: +new Date(),
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.appDefaultValue.map((o) => {
|
||||
if (o.fullNameI18nCode) o.fullName = this.$t(o.fullNameI18nCode)
|
||||
})
|
||||
let style;
|
||||
style = {
|
||||
'width': '238rpx'
|
||||
}
|
||||
if (this.option.appStyleType == 2) {
|
||||
style.width = 100 / this.option.appRowNumber + '%'
|
||||
if (this.option.appShowBorder) {
|
||||
style['border-right'] = '2rpx solid #f0f2f6'
|
||||
style['border-bottom'] = '2rpx solid #f0f2f6'
|
||||
}
|
||||
}
|
||||
this.option.style = style
|
||||
this.option.appDefaultValue = this.option.appDefaultValue.filter((o) => !o.noShow)
|
||||
if (this.config.dataType == 'dynamic') {
|
||||
for (let i = 0; i < this.option.appDefaultValue.length; i++) {
|
||||
this.option.appDefaultValue[i].num = '';
|
||||
}
|
||||
if (!this.config.propsApi) return;
|
||||
let list = this.option.appDefaultValue || []
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
for (let i = 0; i < this.option.appDefaultValue.length; i++) {
|
||||
const list = this.option.appDefaultValue[i]
|
||||
list.num = list.field ? res.data[list.field] : '';
|
||||
}
|
||||
this.handleAttrs()
|
||||
})
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
handleAttrs() {
|
||||
this.option.valueFontSize = this.option.valueFontSize * 2 + 'rpx'
|
||||
this.option.unitFontSize = this.option.unitFontSize * 2 + 'rpx'
|
||||
this.key = +new Date()
|
||||
},
|
||||
jump(item) {
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
if (this.config.platform === 'mp') return
|
||||
let url;
|
||||
if (item.linkType == 1 && item.type == 3) {
|
||||
let data = {
|
||||
id: item.moduleId,
|
||||
moduleId: item.moduleId,
|
||||
urlAddress: item.urlAddress,
|
||||
...JSON.parse(item.propertyJson)
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
} else if (item.linkType == 1 && item.type == 2) {
|
||||
url = item.urlAddress
|
||||
} else if (item.linkType == 1 && item.type == 8) {
|
||||
let propertyJson = JSON.parse(item.propertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId + "&protalType=1" +
|
||||
"&fullName=" + item.fullName,
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
} else {
|
||||
if (!item.urlAddress) return
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(item.urlAddress) +
|
||||
'&fullName= ' + item.fullName
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
// this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.HTodo-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.HTodo-box {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.HTodo-list {
|
||||
.HTodo-list-item {
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
font-size: 60rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
97
pages/portal/components/HEmail/index.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<view class="portal-todoList-box-body">
|
||||
<template v-if="list.length">
|
||||
<a class="item com-hover" v-for="(item, i) in list" :key="i">
|
||||
<span class="name">{{item.fullName}}</span>
|
||||
<span class="time">{{item.creatorTime | date('yyyy-mm-dd')}}</span>
|
||||
</a>
|
||||
</template>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getEmail
|
||||
} from '@/api/home'
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
getEmail().then(res => {
|
||||
this.list = res.data.list.slice(0, 7)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.portal-todoList-box-body {
|
||||
padding: 42rpx 10rpx 10rpx;
|
||||
max-height: 472rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
line-height: 40rpx;
|
||||
font-size: 0;
|
||||
margin-bottom: 24rpx;
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
width: calc(100% - 180rpx);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
width: 180rpx;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
130
pages/portal/components/HImage/index.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<view class="image-v">
|
||||
<view class="custom-cover" @click="jump()">
|
||||
<image class="cover-image" :mode="option.imageFillStyle" :src="imgUrl"></image>
|
||||
<view class="cover-content"
|
||||
:style="{'justify-content':option.textLeft,'background-color':option.textBgColor}">
|
||||
<text class=" uni-subtitle uni-white"
|
||||
:style="{'text-decoration':option.textUnderLine,'color':option.textFontColor,'font-weight':option.textFontWeight?700:0,'font-size':option.textFontSize}">{{option.textDefaultValue}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
import jnpf from '@/utils/jnpf'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
imgUrl: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.imageFillStyle = this.option.imageFillStyle === 'fill' ? 'scaleToFill' : this.option
|
||||
.imageFillStyle === 'cover' ? ' aspectFill' : 'aspectFit'
|
||||
this.option.textFontSize = this.option.textFontSize * 2 + 'rpx'
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
if (this.option.styleType == 1) this.imgUrl = jnpf.getAuthImgUrl(this.option.defaultValue)
|
||||
if (this.option.styleType == 2) this.imgUrl = this.option.defaultValue
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.imgUrl = toString.call(res.data) === `[object String]` ? res.data : ''
|
||||
})
|
||||
}
|
||||
},
|
||||
jump() {
|
||||
if (this.config.platform === 'mp') return
|
||||
let url = '';
|
||||
if (this.config.option.appLinkType == 1 && this.config.option.appType == 3) {
|
||||
let data = {
|
||||
id: this.config.option.appModuleId,
|
||||
moduleId: this.config.option.appModuleId,
|
||||
urlAddress: this.config.option.appUrlAddress,
|
||||
...JSON.parse(this.config.option.propertyJson)
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
} else if (this.config.option.appLinkType == 1 && this.config.option.appType == 2) {
|
||||
url = this.config.option.appUrlAddress
|
||||
} else if (this.config.option.appLinkType == 1 && this.config.option.appType == 8) {
|
||||
let propertyJson = JSON.parse(this.config.option.appPropertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId + "&protalType=1" +
|
||||
"&fullName=" + this.config.option.textDefaultValue || '',
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
} else {
|
||||
if (!this.config.option.appUrlAddress) return
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(this.config.option.appUrlAddress) +
|
||||
'&fullName= ' + this.config.option.fullName
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
// this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.image-v {
|
||||
.custom-cover {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
margin: 20rpx 0;
|
||||
|
||||
.cover-image {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cover-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
227
pages/portal/components/HNotice/index.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<view class="notice-v">
|
||||
<template v-if="list.length">
|
||||
<view class="item-box u-p-l-20 u-p-r-20" v-for="(item,index) in list" :key="index">
|
||||
<view class="u-flex item u-m-t-20 u-p-b-20" v-if="option.appStyleType == 1" @click="readInfo(item)"
|
||||
:style="{'border-bottom':index == list.length-1?'none':'2rpx solid #f0f2f6'}">
|
||||
<view class="img-box">
|
||||
<u-image width="90rpx" height="90rpx" v-if="item.category=='公告'" shape="circle"
|
||||
:src="!item.coverImage? gg : jnpf.getAuthImgUrl(item.coverImage)"></u-image>
|
||||
<u-image v-else width="90rpx" height="90rpx" shape="circle"
|
||||
:src="!item.coverImage?tz:jnpf.getAuthImgUrl(item.coverImage)"></u-image>
|
||||
</view>
|
||||
<view class="u-p-l-20 item-right">
|
||||
<view class="u-flex u-m-b-20">
|
||||
<text class="notice-type u-p-l-10 u-p-r-10 u-font-24" v-if="option.appColumnList[0].show"
|
||||
:style="{'color':item.category=='公告'?'#9a00f3':'#1448f4','background-color':item.category=='公告'?'#ebe6ff':'#e5ebfe'}">{{item.category}}</text>
|
||||
<view class="u-line-1 u-p-l-10 u-p-r-10 name" v-if="option.appColumnList[1].show"
|
||||
:style="{'font-size':option.appColumnList[1].fontSize*2+'rpx','font-weight':option.appColumnList[1].fontWeight?'700':'400','color':option.appColumnList[1].fontColor}">
|
||||
{{item.fullName}}
|
||||
</view>
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-if="option.appColumnList[3].show && option.appColumnList[3].timeClassify ==1">{{$u.timeFormat(item.creatorTime,'mm-dd hh:MM')}}</text>
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-if="option.appColumnList[3].show && option.appColumnList[3].timeClassify == 2">{{$u.timeFormat(item.releaseTime,'mm-dd hh:MM')}}</text>
|
||||
</view>
|
||||
<view class="u-line-1 u-p-r-10 content2 u-m-t-20" v-if="option.appColumnList[2].show"
|
||||
:style="{'font-size':option.appColumnList[2].fontSize*2+'rpx','font-weight':option.appColumnList[1].fontWeight?'700':'400','color':option.appColumnList[2].fontColor}">
|
||||
{{item.excerpt}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-flex item u-m-t-20 u-p-b-20" v-if="option.appStyleType == 2" @click="readInfo(item)"
|
||||
:style="{'border-bottom':index == list.length-1?'none':'2rpx solid #f0f2f6'}">
|
||||
<view class="img-box">
|
||||
<u-image width="90rpx" height="90rpx" v-if="item.category=='公告'" shape="circle"
|
||||
:src="!item.coverImage? gg : jnpf.getAuthImgUrl(item.coverImage)"></u-image>
|
||||
<u-image v-else width="90rpx" height="90rpx" shape="circle"
|
||||
:src="!item.coverImage?tz:jnpf.getAuthImgUrl(item.coverImage)"></u-image>
|
||||
</view>
|
||||
<view class="u-p-l-20 u-flex-col" style="flex: 1;">
|
||||
<view class="u-flex u-m-b-10" style="width: 100%;height: 100%;">
|
||||
<view class="notice-type u-p-l-10 u-p-r-10 u-font-24"
|
||||
:style="{'color':item.category=='公告'?'#9a00f3':'#1448f4','background-color':item.category=='公告'?'#ebe6ff':'#e5ebfe'}"
|
||||
v-if="option.appColumnList[0].show">{{item.category=='公告'?'公告':'通知'}}</view>
|
||||
<view class="u-line-1 u-p-l-10 u-p-r-10 name" v-if="option.appColumnList[1].show"
|
||||
:style="{'font-size':option.appColumnList[1].fontSize*2+'rpx','font-weight':option.appColumnList[1].fontWeight?'700':'400','color':option.appColumnList[1].fontColor}">
|
||||
{{item.fullName}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-line-1 u-p-r-10 content2" v-if="option.appColumnList[2].show"
|
||||
:style="{'font-size':option.appColumnList[2].fontSize*2+'rpx','font-weight':option.appColumnList[1].fontWeight?'700':'400','color':option.appColumnList[2].fontColor}">
|
||||
{{item.excerpt}}
|
||||
</view>
|
||||
<view class="">
|
||||
<text
|
||||
:style="{'font-size':option.appColumnList[4].fontSize*2+'rpx','font-weight':option.appColumnList[4].fontWeight?'700':'400','color':option.appColumnList[4].fontColor}">{{option.appColumnList[4].userClassify==2? item.releaseUser : item.creatorUser}}</text>
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-if="option.appColumnList[3].show && option.appColumnList[3].timeClassify == 1">{{$u.timeFormat(item.creatorTime,'mm-dd hh:MM')}}</text>
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-if="option.appColumnList[3].show && option.appColumnList[3].timeClassify == 2">{{$u.timeFormat(item.releaseTime,'mm-dd hh:MM')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-flex item u-m-t-20 u-p-b-20" v-if="option.appStyleType == 3" @click="readInfo(item)"
|
||||
:style="{'border-bottom':index == list.length-1?'none':'2rpx solid #f0f2f6'}">
|
||||
<text class="notice-type u-p-l-10 u-p-r-10 u-font-24"
|
||||
:style="{'color':item.category=='公告'?'#9a00f3':'#1448f4','background-color':item.category=='公告'?'#ebe6ff':'#e5ebfe'}"
|
||||
v-if="option.appColumnList[0].show">{{item.category=='公告'?'公告':'通知'}}</text>
|
||||
<text class="u-line-1 u-p-l-20 u-p-r-10 content" v-if="option.appColumnList[1].show"
|
||||
:style="{'font-size':option.appColumnList[1].fontSize*2+'rpx','font-weight':option.appColumnList[1].fontWeight?'700':'400','color':option.appColumnList[1].fontColor}">{{item.fullName}}</text>
|
||||
<view v-if="option.appColumnList[3].show">
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-if="option.appColumnList[3].timeClassify == 1">{{$u.timeFormat(item.creatorTime,'mm-dd hh:MM')}}</text>
|
||||
<text class="time"
|
||||
:style="{'font-size':option.appColumnList[3].fontSize*2+'rpx','font-weight':option.appColumnList[3].fontWeight?'700':'400','color':option.appColumnList[3].fontColor}"
|
||||
v-else>{{$u.timeFormat(item.releaseTime,'mm-dd hh:MM')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getNotice
|
||||
} from '@/api/home'
|
||||
import gg from '@/pages/portal/static/image/gg.png'
|
||||
import tz from '@/pages/portal/static/image/tz.png'
|
||||
import jnpf from '@/utils/jnpf'
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
typeList: [],
|
||||
gg,
|
||||
tz
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.appColumnList.map((o) => {
|
||||
if (o.fullNameI18nCode) o.fullName = this.$t(o.fullNameI18nCode)
|
||||
})
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.getData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
readInfo(item) {
|
||||
if (this.config.platform === 'mp') return
|
||||
uni.navigateTo({
|
||||
url: '/pages/message/messageDetail/index?id=' + item.id,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
},
|
||||
initData() {
|
||||
this.getData()
|
||||
},
|
||||
getData() {
|
||||
this.option.appColumnList.forEach((o, i) => {
|
||||
if (o.classify && o.classify.length) {
|
||||
this.typeList = o.classify
|
||||
}
|
||||
});
|
||||
let data = {
|
||||
typeList: this.typeList
|
||||
}
|
||||
getNotice(data).then(res => {
|
||||
let list = JSON.parse(JSON.stringify(res.data.list)) || []
|
||||
this.list = list.slice(0, this.option.appCount || 50)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.notice-v {
|
||||
max-height: 472rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
.item-box {
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.img-box {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
flex: 1;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.notice-type {
|
||||
border-radius: 8rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
max-width: 366rpx;
|
||||
}
|
||||
|
||||
.content2 {
|
||||
width: 540rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
float: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
204
pages/portal/components/HRankList/index.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<view class="rankList-v">
|
||||
<platform v-if="option.styleType==3 || option.styleType==4" :styleType="option.styleType" :option="option"
|
||||
:key="key" :props="props" />
|
||||
<view class="rankList-list">
|
||||
<view class="rankList-list-box">
|
||||
<view class="table-tr u-flex table-title">
|
||||
<view class="table-th u-flex" v-for="(item,index) in option.columnOptions" :key="index"
|
||||
:style="{'width':option.columnOptions.length>1&&option.columnOptions.length<=3?100 / option.columnOptions.length + '%':'208rpx'}">
|
||||
<view class="commin-padding u-line-1">
|
||||
{{item.label}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="table-tr u-flex" v-for="(tr,i) in option.defaultValue" :key="i" @tap="jump(tr)">
|
||||
<view class="table-td" v-for="(item,index) in option.columnOptions" :key="index"
|
||||
:style="{'width':option.columnOptions.length>1&&option.columnOptions.length<=3?100 / option.columnOptions.length + '%':'208rpx'}">
|
||||
<view class="commin-padding"
|
||||
v-if="item.value === 'pm'&& i+1 > 0 && i+1<4 && option.styleType!==3 && option.styleType!==4">
|
||||
<view class="image-box">
|
||||
<u-image :src='tr.imgUrl' width='60rpx' height='60rpx'>
|
||||
</u-image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="commin-padding" v-else>
|
||||
<view class="order" v-if="item.value === 'pm'" :style="option.styleType == 1?orderSty:''">
|
||||
<text>{{tr.index}}</text>
|
||||
</view>
|
||||
<view v-else class="u-line-1"
|
||||
:style="{'color':tr.index == 1?'rgb(206, 124, 31)':tr.index == 2?'rgb(111, 137, 172)':tr.index == 3?'rgb(141, 65, 18)':'#606266'}">
|
||||
{{tr[item.value]}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
import platform from './platform.vue'
|
||||
import ordinary0 from '@/pages/portal/static/image/ordinary0.png'
|
||||
import ordinary1 from '@/pages/portal/static/image/ordinary1.png'
|
||||
import ordinary2 from '@/pages/portal/static/image/ordinary2.png'
|
||||
import medal0 from '@/pages/portal/static/image/medal0.png'
|
||||
import medal1 from '@/pages/portal/static/image/medal1.png'
|
||||
import medal2 from '@/pages/portal/static/image/medal2.png'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
platform
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
orderSty: {
|
||||
'background': 'rgba(24, 144, 255, 0.39)',
|
||||
'border-radius': '50%',
|
||||
'opacity': 0.3,
|
||||
'color': '#fff'
|
||||
},
|
||||
option: {},
|
||||
props: {},
|
||||
ordinary0,
|
||||
ordinary1,
|
||||
ordinary2,
|
||||
medal0,
|
||||
medal1,
|
||||
medal2,
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
jump(item) {
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.jnpf.jumpLink(item.urlAddress)
|
||||
},
|
||||
init() {
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.props = {
|
||||
label: this.config.option.columnOptions[0].value,
|
||||
value: this.config.option.columnOptions[1].value
|
||||
}
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.option.columnOptions.unshift({
|
||||
label: '排名',
|
||||
value: 'pm'
|
||||
})
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.option.defaultValue = res.data || []
|
||||
this.handleAttrs()
|
||||
})
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
handleAttrs() {
|
||||
if (!Array.isArray(this.option.defaultValue)) return
|
||||
this.option.defaultValue.forEach((o, i) => {
|
||||
o.index = i + 1
|
||||
if (i <= 2) {
|
||||
o.imgUrl = this.option.styleType == 1 || this.option.styleType == 3 ?
|
||||
this[`ordinary${i}`] : this[`medal${i}`]
|
||||
}
|
||||
})
|
||||
if (this.option.styleType == 3 || this.option.styleType == 4) {
|
||||
this.option.frontValue = this.option.defaultValue.slice(0, 3)
|
||||
if (this.option.defaultValue.length <= 3) this.option.columnOptions = []
|
||||
let newVal = this.option.defaultValue.slice(3, this.option.defaultValue.length)
|
||||
this.option.defaultValue = newVal
|
||||
}
|
||||
this.key = +new Date()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.rankList-v {
|
||||
.rankList-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.rankList-list-box {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.table-tr {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.table-th,
|
||||
.table-td {
|
||||
height: 80rpx;
|
||||
border-bottom: 1px solid #EEF0F4;
|
||||
box-sizing: border-box;
|
||||
|
||||
.commin-padding {
|
||||
height: 100%;
|
||||
width: 200rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx;
|
||||
justify-content: center;
|
||||
|
||||
.image-box {
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.order {
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
text-align: center;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
|
||||
.table-th,
|
||||
.table-td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
233
pages/portal/components/HRankList/platform.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<view class="stage" v-if="show" :key='key'>
|
||||
<view class="cup-top-box" v-if="platformData.styleType == 3">
|
||||
<view class="cup1-box cup-box" v-for="(item,index) in frontValue" :key="index">
|
||||
<view class="img">
|
||||
<image :src="imgList[index].url"></image>
|
||||
</view>
|
||||
<view class="top-bg"></view>
|
||||
<view class="cup-box-content" :class="'cup-box-content'+index">
|
||||
<text class="txt">{{item[props.label]}}</text>
|
||||
<text class="txt">{{item[props.value]}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="medal-v" v-if="platformData.styleType == 4">
|
||||
<view class="medal-box u-flex">
|
||||
<view class="medal-box-inner" :class="'medal-box-inner'+index" v-for="(item,index) in frontValue"
|
||||
:key="index">
|
||||
<view class="img">
|
||||
<image :src="imgList2[index].url"></image>
|
||||
</view>
|
||||
<view class="u-flex-col txt-box">
|
||||
<text class='txt'>{{item[props.label]}}</text>
|
||||
<text class='txt'>{{item[props.value]}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import runnerUp from '@/pages/portal/static/image/runnerUp.png'
|
||||
import champion from '@/pages/portal/static/image/champion.png'
|
||||
import thirdPlace from '@/pages/portal/static/image/thirdPlace.png'
|
||||
import runnerUp2 from '@/pages/portal/static/image/runnerUp2.png'
|
||||
import champion2 from '@/pages/portal/static/image/champion2.png'
|
||||
import thirdPlace2 from '@/pages/portal/static/image/thirdPlace3.png'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
})
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
platformData: {},
|
||||
show: false,
|
||||
key: +new Date(),
|
||||
imgList: [{
|
||||
url: runnerUp
|
||||
}, {
|
||||
url: champion
|
||||
}, {
|
||||
url: thirdPlace
|
||||
}],
|
||||
imgList2: [{
|
||||
url: runnerUp2
|
||||
}, {
|
||||
url: champion2
|
||||
}, {
|
||||
url: thirdPlace2
|
||||
}]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
frontValue() {
|
||||
return this.platformData.frontValue || []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.platformData = JSON.parse(JSON.stringify(this.option)) || {}
|
||||
this.show = true
|
||||
this.key = +new Date()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.stage {
|
||||
.cup-top-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
overflow: hidden;
|
||||
padding: 20rpx 0 30rpx;
|
||||
|
||||
.cup-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
width: 100rpx;
|
||||
height: 96rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bg {
|
||||
width: 230rpx;
|
||||
height: 0;
|
||||
border-bottom: 10rpx solid rgba(239, 233, 225, .39);
|
||||
border-left: 20rpx solid transparent;
|
||||
border-right: 10rpx solid transparent;
|
||||
}
|
||||
|
||||
.cup-box-content {
|
||||
width: 230rpx;
|
||||
height: 90rpx;
|
||||
background: rgba(245, 241, 234, .59);
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #6f89ac;
|
||||
|
||||
.txt {
|
||||
font-size: 20rpx;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6F89AC;
|
||||
}
|
||||
}
|
||||
|
||||
.cup-box-content1 {
|
||||
height: 110rpx;
|
||||
|
||||
.txt {
|
||||
color: #CE7C1F;
|
||||
}
|
||||
}
|
||||
|
||||
.cup-box-content0 {
|
||||
.txt {
|
||||
color: #6F89AC;
|
||||
}
|
||||
}
|
||||
|
||||
.cup-box-content2 {
|
||||
.txt {
|
||||
color: #8D4112;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.medal-v {
|
||||
padding: 80rpx 0 0;
|
||||
|
||||
.medal-box {
|
||||
align-items: flex-end;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.medal-box-inner {
|
||||
width: 232rpx;
|
||||
height: 132rpx;
|
||||
border: 2rpx solid rgba(111, 137, 172, .59);
|
||||
position: relative;
|
||||
|
||||
.txt-box {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 100rpx;
|
||||
height: 96rpx;
|
||||
position: absolute;
|
||||
top: -60rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.txt {
|
||||
font-size: 20rpx;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
color: rgba(111, 137, 172, .59);
|
||||
}
|
||||
}
|
||||
|
||||
.medal-box-inner1 {
|
||||
width: 252rpx;
|
||||
height: 176rpx;
|
||||
border: 2rpx solid rgba(206, 124, 31, .59);
|
||||
margin: 0 6rpx;
|
||||
position: relative;
|
||||
|
||||
.txt {
|
||||
|
||||
color: rgba(206, 124, 31, .59);
|
||||
}
|
||||
}
|
||||
|
||||
.medal-box-inner2 {
|
||||
border: 2rpx solid rgba(141, 65, 18, .59);
|
||||
|
||||
.txt-box {
|
||||
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.txt {
|
||||
color: rgba(141, 65, 18, .59);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
127
pages/portal/components/HTable/index.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<view class="tabs-v">
|
||||
<template v-if="option.defaultValue && option.defaultValue.length">
|
||||
<scroll-view scroll-y="true" :style="option.defaultValue<5?'' :'height: 620rpx'">
|
||||
<div v-for="(item, i) in option.defaultValue" :key="i">
|
||||
<div class="app-title">
|
||||
<div class='name' v-for="(it, ii) in option.appColumnList" :key="ii" style="" @tap="jump(item)">
|
||||
<text v-if="option.showName" :style="{'font-weight': option.nameFontWeight?'bolder':'normal',
|
||||
'font-size':option.nameFontSize+'px',color:option.nameFontColor}">
|
||||
{{it.fullName}}:</text>
|
||||
<text :style="{'font-weight': option.dataFontWeight?'bolder':'normal','font-size':option.dataFontSize+'px',
|
||||
color:option.dataFontColor}">{{item[it.fieldName]}}</text>
|
||||
</div>
|
||||
<u-line v-if="i<option.defaultValue.length-1"></u-line>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
</template>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
export default {
|
||||
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
propsApi: ""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
jump(item) {
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.jnpf.jumpLink(item.urlAddress)
|
||||
},
|
||||
init() {
|
||||
this.initData()
|
||||
if (this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.config.option.defaultValue = res.data || []
|
||||
this.handleAttrs()
|
||||
})
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
handleAttrs() {
|
||||
this.option = this.config.option
|
||||
this.option.appColumnList.map((o) => {
|
||||
if (o.fullNameI18nCode) o.fullName = this.$t(o.fullNameI18nCode)
|
||||
})
|
||||
this.option.defaultValue = this.option.defaultValue.slice(0, this.option.appCount || 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.tabs-v {
|
||||
padding: 16rpx 10rpx 10rpx;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
width: calc(100% - 100rpx);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
vertical-align: top;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
padding: 8rpx 0px 10rpx 20px;
|
||||
}
|
||||
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
150
pages/portal/components/HText/index.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<view class="text-v">
|
||||
<view class="" v-if="option.styleType==1">
|
||||
<view v-if="option.textAutoplay" @click="jump"
|
||||
:style="{'font-weight':option.textFontWeight?700:400,'font-style':option.textFontStyle?'italic':'normal','text-decoration':option.textUnderLine,'color':option.textFontColor}">
|
||||
<u-notice-bar :volume-icon="false" :list="option.defaultValue" :bg-color="option.textBgColor || '#fff'"
|
||||
:color="option.textFontColor" :font-size="option.textFontSize*2" :speed="option.textAutoplaySpeed"
|
||||
:autoplay="option.textAutoplay">
|
||||
</u-notice-bar>
|
||||
</view>
|
||||
<view class="txtSty" v-if="!option.textAutoplay" @click="jump"
|
||||
:style="{'color':option.textFontColor,'font-size':option.textFontSize*2+'rpx','background-color':option.textBgColor,'font-weight':option.textFontWeight?700:400,'text-decoration':option.textUnderLine,'font-style':option.textFontStyle?'italic':'normal','text-align':option.textLeft}">
|
||||
<text>{{option.defaultValue}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-p-20 parse" v-if="option.styleType==2">
|
||||
<mp-html class="editor-box" :content="option.defaultValue" :key="key" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
jump() {
|
||||
let item = {
|
||||
urlAddress: this.option.appUrlAddress,
|
||||
value: this.option.defaultValue
|
||||
}
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.option.appUrlAddress = item.urlAddress
|
||||
|
||||
if (this.config.platform === 'mp') return
|
||||
let url;
|
||||
if (!this.option.appLinkType) return
|
||||
if (this.option.appLinkType == 1 && this.option.appType == 8) {
|
||||
let propertyJson = JSON.parse(this.option.appPropertyJson)
|
||||
uni.navigateTo({
|
||||
url: "/pages/portal/scanPortal/index?id=" + propertyJson.moduleId + "&protalType=1" +
|
||||
"&fullName=" + this.option.defaultValue || '',
|
||||
fail: (err) => {},
|
||||
});
|
||||
return
|
||||
}
|
||||
if (this.option.appLinkType == 1) {
|
||||
let data = {
|
||||
id: this.option.appModuleId,
|
||||
moduleId: this.option.appModuleId,
|
||||
urlAddress: this.option.appUrlAddress,
|
||||
...JSON.parse(this.option.appPropertyJson)
|
||||
}
|
||||
if (this.option.appType == 3) {
|
||||
url = '/pages/apply/dynamicModel/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(data))
|
||||
} else if (this.option.appType == 2) {
|
||||
url = this.option.appUrlAddress + '?menuId=' + this.option.appModuleId
|
||||
} else {
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(this.option.appUrlAddress)
|
||||
}
|
||||
} else {
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(this.option.appUrlAddress)
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
},
|
||||
initData() {
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.option.defaultValue = res.data
|
||||
if (this.option.styleType == 2 && typeof(res.data) != 'string') {
|
||||
this.option.defaultValue = JSON.stringify(res.data)
|
||||
}
|
||||
this.handleAttrs()
|
||||
})
|
||||
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
handleAttrs() {
|
||||
if (this.option.textAutoplay) this.option.defaultValue = [this.option
|
||||
.defaultValue
|
||||
]
|
||||
this.key = +new Date()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.text-v {
|
||||
|
||||
// padding: 20rpx 0;
|
||||
::v-deep .u-notice-box {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.parse {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.txtSty {
|
||||
width: 100wh;
|
||||
height: 100%;
|
||||
padding: 20rpx;
|
||||
word-wrap: break-word;
|
||||
color: blue;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
188
pages/portal/components/HTimeAxis/index.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<view class="timeLine-v">
|
||||
<view class="timeLine" :key="key">
|
||||
<u-time-line v-if="option.isVertical" :class="option.isLeft?'timeLine-right':''">
|
||||
<u-time-line-item v-for="(item,i) in option.defaultValue" :key="i">
|
||||
<template v-slot:node>
|
||||
<view class="timeLine-dot" v-if="i==0" :style="{'background':'rgba(62, 213, 56, 0.39)'}">
|
||||
</view>
|
||||
<view class="timeLine-dot" v-else-if="i==option.defaultValue.length-1"
|
||||
:style="{'background':'rgba(228, 231, 237, 0.39)'}">
|
||||
</view>
|
||||
<view class="timeLine-dot" v-else :style="{'background':'rgba(25, 144, 250, 0.39)'}">
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<view class="timeLine-content" :style="{'text-align':option.isLeft?'right':'left'}"
|
||||
@tap="jump(item)">
|
||||
<view class="u-font-24" v-if="option.isCrad">
|
||||
{{item.title}}
|
||||
</view>
|
||||
<view class="u-flex-col" :class="option.isCrad?'timeLine-title2':'timeLine-title'">
|
||||
<text class="name u-font-28">{{item.content}}</text>
|
||||
<text class="time u-font-28">{{item.timestamp}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-time-line-item>
|
||||
</u-time-line>
|
||||
<timeLine-row v-if="!option.isVertical" :list='option.defaultValue' :isCrad='option.isCrad'
|
||||
:isUpper="option.isUpper">
|
||||
</timeLine-row>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import timeLineRow from './timeLine-row.vue'
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
timeLineRow
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
option: {},
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
jump(item) {
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.jnpf.jumpLink(item.urlAddress)
|
||||
},
|
||||
init() {
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.config.option.defaultValue = res.data || []
|
||||
this.handleAttrs()
|
||||
})
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
handleAttrs() {
|
||||
if (this.config.option.sortable == 2) this.config.option.defaultValue = this.config.option.defaultValue
|
||||
.reverse();
|
||||
this.config.option.isCrad = this.config.option.styleType == 2 ? true : false
|
||||
this.config.option.isLeft = false
|
||||
this.config.option.isVertical = false
|
||||
this.config.option.isUpper = false
|
||||
if (this.config.option.layout == 1 || this.config.option.layout == 2 || this.config.option.layout ==
|
||||
3 || this.config.option.layout == 4) {
|
||||
this.config.option.isVertical = true
|
||||
if (this.config.option.layout == 3) {
|
||||
this.config.option.isLeft = true
|
||||
}
|
||||
}
|
||||
if (!this.config.option.isVertical) {
|
||||
if (this.config.option.layout == 5 || this.config.option.layout == 6 || this.config.option
|
||||
.layout == 7)
|
||||
this.config.option.isUpper = true
|
||||
}
|
||||
this.config.option.appShowNumber = this.config.option.appShowNumber || 50
|
||||
if (this.config.option.appShowNumber && Array.isArray(this.config.option.defaultValue)) {
|
||||
this.config.option.defaultValue = this.config.option.defaultValue.slice(0, this.config.option
|
||||
.appShowNumber)
|
||||
}
|
||||
this.option = this.config.option
|
||||
this.key = +new Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.timeLine-v {
|
||||
.timeLine {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20rpx;
|
||||
|
||||
.u-time-axis-item {
|
||||
.u-time-axis-node {
|
||||
top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.timeLine-right {
|
||||
padding-left: 0;
|
||||
padding-right: 40rpx !important;
|
||||
|
||||
&::before {
|
||||
left: 670rpx !important;
|
||||
}
|
||||
|
||||
.u-time-axis-item {
|
||||
.u-time-axis-node {
|
||||
left: 670rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeLine-dot {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border: 4rpx solid #FFFFFF;
|
||||
box-shadow: 0 6rpx 12rpx rgba(2, 7, 28, 0.16);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.timeLine-content {
|
||||
padding: 0 10rpx;
|
||||
|
||||
.timeLine-title {
|
||||
font-size: 30rpx;
|
||||
line-height: 36rpx;
|
||||
|
||||
.name {
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.timeLine-title2 {
|
||||
margin-top: 6rpx;
|
||||
background: rgba(255, 255, 255, 0.39);
|
||||
box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.timeLine-desc {
|
||||
margin-top: 10rpx;
|
||||
font-size: 26rpx;
|
||||
line-height: 36rpx;
|
||||
color: #909399;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
165
pages/portal/components/HTimeAxis/timeLine-row.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<view class="steps-v">
|
||||
<view class="steps-box">
|
||||
<view class="steps-line" :style="isUpper? lowerStyle:upperStyle" v-for="(item,index) in list" :key="index"
|
||||
@click="jump(item)">
|
||||
<view class="steps-item">
|
||||
<view class="steps-content" :style="{'width':isCrad?'270rpx':'250rpx'}">
|
||||
<view class="u-font-24 steps-content-hd" v-if="isCrad">
|
||||
<text>{{item.title}}</text>
|
||||
</view>
|
||||
<view class="u-font-24" :class="isCrad?'steps-title':'steps-title2'">
|
||||
<text class="name u-line-2">{{item.content}}</text>
|
||||
<text class="time">{{item.timestamp}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="steps-node" :style="isUpper?lowerDotStyle:upperDotStyle">
|
||||
<view class="steps-node-dot" v-if="index==0" :style="{'background':'rgba(62, 213, 56, 0.39)'}">
|
||||
</view>
|
||||
<view class="steps-node-dot" v-else-if="index==list.length-1"
|
||||
:style="{'background':'rgba(228, 231, 237, 0.39)'}"></view>
|
||||
<view class="steps-node-dot" v-else :style="{'background':'rgba(25, 144, 250, 0.39)'}"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
isCrad: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isUpper: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
upperStyle: {
|
||||
'padding-top': '40rpx',
|
||||
'border-top': '2rpx solid #DEDEDE'
|
||||
},
|
||||
upperDotStyle: {
|
||||
'top': '-54rpx'
|
||||
},
|
||||
lowerStyle: {
|
||||
'padding-bottom': '40rpx',
|
||||
'border-bottom': '2rpx solid #DEDEDE'
|
||||
},
|
||||
lowerDotStyle: {
|
||||
'bottom': '-52rpx'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
jump(item) {
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.jnpf.jumpLink(item.urlAddress)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.steps-v {
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.steps-box {
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
|
||||
.steps-line {
|
||||
.steps-item {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.steps-node {
|
||||
position: absolute;
|
||||
left: 12rpx;
|
||||
transform-origin: 0;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
font-size: 24rpx;
|
||||
background-color: rgb(255, 255, 255);
|
||||
z-index: 9;
|
||||
|
||||
.steps-node-dot {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border: 4rpx solid #FFFFFF;
|
||||
box-shadow: 0 6rpx 12rpx rgba(2, 7, 28, 0.16);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.steps-content {
|
||||
.steps-content-hd {
|
||||
width: 90%;
|
||||
height: 44rpx;
|
||||
color: #606266;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.steps-title2 {
|
||||
line-height: 36rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 90%;
|
||||
height: 120rpx;
|
||||
justify-content: space-between;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.steps-title {
|
||||
line-height: 36rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 90%;
|
||||
height: 170rpx;
|
||||
background: rgba(255, 255, 255, 0.39);
|
||||
box-shadow: 0px 6px 20px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 22rpx;
|
||||
justify-content: space-between;
|
||||
|
||||
.name {
|
||||
margin-bottom: 6rpx;
|
||||
letter-spacing: 2rpx;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.time {
|
||||
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
203
pages/portal/components/HTodo/index.vue
Normal file
@@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<view class="HTodo-v" :key="key" v-if="!loading">
|
||||
<view class="system-close" v-if="!hasAuth">您暂无该控件的访问权限</view>
|
||||
<view class="HTodo-box" v-else>
|
||||
<view class="HTodo-list u-flex" :style="{'flex-wrap':option.styleType==1?'nowrap':'wrap'}">
|
||||
<view class="u-flex-col HTodo-list-item" v-for="(item,index) in option.defaultValue" :key="index"
|
||||
@click="jump(item)" :style="option.style">
|
||||
<view class="u-m-b-8" style="position: relative">
|
||||
<view :class="item.icon" class="icon"
|
||||
:style="{'background-color':item.iconColor||item.iconBgColor || '#008cff'}"></view>
|
||||
<u-badge type="error" :offset="offset" :count="item.num" show-zero
|
||||
:bgColor="option.valueFontBgColor"
|
||||
:style="{'color':option.valueFontColor,'font-weight':option.valueFontWeight?700:400}">
|
||||
</u-badge>
|
||||
</view>
|
||||
<view class="u-line-1 title"
|
||||
:style="{'font-size':option.labelFontSize,'color':option.labelFontColor,'font-weight':option.labelFontWeight?700:400}">
|
||||
{{item.fullName}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getFlowTodoCount
|
||||
} from "@/api/workFlow/flowEngine";
|
||||
export default {
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
offset: ['-8', '-14'],
|
||||
option: {},
|
||||
propsApi: '',
|
||||
key: +new Date(),
|
||||
flowDone: [],
|
||||
toBeReviewed: [],
|
||||
flowCirculateType: [],
|
||||
hasAuth: true,
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getFlowTodoCount() {
|
||||
this.loading = true
|
||||
for (let i = 0; i < this.option.defaultValue.length; i++) {
|
||||
let defaultValue = this.option.defaultValue[i]
|
||||
if (defaultValue.category && defaultValue.category.length) this[defaultValue.id] = defaultValue
|
||||
.category
|
||||
}
|
||||
const query = {
|
||||
flowCirculateType: this.flowCirculateType,
|
||||
flowDoneType: this.flowDone,
|
||||
toBeReviewedType: this.toBeReviewed,
|
||||
}
|
||||
getFlowTodoCount(query).then(res => {
|
||||
let data = res.data || {}
|
||||
this.hasAuth = data.isToSign || data.isTodo || data.isDoing || data.isDone ||
|
||||
data.isCirculate;
|
||||
this.option.defaultValue.forEach(e => {
|
||||
if (e.id == 'flowToSign') {
|
||||
e.num = data.flowToSign || 0;
|
||||
if (!e.noShow) e.noShow = !data.isToSign;
|
||||
}
|
||||
if (e.id == 'flowTodo') {
|
||||
e.num = data.flowTodo || 0;
|
||||
if (!e.noShow) e.noShow = !data.isTodo;
|
||||
}
|
||||
if (e.id == 'flowDoing') {
|
||||
e.num = data.flowDoing || 0;
|
||||
if (!e.noShow) e.noShow = !data.isDoing;
|
||||
}
|
||||
if (e.id == 'flowDone') {
|
||||
e.num = data.flowDone || 0;
|
||||
if (!e.noShow) e.noShow = !data.isDone;
|
||||
}
|
||||
if (e.id == 'flowCirculate') {
|
||||
e.num = data.flowCirculate || 0;
|
||||
if (!e.noShow) e.noShow = !data.isCirculate;
|
||||
}
|
||||
})
|
||||
this.option.defaultValue = this.option.defaultValue.filter((o) => !o.noShow)
|
||||
this.key = +new Date()
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
init() {
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.option = JSON.parse(JSON.stringify(this.config.option))
|
||||
let style;
|
||||
style = {
|
||||
'width': '240rpx'
|
||||
}
|
||||
if (this.option.styleType == 2) {
|
||||
style = {
|
||||
'width': 100 / this.option.appRowNumber + '%'
|
||||
}
|
||||
if (this.option.appShowBorder) {
|
||||
style['border-right'] = '2rpx solid #f0f2f6'
|
||||
style['border-bottom'] = '2rpx solid #f0f2f6'
|
||||
}
|
||||
}
|
||||
this.option.style = style
|
||||
this.getFlowTodoCount()
|
||||
this.option.labelFontSize = this.option.labelFontSize * 2 + 'rpx'
|
||||
this.key = +new Date()
|
||||
},
|
||||
jump(item) {
|
||||
if (this.config.platform === 'mp') return
|
||||
const sysConfigInfo = uni.getStorageSync('sysConfigInfo')
|
||||
if (['flowToSign'].includes(item.id) && sysConfigInfo.flowSign == 0) return this.$u.toast(
|
||||
"系统未开启流程待签,无法跳转")
|
||||
if (['flowTodo'].includes(item.id) && sysConfigInfo.flowTodo == 0) return this.$u.toast(
|
||||
"系统未开启流程待办,无法跳转")
|
||||
let url = '/my/entrustAgent'
|
||||
let tabIndex = {
|
||||
'flowToSign': 0,
|
||||
'flowTodo': 1,
|
||||
'flowDoing': 2,
|
||||
'flowDone': 4,
|
||||
'flowCirculate': 5,
|
||||
}
|
||||
let data = {
|
||||
tabIndex: tabIndex[item.id]
|
||||
}
|
||||
if (['flowToSign', 'flowDoing', 'flowDone', 'flowCirculate', 'flowTodo'].includes(item.id)) url =
|
||||
'/workFlow/flowTodo'
|
||||
uni.navigateTo({
|
||||
url: `/pages${url}/index?data=${encodeURIComponent(JSON.stringify(data))}`
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
// this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.HTodo-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.system-close {
|
||||
color: #8b949e;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 150rpx;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.HTodo-box {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.HTodo-list {
|
||||
|
||||
|
||||
.HTodo-list-item {
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
font-size: 60rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
137
pages/portal/components/HTodoList/index.vue
Normal file
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<view v-if="!loading">
|
||||
<view class="system-close" v-if="!hasAuth">您暂无该控件的访问权限</view>
|
||||
<view class="portal-todoList-box-body" v-else>
|
||||
<template v-if="list.length">
|
||||
<a class="item com-hover" @click="goDetail(item)" v-for="(item, i) in list" :key="i">
|
||||
<span class="name">{{item.fullName}}</span>
|
||||
<span class="time">{{$u.timeFormat(item.creatorTime)}}</span>
|
||||
</a>
|
||||
</template>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
checkInfo
|
||||
} from '@/api/message.js'
|
||||
import {
|
||||
getFlowTodo
|
||||
} from '@/api/home'
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
hasAuth: true,
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
this.loading = true
|
||||
getFlowTodo(this.config.type || 0).then(res => {
|
||||
this.list = res.data?.list?.length ? res.data.list.slice(0, 7) : [];
|
||||
this.hasAuth = !!res.data?.isAuthorize;
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
goDetail(item) {
|
||||
if (this.config.platform === 'mp') return
|
||||
let config = {
|
||||
...item,
|
||||
operatorId: item.id,
|
||||
opType: this.config.type,
|
||||
}
|
||||
checkInfo(config.operatorId || config.taskId, config.opType).then(res => {
|
||||
config.opType = res.data.opType;
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workFlow/flowBefore/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(config))
|
||||
});
|
||||
}, 300)
|
||||
}).catch((err) => {})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.system-close {
|
||||
color: #8b949e;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 150rpx;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.portal-todoList-box-body {
|
||||
padding: 42rpx 10rpx 10rpx;
|
||||
max-height: 472rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
line-height: 40rpx;
|
||||
font-size: 0;
|
||||
margin-bottom: 24rpx;
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
width: calc(100% - 180rpx);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
width: 180rpx;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
118
pages/portal/components/HVideo/index.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<view class="video-v">
|
||||
<view class="uni-padding-wrap uni-common-mt">
|
||||
<view v-if="option.defaultValue && !Array.isArray(option.defaultValue)" class="video-box">
|
||||
<video id="myVideo" :src="option.defaultValue" object-fit="fill" :loop="option.playNumber"
|
||||
:autoplay="option.videoAutoplay" :muted="option.mutePlay" v-show="showVideo" :key="key" />
|
||||
</view>
|
||||
<view class="nodata" v-else>
|
||||
<u-image width="100px" height="100px" :src="nodata" class="img" />
|
||||
<text>暂无视频</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
import nodata from '@/pages/portal/static/image/portal-nodata.png'
|
||||
import jnpf from '@/utils/jnpf'
|
||||
|
||||
export default {
|
||||
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'video',
|
||||
src: '',
|
||||
danmuValue: '',
|
||||
showVideo: true,
|
||||
autoplay: true,
|
||||
option: {},
|
||||
key: +new Date(),
|
||||
nodata
|
||||
}
|
||||
},
|
||||
onReady: function(res) {
|
||||
// #ifndef MP-ALIPAY
|
||||
this.videoContext = uni.createVideoContext('myVideo')
|
||||
// #endif
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.initData()
|
||||
})
|
||||
// #ifdef APP-PLUS
|
||||
uni.$on('showVideo', (show) => {
|
||||
this.showVideo = show
|
||||
this.key = +new Date()
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.config.option.playNumber = this.config.option.playNumber == 1 ? false : true
|
||||
this.initData()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config.refresh.autoRefresh) {
|
||||
setInterval(this.initData, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.option = this.config.option
|
||||
if (this.config.dataType === "dynamic") {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.config.option.defaultValue = res.data
|
||||
this.option = this.config.option
|
||||
})
|
||||
} else {
|
||||
if (this.config.option.styleType == 1) {
|
||||
this.option.defaultValue = jnpf.getAuthImgUrl(this.config.option.defaultValue.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.video-v {
|
||||
padding: 20rpx;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
||||
.video-box {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.nodata {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
||||
.img {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
604
pages/portal/components/chartsJs.js
Normal file
@@ -0,0 +1,604 @@
|
||||
import jnpf from '@/utils/jnpf'
|
||||
import {
|
||||
geojson,
|
||||
getAtlas
|
||||
} from '@/api/portal/portal.js'
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
let timer;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
mapData: [],
|
||||
mapList: [],
|
||||
mapType: '',
|
||||
markPoints: [],
|
||||
pointLoading: false,
|
||||
opts: {
|
||||
update: true,
|
||||
fontSize: 10,
|
||||
padding: [40, 15, 30, 15],
|
||||
extra: {
|
||||
map: {
|
||||
mercator: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
regionStep: [],
|
||||
stepMapList: [],
|
||||
option: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
if (this.config.dataType === 'dynamic') {
|
||||
uni.$off('proRefresh')
|
||||
uni.$on('proRefresh', () => {
|
||||
this.handelChart()
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (timer) clearInterval(timer)
|
||||
this.handelChart()
|
||||
if (!this.config.allRefresh.autoRefresh && this.config?.refresh?.autoRefresh) {
|
||||
timer = setInterval(this.handelChart, this.config.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
},
|
||||
async handelChart() {
|
||||
if (this.config.dataType === 'dynamic') {
|
||||
if (!this.config.propsApi) return
|
||||
const query = {
|
||||
paramList: this.config.templateJson
|
||||
};
|
||||
getDataInterfaceRes(this.config.propsApi, query).then(res => {
|
||||
this.config.option.defaultValue = this.handleMappingConfig(res.data, this.config)
|
||||
this.handleAttrs()
|
||||
})
|
||||
} else {
|
||||
this.handleAttrs()
|
||||
}
|
||||
},
|
||||
// 处理字段映射
|
||||
handleMappingConfig(resultData, config) {
|
||||
let defaultValue = undefined
|
||||
if (['rankList', 'barChart', 'pieChart', 'tableList'].includes(this.config.jnpfKey)) {
|
||||
defaultValue = this.config.option.defaultValue || []
|
||||
}
|
||||
let mappingConfig = config.mappingConfig
|
||||
let result = []
|
||||
|
||||
resultData.length && resultData.forEach(data => {
|
||||
let temp = {}
|
||||
for (let item of mappingConfig) {
|
||||
if (item.field === '系列') {
|
||||
temp['type'] = item.value ? data[item.value] : data['type']
|
||||
}
|
||||
if (item.field === '维度') {
|
||||
temp['name'] = item.value ? data[item.value] : data['name']
|
||||
}
|
||||
if (item.field === '数值') {
|
||||
temp['value'] = item.value ? data[item.value] : data['value']
|
||||
}
|
||||
if (item.field === '最大值') {
|
||||
temp['max'] = item.value ? data[item.value] : data['max']
|
||||
}
|
||||
if (item.field === '时间戳') {
|
||||
temp['timestamp'] = item.value ? data[item.value] : data['timestamp']
|
||||
}
|
||||
if (item.field === '经度') {
|
||||
temp['long'] = item.value ? data[item.value] : data['long']
|
||||
}
|
||||
if (item.field === '纬度') {
|
||||
temp['lat'] = item.value ? data[item.value] : data['lat']
|
||||
}
|
||||
}
|
||||
result.push(temp)
|
||||
})
|
||||
return result
|
||||
},
|
||||
handleParam(e) {
|
||||
let jnpfKey = this.config.jnpfKey
|
||||
let item = {}
|
||||
let choose = e.opts.series && e.opts.series[0]
|
||||
let chooseIndex = e.currentIndex['index']
|
||||
let name = ''
|
||||
let type = ''
|
||||
let value = ''
|
||||
if (jnpfKey === "barChart") {
|
||||
name = e.opts.categories[chooseIndex]
|
||||
value = choose.data[chooseIndex]
|
||||
type = choose.name
|
||||
}
|
||||
if (jnpfKey === "pieChart") {
|
||||
name = choose.name
|
||||
value = choose.data
|
||||
let series = this.option.chartData.series && this.option.chartData.series[0]
|
||||
type = series.name
|
||||
}
|
||||
if (jnpfKey === "lineChart") {
|
||||
name = e.opts.categories[chooseIndex]
|
||||
value = choose.data[chooseIndex]
|
||||
type = choose.name
|
||||
}
|
||||
if (jnpfKey === "radarChart") {
|
||||
chooseIndex = e.currentIndex
|
||||
name = e.opts.categories[chooseIndex]
|
||||
value = choose.data[chooseIndex]
|
||||
type = choose.name
|
||||
}
|
||||
if (jnpfKey === "mapChart" && choose.properties.childrenNum == 0) {
|
||||
name = choose.properties.name
|
||||
item.long = choose.properties.center[0]
|
||||
item.lat = choose.properties.center[1]
|
||||
}
|
||||
if (chooseIndex < 0 && jnpfKey !== "mapChart") return
|
||||
if (jnpfKey === "mapChart" && choose.properties.childrenNum != 0) return
|
||||
item.name = name
|
||||
item.value = value
|
||||
item.type = type
|
||||
item.urlAddress = this.config.option.urlAddress
|
||||
this.jnpf.solveAddressParam(item, this.config)
|
||||
this.jnpf.jumpLink(item.urlAddress)
|
||||
},
|
||||
handleAttrs() {
|
||||
let chartTitle = {
|
||||
titleText: this.config.option.titleText, //主标题
|
||||
titleTextStyleColor: this.config.option.titleTextStyleColor, //主标题字体颜色
|
||||
titleTextStyleFontSize: this.config.option.titleTextStyleFontSize * 2 + 'rpx', //主标题字体大小[12-25px]
|
||||
titleTextStyleFontWeight: this.config.option.titleTextStyleFontWeight ? 700 : 0, //主标题是否加粗
|
||||
titleLeft: this.config.option.titleLeft === 'left' ? 'flex-start' : this.config.option
|
||||
.titleLeft === 'right' ? 'flex-end' : 'center', //主子标题位置[left,center,right]
|
||||
titleBgColor: this.config.option.titleBgColor, //主子标题背景色[rgba(),#303133]
|
||||
// 图表副标题设置
|
||||
titleSubtext: this.config.option.titleSubtext, //子标题
|
||||
titleSubtextStyleColor: this.config.option.titleSubtextStyleColor, //子标题字体颜色
|
||||
titleSubtextStyleFontSize: this.config.option.titleSubtextStyleFontSize * 2 +
|
||||
'rpx', //子标题字体大小[12-25px]
|
||||
titleSubtextStyleFontWeight: this.config.option.titleSubtextStyleFontWeight ? 700 : 0, //子标题是否加粗
|
||||
}
|
||||
let defVal = this.config.option.defaultValue
|
||||
let chartVal = JSON.parse(JSON.stringify(defVal)) || []
|
||||
let typeArr = Array.from(new Set(chartVal.map((item) => item.type)))
|
||||
let axisData = Array.from(new Set(chartVal.map((item) => item.name)))
|
||||
let seriesData = []
|
||||
let colorList = [];
|
||||
let chartsType = "";
|
||||
let Ymin = []; //y轴最小
|
||||
let Ymax = []; //y轴最大
|
||||
let type = "";
|
||||
let yAxis = {};
|
||||
let xAxis = {};
|
||||
if (!['mapChart', 'customEcharts'].includes(this.config.jnpfKey)) {
|
||||
typeArr.forEach((title, index) => {
|
||||
const type = this.getType(title, this.config)
|
||||
let obj = {
|
||||
name: title,
|
||||
type: type
|
||||
}
|
||||
if (this.config.option.seriesLabelShow) {
|
||||
obj.textSize = (this.config.option.seriesLabelFontSize / 2) < 12 ? 12 : this.config
|
||||
.option
|
||||
.seriesLabelFontSize / 2
|
||||
obj.textColor = this.config.option.seriesLabelColor
|
||||
}
|
||||
let chartArr = chartVal.filter((item) => title === item.type)
|
||||
if (this.config.jnpfKey === 'barChart' || this.config.jnpfKey === 'lineChart' || this
|
||||
.config
|
||||
.jnpfKey ==
|
||||
'radarChart') {
|
||||
obj['data'] = chartArr.map((item) => item.value)
|
||||
} else {
|
||||
obj['data'] = chartArr.map((item) => {
|
||||
return {
|
||||
value: item.value,
|
||||
name: item.name,
|
||||
}
|
||||
})
|
||||
if (this.config.option.showZero) obj['data'] = obj['data'].filter((item) => item
|
||||
.value != 0)
|
||||
this.key = +new Date
|
||||
}
|
||||
Ymin.push(Math.min(...obj['data']))
|
||||
Ymax.push(Math.max(...obj['data']))
|
||||
seriesData.push(obj);
|
||||
})
|
||||
xAxis = {
|
||||
disabled: !this.config.option.xAxisShow, //不绘制X轴
|
||||
axisLine: this.config.option.xAxisShow, //绘制坐标轴轴线
|
||||
axisLineColor: !this.config.option.xAxisShow ? '#fff' : this.config.option
|
||||
.xAxisAxisLineLineStyleColor, //坐标轴轴线颜色,默认#CCCCCC
|
||||
title: "", //X轴标题
|
||||
titleFontSize: this.config.option.xAxisNameTextStyleFontSize, //标题字体大小
|
||||
titleFontColor: this.config.option.xAxisNameTextStyleColor, //X轴名称字体颜色
|
||||
titleOffsetY: -20, //标题纵向偏移距离,负数为向上偏移,正数向下偏移
|
||||
titleOffsetX: -300, //标题横向偏移距离,负数为向左偏移,正数向右偏移
|
||||
fontSize: (this.config.option.xAxisAxisLabelTextStyleFontSize / 2) < 14 ? 14 : this.config
|
||||
.option
|
||||
.xAxisAxisLabelTextStyleFontSize / 2, //X轴标签字体大小
|
||||
fontColor: this.config.option.xAxisAxisLabelTextStyleColor, //X轴标签字体颜色
|
||||
rotateAngle: this.config.option.xAxisAxisLabelRotate, ////X轴标签角度
|
||||
rotateLabel: this.config.option.xAxisAxisLabelRotate > 0 ? true : false, //【旋转】数据点(刻度点)文字
|
||||
gridColor: this.config.option.xAxisSplitLineLineStyleColor, //纵向网格颜色,默认#CCCCCC
|
||||
splitNumber: 4, //X轴网格数量,纵向网格数量(竖着的)
|
||||
disableGrid: !this.config.option.xAxisShow ? !this.config.option.xAxisShow : !this.config
|
||||
.option.xAxisSplitLineShow, //不绘制纵向网格(即默认绘制网格)
|
||||
scrollShow: axisData.length > 5 ? true : false, //是否显示滚动条,配合拖拽滚动使用(即仅在启用 enableScroll 时有效
|
||||
scrollAlign: "left", //滚动条初始位置
|
||||
scrollColor: "#A6A6A6", //滚动条颜色,默认#A6A6A6
|
||||
scrollBackgroundColor: "#EFEBEF", //滚动条底部背景颜色,默认#EFEBEF
|
||||
itemCount: axisData.length > 5 ? 6 : 5, //单屏数据密度即图表可视区域内显示的X轴数据点数量,仅在启用enableScroll时有效
|
||||
};
|
||||
yAxis = {
|
||||
data: [{
|
||||
position: "left",
|
||||
title: "",
|
||||
min: this.config.option.styleType == 6 ? -jnpf.toRound(Math.abs(Math.min(...
|
||||
Ymin)
|
||||
.toString().length > 2 ? Math.min(...Ymin) - 200 : Math
|
||||
.min(
|
||||
...Ymin) - 50)) : 0,
|
||||
max: jnpf.toRound(Math.max(...Ymax)),
|
||||
axisLine: true, //坐标轴轴线是否显示(数据还能显示)
|
||||
axisLineColor: this.config.option
|
||||
.yAxisAxisLineLineStyleColor, //坐标轴轴线颜色,默认#CCCCCC
|
||||
disabled: !this.config.option.yAxisShow, //不绘制Y轴(刻度和轴线都不绘制)
|
||||
fontColor: this.config.option
|
||||
.yAxisAxisLabelTextStyleColor, //数据点(刻度点)字体颜色,默认#666666
|
||||
fontSize: (this.config.option.yAxisAxisLabelTextStyleFontSize / 2) < 12 ? 12 : this
|
||||
.config
|
||||
.option.yAxisAxisLabelTextStyleFontSize / 2, //数据点(刻度点)字体颜色,默认#666666
|
||||
}],
|
||||
padding: 10, //多个Y轴间的间距
|
||||
gridSet: "number", //横向向网格数量类型设置,可选值,'auto','array'
|
||||
disableGrid: !this.config.option.yAxisSplitLineShow, //不绘制横向向网格(即默认绘制网格)
|
||||
splitNumber: 4, //【指定数量】的横向向网格数量,此数量与Y轴数据点是否为小数有关,如果指定了max,请指定为能被max-min整除的数值
|
||||
gridType: "solid", //横向向网格线型
|
||||
gridColor: this.config.option.yAxisSplitLineLineStyleColor, //横向网格颜色,默认#CCCCCC
|
||||
};
|
||||
this.config.option.colorList.forEach((o, i) => {
|
||||
if (o.color1) colorList.push(o.color1)
|
||||
})
|
||||
}
|
||||
let opts = {
|
||||
color: colorList, //主题颜色,16进制颜色格式,Array格式
|
||||
padding: [15, 15, 0, 15], //画布填充边距[上,右,下,左],Array格式
|
||||
enableScroll: axisData.length > 5 ? true :
|
||||
false, //开启图表可拖拽滚动,开启后ontouch需要赋值为true,X轴配置里需要配置itemCount单屏幕数据点数量
|
||||
dataLabel: this.config.option.seriesLabelShow, //是否显示图表区域内数据点上方的数据文案
|
||||
legend: {
|
||||
fontColor: this.config.jnpfKey === 'pieChart' ? "#666666" : "",
|
||||
show: this.config.option.legendShow, //是否显示图例标识
|
||||
position: 'top',
|
||||
float: 'right',
|
||||
fontSize: (this.config.option.legendTextStyleFontSize / 2) < 14 ? 14 : this.config.option
|
||||
.legendTextStyleFontSize / 2
|
||||
},
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: this.config.option.tooltipShow, //提示语显示
|
||||
fontSize: (this.config.option.tooltipTextStyleFontSize / 2) < 14 ? 14 : this.config
|
||||
.option
|
||||
.tooltipTextStyleFontSize / 2, //提示语字体大小
|
||||
fontColor: this.config.option.tooltipTextStyleColor, //提示语字体颜色
|
||||
bgColor: this.config.option.tooltipBgColor || '#000000' //提示窗口的背景颜色
|
||||
},
|
||||
mix: {
|
||||
column: {}
|
||||
},
|
||||
column: {
|
||||
type: 'group',
|
||||
width: this.config.option.seriesBarWidth, //柱体宽度
|
||||
activeBgColor: "#000000",
|
||||
activeBgOpacity: 0.08,
|
||||
linearType: "none",
|
||||
barBorderRadius: [this.config.option.seriesItemStyleBarBorderRadius, this.config.option
|
||||
.seriesItemStyleBarBorderRadius, this.config.option
|
||||
.seriesItemStyleBarBorderRadius,
|
||||
this.config.option.seriesItemStyleBarBorderRadius
|
||||
], //自定义4个圆角半径[左上,右上,右下,左下]
|
||||
seriesGap: 5, //多series每个柱子之间的间距
|
||||
customColor: colorList, //扩展渐变色
|
||||
barBorderCircle: false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.config.jnpfKey === 'barChart') {
|
||||
if (this.config.option.styleType == 5 || this.config.option.styleType == 1 ||
|
||||
this.config.option.styleType == 4 || this.config.option.styleType == 6) {
|
||||
type = 'group'
|
||||
if (this.config.option.styleType == 6) {
|
||||
opts.extra.column.barBorderRadius = []
|
||||
|
||||
// opts.extra.column.width = 50
|
||||
// yAxis.splitNumber = (yAxis.data[0].max / 500) + (Math.abs(yAxis.data[0].min) / 500)
|
||||
}
|
||||
} else {
|
||||
type = 'stack'
|
||||
opts.extra.mix.column = {
|
||||
width: this.config.option.seriesBarWidth, //柱体宽度
|
||||
barBorderCircle: false, //启用分组柱状图半圆边框
|
||||
barBorderRadius: [this.config.option.seriesItemStyleBarBorderRadius, this.config.option
|
||||
.seriesItemStyleBarBorderRadius, this.config.option
|
||||
.seriesItemStyleBarBorderRadius,
|
||||
this.config.option.seriesItemStyleBarBorderRadius
|
||||
], //自定义4个圆角半径[左上,右上,右下,左下]
|
||||
}
|
||||
}
|
||||
chartsType = this.config.option.styleType == 7 ? 'mix' : 'column'
|
||||
opts.xAxis = {
|
||||
...xAxis
|
||||
}
|
||||
opts.yAxis = {
|
||||
...yAxis
|
||||
}
|
||||
opts.extra.column.type = type
|
||||
} else if (this.config.jnpfKey === "pieChart") {
|
||||
chartsType = 'pie'
|
||||
opts.fontColor = this.config.option.seriesLabelColor
|
||||
opts.fontSize = (this.config.option.seriesLabelFontSize / 2) < 14 ? 14 : this.config.option
|
||||
.seriesLabelFontSize / 2
|
||||
let pieChartObj = {
|
||||
borderColor: "#FFFFFF",
|
||||
borderWidth: 3,
|
||||
activeOpacity: 0.5,
|
||||
offsetAngle: -90,
|
||||
labelWidth: 15,
|
||||
border: false,
|
||||
}
|
||||
let pieChartObj2 = {
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
name: "",
|
||||
}
|
||||
if (this.config.option.styleType == 1) {
|
||||
if (this.config.option.roseType) chartsType = 'rose'
|
||||
opts.extra[chartsType] = {
|
||||
...pieChartObj
|
||||
}
|
||||
} else {
|
||||
chartsType = 'ring';
|
||||
opts.title = {
|
||||
fontSize: 15,
|
||||
color: "#666666",
|
||||
...pieChartObj2
|
||||
};
|
||||
opts.subtitle = {
|
||||
fontSize: 25,
|
||||
color: "#7cb5ec",
|
||||
...pieChartObj2
|
||||
}
|
||||
opts.extra[chartsType] = {
|
||||
ringWidth: 60,
|
||||
activeRadius: 10,
|
||||
...pieChartObj
|
||||
}
|
||||
}
|
||||
} else if (this.config.jnpfKey === "lineChart") {
|
||||
chartsType = this.config.option.areaStyle ? 'area' : 'line'
|
||||
type = this.config.option.styleType == 2 ? 'curve' : this.config.option.styleType == 3 ? 'step' :
|
||||
'straight'
|
||||
let lineChartObj = {
|
||||
type: type,
|
||||
width: this.config.option.seriesLineStyleWidth
|
||||
}
|
||||
opts.extra[chartsType] = {
|
||||
...lineChartObj
|
||||
}
|
||||
opts.xAxis = {
|
||||
...xAxis
|
||||
}
|
||||
opts.yAxis = {
|
||||
...yAxis
|
||||
}
|
||||
} else if (this.config.jnpfKey === "radarChart") {
|
||||
chartsType = "radar";
|
||||
type = this.config.option.styleType == 1 ? chartsType : 'circle'
|
||||
opts.fontSize = (this.config.option.radarAxisNameFontSize / 2) < 14 ? 14 : this.config.option
|
||||
.radarAxisNameFontSize / 2
|
||||
opts.fontColor = this.config.option.seriesLabelColor
|
||||
opts.extra[chartsType] = {
|
||||
gridType: type,
|
||||
gridColor: "#CCCCCC",
|
||||
gridCount: 5,
|
||||
opacity: 0.2,
|
||||
max: 200,
|
||||
labelShow: true,
|
||||
border: true,
|
||||
max: 100,
|
||||
labelColor: this.config.option.radarAxisNameColor
|
||||
}
|
||||
} else {
|
||||
this.getAtlas()
|
||||
chartsType = "map";
|
||||
this.config.option.markPoints = []
|
||||
opts = {
|
||||
update: true,
|
||||
fontSize: this.config.option.geoLabelFontSize,
|
||||
padding: [15, 15, 30, 15],
|
||||
dataLabel: this.config.option.geoLabelShow,
|
||||
fontColor: this.config.option.geoLabelColor,
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: this.config.option.tooltipShow,
|
||||
fontColor: this.config.option.tooltipTextStyleColor || '#000',
|
||||
//fontSize: this.config.option.tooltipTextStyleFontSize,
|
||||
bgColor: this.config.option.tooltipBgColor || '#fff',
|
||||
bgOpacity: 1
|
||||
},
|
||||
map: {
|
||||
mercator: false,
|
||||
border: true,
|
||||
borderWidth: this.config.option.geoBorderWidth / 2,
|
||||
borderColor: this.config.option.geoBorderColor,
|
||||
activeBorderColor: "#F04864",
|
||||
activeFillColor: "#FACC14",
|
||||
activeFillOpacity: 1,
|
||||
active: true,
|
||||
activeTextColor: "#FFFFFF",
|
||||
fillOpacity: 1
|
||||
},
|
||||
},
|
||||
}
|
||||
this.config.option.defaultValue.forEach(o => {
|
||||
this.config.option.markPoints.push({
|
||||
latitude: o.lat,
|
||||
longitude: o.long,
|
||||
name: o.name,
|
||||
value: o.value
|
||||
})
|
||||
})
|
||||
}
|
||||
let chartData = {
|
||||
categories: axisData,
|
||||
series: seriesData,
|
||||
opts,
|
||||
type: chartsType
|
||||
}
|
||||
if (chartsType != 'map') {
|
||||
if (chartTitle.titleText && chartTitle.titleSubtext) {
|
||||
chartData.opts.legend.padding = 50
|
||||
} else if (chartTitle.titleText && !chartTitle.titleSubtext) {
|
||||
chartData.opts.legend.padding = 30
|
||||
} else {
|
||||
chartData.opts.legend.padding = 5
|
||||
}
|
||||
}
|
||||
this.config.option.chartData = chartData
|
||||
this.config.option.chartTitle = chartTitle
|
||||
this.option = this.config.option
|
||||
this.$nextTick(() => {
|
||||
this.show = true
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
/* 获取地图树 */
|
||||
getAtlas() {
|
||||
getAtlas().then(res => {
|
||||
this.mapList = jnpf.treeToArray(res.data);
|
||||
this.regionStep = []
|
||||
this.drawChina()
|
||||
})
|
||||
},
|
||||
/* 获取地图数据 */
|
||||
drawChina(type) {
|
||||
if (Array.isArray(this.option.mapType) && !type) this.mapType = this.option.mapType[this.option.mapType
|
||||
.length - 1]
|
||||
geojson(this.mapType).then(res => {
|
||||
let series = JSON.parse(JSON.stringify(res.data.features)) || [];
|
||||
for (var i = 0; i < series.length; i++) {
|
||||
if (series[i].geometry.type === 'Polygon' && !type) {
|
||||
if (this.mapType == 150000) {
|
||||
series[i].geometry.coordinates = series[i].geometry.coordinates
|
||||
} else {
|
||||
series[i].geometry.coordinates = [series[i].geometry.coordinates]
|
||||
}
|
||||
}
|
||||
series[i].value = Math.floor(Math.random() * 1000)
|
||||
series[i].color = this.option.geoAreaColor
|
||||
}
|
||||
this.mapData = series
|
||||
this.stepMapList.push(this.mapData)
|
||||
this.option.chartData.series = series
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
/* 地图点击路径 */
|
||||
regionStepClick(e, index) {
|
||||
if (index == 0) {
|
||||
this.stepMapList = []
|
||||
this.regionStep = []
|
||||
for (let i = 0; i < this.mapList.length; i++) {
|
||||
if (this.mapList[i].enCode == this.option.mapType[this.option.mapType.length - 1]) {
|
||||
this.regionStep.push({
|
||||
name: this.mapList[i].fullName,
|
||||
adcode: this.mapList[i].enCode
|
||||
})
|
||||
}
|
||||
}
|
||||
this.drawChina()
|
||||
return
|
||||
}
|
||||
this.mapType = e.adcode
|
||||
this.stepMapList.splice(index + 1, this.regionStep.length - index - 1)
|
||||
this.regionStep.splice(index + 1, this.regionStep.length - index - 1)
|
||||
this.drawChina(1)
|
||||
},
|
||||
/* 地图点击 */
|
||||
getIndex(e) {
|
||||
// 处理跳转参数
|
||||
this.handleParam(e)
|
||||
let current = this.mapList.filter(o => o.enCode == this.option.mapType[this.option.mapType.length - 1])
|
||||
if (!this.config.option.drillDown) return
|
||||
let mapData = this.mapData[e.currentIndex] ? this.mapData[e.currentIndex] : []
|
||||
this.mapType = mapData.properties.adcode
|
||||
let acroutes = mapData.properties.acroutes
|
||||
let selectName = mapData.properties.name
|
||||
let adcode = mapData.properties.adcode
|
||||
this.regionStep.unshift({
|
||||
name: current[0].fullName,
|
||||
adcode: current[0].enCode
|
||||
})
|
||||
this.regionStep.push({
|
||||
name: selectName,
|
||||
adcode: adcode
|
||||
})
|
||||
//对象数组去重
|
||||
this.regionStep = this.regionStep.filter((a, b, c) => {
|
||||
return c.findIndex(x => x.name === a.name) === b
|
||||
})
|
||||
this.pointLoading = false
|
||||
this.drawChina(1)
|
||||
},
|
||||
getType(title) {
|
||||
if (this.config.jnpfKey == 'barChart') {
|
||||
if (this.config.option.styleType == 7) {
|
||||
const arr = this.config.option.barType.find(ele => title == ele.title)
|
||||
if (arr && arr.type) {
|
||||
if (arr.type == 'bar') return 'column'
|
||||
return arr.type
|
||||
}
|
||||
}
|
||||
return 'column'
|
||||
} else if (this.config.jnpfKey == 'lineChart') {
|
||||
return 'line'
|
||||
} else if (this.config.jnpfKey == 'pieChart') {
|
||||
return 'pie'
|
||||
} else {
|
||||
return 'radar'
|
||||
}
|
||||
},
|
||||
/* 设置地图点 */
|
||||
setPoints(e) {
|
||||
const mapData = e.opts.chartData.mapData;
|
||||
this.option.markPoints = this.option.markPoints.slice(0, this.option.appShowNumber)
|
||||
for (var i = 0; i < this.option.markPoints.length; i++) {
|
||||
const points = this.coordinateToPoint(this.option.markPoints[i].longitude, this.option.markPoints[i]
|
||||
.latitude, mapData
|
||||
.bounds,
|
||||
mapData.scale, mapData.xoffset, mapData.yoffset, mapData.mercator)
|
||||
this.option.markPoints[i].x = points.x;
|
||||
this.option.markPoints[i].y = points.y;
|
||||
}
|
||||
this.pointLoading = true
|
||||
this.$refs.charts.key = +new Date();
|
||||
},
|
||||
/* 经纬度转画布坐标 */
|
||||
coordinateToPoint(longitude, latitude, bounds, scale, xoffset, yoffset, mercator) {
|
||||
var x = longitude;
|
||||
var y = latitude;
|
||||
if (mercator == true) {
|
||||
x = longitude * 20037508.34 / 130;
|
||||
y = Math.log(Math.tan((90 + latitude) * Math.PI / 360)) / (Math.PI / 180);
|
||||
y = y * 20037508.34 / 180;
|
||||
}
|
||||
return {
|
||||
x: (x - bounds.xMin) * scale + xoffset,
|
||||
y: (bounds.yMax - y) * scale + yoffset
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
506
pages/portal/components/defaultPortal.vue
Normal file
@@ -0,0 +1,506 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="cardData">
|
||||
<template #content>
|
||||
<view class="sale-module">
|
||||
<view class="sale-module-box u-flex">
|
||||
<view class="head-tabs u-flex"
|
||||
:style="{'justify-content':list.length>3?'flex-start':'space-between'}">
|
||||
<view class="head-tabs-item" v-for="(item,index) in list" :key="index">
|
||||
<view class="u-flex-col">
|
||||
<text class="u-font-24">{{item.text1}}</text>
|
||||
<text class="u-font-28" style="color: #1890FF;">{{item.text2}}</text>
|
||||
<text class="u-font-20" style="color: #008B4F;">{{item.text3}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
<view class="u-m-b-20">
|
||||
<HCard>
|
||||
<template #content>
|
||||
<view class="sale-module">
|
||||
<view class="sale-module-box u-flex">
|
||||
<view class="head-tabs u-flex"
|
||||
:style="{'justify-content':list2.length>3?'flex-start':'space-between'}">
|
||||
<view class="head-tabs-item" v-for="(item,index) in list2" :key="index">
|
||||
<view class="u-flex-col head-tabs-inner">
|
||||
<view class="img" :class="item.icon" :style="{'background':item.bgColor}">
|
||||
</view>
|
||||
<text class="u-font-24 u-m-b-10 u-m-t-10">{{item.text1}}</text>
|
||||
<text class="u-font-28" style="font-weight: 700;">{{item.text3}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData='cardData2'>
|
||||
<template #content>
|
||||
<view class="charts-box">
|
||||
<qiun-data-charts type="tarea" :opts="opts" :chartData="chartData" :ontouch="true" />
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData='cardData3'>
|
||||
<template #content>
|
||||
<view class="notice-v">
|
||||
<view class="notice-box">
|
||||
<view class="notice-inner u-flex" v-for="(item,index) in noticeList" :key="index">
|
||||
<view class="l"
|
||||
:style="{'color':item.type==1?'#093FF4':'#05ED05','background-color':item.type==1?'#e5ebfe':'#e6ffe5'}">
|
||||
{{item.title}}
|
||||
</view>
|
||||
<view class="c u-line-1 u-font-28">{{item.content}}</view>
|
||||
<span class="r u-font-24">{{item.time}}</span>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData='cardData4'>
|
||||
<template #content>
|
||||
<view class="proList-v">
|
||||
<view class="proList-box">
|
||||
<view class="proList-inner" v-for="(item,index) in proListList" :key="index">
|
||||
<view class="u-flex u-m-b-20 t">
|
||||
<u-image width="40rpx" height="40rpx" :src="item.imgUrl" class="img"></u-image>
|
||||
<text class="u-font-28 u-m-l-10 title">{{item.title}}</text>
|
||||
<text class="u-font-24 time">5{{item.time}}</text>
|
||||
</view>
|
||||
<view class="c u-line-3">
|
||||
{{item.content}}
|
||||
</view>
|
||||
<view class="b">
|
||||
<span>项目组名:{{item.name}}</span>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import HCard from './HCard'
|
||||
import img1 from '@/pages/portal/static/image/1.png'
|
||||
import img2 from '@/pages/portal/static/image/2.png'
|
||||
import img3 from '@/pages/portal/static/image/3.png'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
opts: {
|
||||
color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
|
||||
"#ea7ccc"
|
||||
],
|
||||
padding: [15, 15, 0, 15],
|
||||
enableScroll: true,
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
scrollShow: true,
|
||||
itemCount: 4
|
||||
},
|
||||
yAxis: {
|
||||
gridType: "dash",
|
||||
dashLength: 2,
|
||||
data: [{
|
||||
min: null,
|
||||
max: 10000,
|
||||
}]
|
||||
},
|
||||
extra: {
|
||||
area: {
|
||||
type: "curve",
|
||||
opacity: 0.2,
|
||||
addLine: true,
|
||||
width: 2,
|
||||
gradient: true,
|
||||
activeType: "hollow"
|
||||
}
|
||||
}
|
||||
},
|
||||
chartData: {},
|
||||
proListList: [{
|
||||
imgUrl: img1,
|
||||
title: "销售管理信息项目",
|
||||
time: '5 小时前',
|
||||
name: '超越超越卓尔不凡',
|
||||
content: '销售管理信息项目是为全面提升企业市场占有率和竞争力,越来越多企业已经意识到上销售管理软件销售管理信息项目是为全面提升企业市场占有率和竞争力,越来越多企业已经意识到上销售管理软件销售管理信息项目是为全面提升企业市场占有率和竞争力,越来越多企业已经意识到上销售管理软件'
|
||||
},
|
||||
{
|
||||
imgUrl: img1,
|
||||
title: "知识库管理搭建",
|
||||
time: '5 小时前',
|
||||
name: '快乐每一天',
|
||||
content: '知识库管理搭建是一个企业内部信息的汇总,建立知识库,对这些知识进行统一管理能够有效帮助企业提高'
|
||||
},
|
||||
{
|
||||
imgUrl: img2,
|
||||
title: "报表样式调整",
|
||||
time: '5 小时前',
|
||||
name: '超越超越卓尔不凡',
|
||||
content: '报表引用UReport2是一款基于架构在Spring之上纯Java的高性能报表引擎,通过迭代单元格可以实现任意'
|
||||
},
|
||||
{
|
||||
imgUrl: img3,
|
||||
title: "企业门户平台",
|
||||
time: '5 小时前',
|
||||
name: '智慧成功人士',
|
||||
content: '企业统一门户为企业提供一个统一入口访问企业各种资源信息,企业的员工、客户、合作伙伴和供应商等都可'
|
||||
}
|
||||
],
|
||||
list: [{
|
||||
text1: "今日交易总额",
|
||||
text2: "¥ 124,546,233",
|
||||
text3: "+2.34%"
|
||||
},
|
||||
{
|
||||
text1: "销售目标完成率",
|
||||
text2: "92 %",
|
||||
text3: "-0.3%"
|
||||
},
|
||||
{
|
||||
text1: "活动剩余时间",
|
||||
text2: "23:26:59",
|
||||
text3: "活动时间48小时"
|
||||
},
|
||||
{
|
||||
text1: "每秒交易总额",
|
||||
text2: "¥ 2,663",
|
||||
text3: "+9.34%"
|
||||
},
|
||||
{
|
||||
text1: "在售商品总数",
|
||||
text2: "569 件",
|
||||
text3: ""
|
||||
}
|
||||
],
|
||||
noticeList: [{
|
||||
title: '通知',
|
||||
content: '中秋国庆双节放假通知',
|
||||
time: '2020-09-19',
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
title: '公告',
|
||||
content: '你好朋友,感谢使用 JNPF快速开发平台新版本',
|
||||
time: '2020-09-18',
|
||||
type: 2
|
||||
},
|
||||
{
|
||||
title: '通知',
|
||||
content: '月饼发放通知,请各部门主管到行政部领取',
|
||||
time: '2020-09-17',
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
title: '公告',
|
||||
content: '本季度销售之星名单公示',
|
||||
time: '2020-09-16',
|
||||
type: 2
|
||||
},
|
||||
{
|
||||
title: '通知',
|
||||
content: '公司上班时间调整通知,下月执行',
|
||||
time: '2020-09-15',
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
title: '公告',
|
||||
content: '公司新上任总裁任命书',
|
||||
time: '2020-09-14',
|
||||
type: 2
|
||||
},
|
||||
{
|
||||
title: '公告',
|
||||
content: '午餐补贴通知,本月生效',
|
||||
time: '2020-09-13',
|
||||
type: 2
|
||||
},
|
||||
{
|
||||
title: '通知',
|
||||
content: '公司技术交流培训课通知',
|
||||
time: '2020-09-12',
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
title: '通知',
|
||||
content: '关于公司组织员工秋季旅游通知',
|
||||
time: '2020-09-11',
|
||||
type: 1
|
||||
}
|
||||
],
|
||||
list2: [{
|
||||
bgColor: '#f2ebfb',
|
||||
icon: 'icon-ym icon-ym-wf-payDistribution',
|
||||
text1: "总销售额",
|
||||
text3: "102,400"
|
||||
},
|
||||
{
|
||||
bgColor: '#edf8fe',
|
||||
icon: 'icon-ym icon-ym-generator-Panel',
|
||||
text1: "访问量",
|
||||
text3: "81,212"
|
||||
},
|
||||
{
|
||||
bgColor: '#fef3ef',
|
||||
icon: 'icon-ym icon-ym-extend-folder',
|
||||
text1: "支付笔数",
|
||||
text3: "9,280"
|
||||
},
|
||||
{
|
||||
bgColor: '#ffeff2',
|
||||
icon: 'icon-ym icon-ym-Refresh',
|
||||
text1: "线上购物转化率",
|
||||
text3: "13,600"
|
||||
},
|
||||
],
|
||||
cardData: {
|
||||
'title': "销售指数",
|
||||
'viceTitle': '活动实时交易情况',
|
||||
'card': {
|
||||
'titleBgColor': "#fff",
|
||||
'cardIcon': "icon-ym icon-ym-generator-bar",
|
||||
'titleFontColor': '#6a6a6a',
|
||||
'viceTitleFontColor': '#606266',
|
||||
'titleFontSize': 14,
|
||||
'viceTitleFontSize': 12,
|
||||
'titleFontWeight': false,
|
||||
'cardRightBtn': '',
|
||||
'titleLeft': 'left'
|
||||
}
|
||||
},
|
||||
cardData2: {
|
||||
'title': "实时数据",
|
||||
'viceTitle': '',
|
||||
'card': {
|
||||
'titleBgColor': "#fff",
|
||||
'cardIcon': "icon-ym icon-ym-liveData",
|
||||
'titleFontColor': '#6a6a6a',
|
||||
'viceTitleFontColor': '#606266',
|
||||
'titleFontSize': 14,
|
||||
'viceTitleFontSize': 12,
|
||||
'titleFontWeight': false,
|
||||
'cardRightBtn': '',
|
||||
'titleLeft': 'left'
|
||||
}
|
||||
},
|
||||
cardData3: {
|
||||
'title': "公告通知",
|
||||
'viceTitle': '',
|
||||
'card': {
|
||||
'titleBgColor': "#fff",
|
||||
'cardIcon': "icon-ym icon-ym-xitong",
|
||||
'titleFontColor': '#6a6a6a',
|
||||
'viceTitleFontColor': '#606266',
|
||||
'titleFontSize': 14,
|
||||
'viceTitleFontSize': 12,
|
||||
'titleFontWeight': false,
|
||||
'cardRightBtn': '查看更多>',
|
||||
'titleLeft': 'left'
|
||||
}
|
||||
},
|
||||
cardData4: {
|
||||
'title': "进行中的项目",
|
||||
'viceTitle': '',
|
||||
'card': {
|
||||
'titleBgColor': "#fff",
|
||||
'cardIcon': "icon-ym icon-ym-tree-department",
|
||||
'titleFontColor': '#6a6a6a',
|
||||
'viceTitleFontColor': '#606266',
|
||||
'titleFontSize': 14,
|
||||
'viceTitleFontSize': 12,
|
||||
'titleFontWeight': false,
|
||||
'cardRightBtn': '查看更多>',
|
||||
'titleLeft': 'left'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getServerData();
|
||||
},
|
||||
methods: {
|
||||
getServerData() {
|
||||
//模拟从服务器获取数据时的延时
|
||||
setTimeout(() => {
|
||||
//模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
|
||||
let res = {
|
||||
categories: ["2AM", "4AM", "6AM", "8AM", "10AM", "12AM", "2AM", "4AM", "6AM", "8AM",
|
||||
"10AM", "12AM"
|
||||
],
|
||||
series: [{
|
||||
name: "成交量A",
|
||||
data: [0, 2820, 8932, 5700, 7901, 4934, 5000, 3000, 4090, 2330, 3820, 0]
|
||||
}]
|
||||
};
|
||||
this.chartData = JSON.parse(JSON.stringify(res));
|
||||
}, 500);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.charts-box {
|
||||
width: 100%;
|
||||
height: 660rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.proList-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.proList-box {
|
||||
width: 100%;
|
||||
max-height: 600rpx;
|
||||
overflow-y: scroll;
|
||||
padding: 20rpx 20rpx 0rpx 20rpx;
|
||||
|
||||
.proList-inner {
|
||||
margin-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #ebebeb;
|
||||
|
||||
.t {
|
||||
.img {}
|
||||
|
||||
.title {
|
||||
color: #303133;
|
||||
flex: 0.8;
|
||||
}
|
||||
|
||||
.time {
|
||||
flex: 0.2;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.c {
|
||||
margin: 20rpx 0;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.b {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.notice-box {
|
||||
width: 100%;
|
||||
max-height: 400rpx;
|
||||
overflow-y: scroll;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.notice-inner {
|
||||
// margin-bottom: 20rpx;
|
||||
justify-content: flex-start;
|
||||
padding: 16rpx 0;
|
||||
|
||||
.l {
|
||||
width: 64rpx;
|
||||
height: 36rpx;
|
||||
font-size: 24rpx;
|
||||
border-radius: 4rpx;
|
||||
line-height: 36rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.c {
|
||||
flex: 0.8;
|
||||
width: 61%;
|
||||
margin-left: 20rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.r {
|
||||
flex: 0.3;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sale-module {
|
||||
.sale-module-box {
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
|
||||
.head-tabs {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
align-items: flex-start;
|
||||
|
||||
.head-tabs-item {
|
||||
width: 220rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
line-height: 40rpx;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
padding: 20rpx 0;
|
||||
border-right: 1rpx solid #EEF0F4;
|
||||
text-align: center;
|
||||
|
||||
.head-tabs-inner {
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
width: 75rpx;
|
||||
height: 75rpx;
|
||||
text-align: center;
|
||||
line-height: 75rpx;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.icon-ym-wf-payDistribution {
|
||||
color: #713bdb;
|
||||
}
|
||||
|
||||
.icon-ym-Refresh {
|
||||
color: #fc5180;
|
||||
|
||||
}
|
||||
|
||||
.icon-ym-extend-folder {
|
||||
color: #ff8b58;
|
||||
}
|
||||
|
||||
.icon-ym-generator-Panel {
|
||||
color: #4ab8ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
327
pages/portal/components/index.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 卡片 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'card'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<view class="card-inner u-p-l-8 u-p-r-8 u-p-t-8">
|
||||
<Item v-for="(child, index) in activeData.children" :item="child" :key="index" />
|
||||
</view>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 排行榜 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'rankList'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HRankList :config="activeData"></HRankList>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 文本 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'text'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HText :config="activeData"></HText>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 图片 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'image'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HImage :config="activeData"></HImage>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 轮播图 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'carousel'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HCarousel :config="activeData"></HCarousel>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 视频 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'video'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HVideo :config="activeData"></HVideo>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 图表 -->
|
||||
<template v-if="activeData.show && chartList.includes(activeData.jnpfKey)">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HCharts :config="activeData" :key="key"></HCharts>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 自定义echarts -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'customEcharts'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HCustomeCharts :config="activeData" :key="key"></HCustomeCharts>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 我的待办 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'todo'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HTodo :config="activeData" :key="key"></HTodo>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 常用功能 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'dataBoard'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HDataBoard :config="activeData" :key="key"></HDataBoard>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 数据面板 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'commonFunc'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HCommonFunc :config="activeData" :key="key"></HCommonFunc>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 时间轴 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'timeAxis'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HTimeAxis :config="activeData"></HTimeAxis>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 表格 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'tableList'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HTable :config="activeData"></HTable>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 待办事项 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'todoList'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HTodoList :config="activeData"></HTodoList>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 未读邮件 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'email'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HEmail :config="activeData"></HEmail>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 公告通知 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'notice'">
|
||||
<view class="u-m-b-20">
|
||||
<HCard :cardData="activeData">
|
||||
<template #content>
|
||||
<HNotice :config="activeData"></HNotice>
|
||||
</template>
|
||||
</HCard>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 标签 -->
|
||||
<template v-if="activeData.show && activeData.jnpfKey === 'tab'">
|
||||
<view class="u-m-b-20" style="background-color: #ffffff;">
|
||||
<u-tabs :list="activeData.children" name="title" :is-scroll="activeData.children.length>3"
|
||||
v-model="tabCurrent" @change="onTabChange" :show-bar="!!activeData.type" :class="tabsClass"
|
||||
:inactive-color="activeData.type==='border-card'?' #9ea1a6':'#303133'"
|
||||
:active-item-style='activeItemStyle' :bg-color="activeData.type==='border-card'?'#f5f7fa':'#fff'">
|
||||
</u-tabs>
|
||||
<view v-for="(item,i) in activeData.children" :key='i' class="tab-inner u-p-8">
|
||||
<view v-show="i == tabCurrent">
|
||||
<Item v-for="(child, index) in item.children" :item="child" :key="key" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import HCard from './HCard'
|
||||
import HDataBoard from './HDataBoard'
|
||||
import HTable from './HTable'
|
||||
import HNotice from './HNotice'
|
||||
import HEmail from './HEmail'
|
||||
import HTodoList from './HTodoList'
|
||||
import HCharts from './HCharts'
|
||||
import HCustomeCharts from './HCustomeCharts'
|
||||
import HRankList from './HRankList'
|
||||
import HImage from './HImage'
|
||||
import HCarousel from './HCarousel'
|
||||
import HText from './HText'
|
||||
import HVideo from './HVideo'
|
||||
import HTodo from './HTodo'
|
||||
import HCommonFunc from './HCommonFunc'
|
||||
import HTimeAxis from './HTimeAxis'
|
||||
const chartList = ['barChart', 'lineChart', 'pieChart', 'radarChart', 'mapChart'];
|
||||
export default {
|
||||
name: 'Item',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
components: {
|
||||
HCard,
|
||||
HDataBoard,
|
||||
HTable,
|
||||
HNotice,
|
||||
HEmail,
|
||||
HTodoList,
|
||||
HCharts,
|
||||
HRankList,
|
||||
HImage,
|
||||
HCarousel,
|
||||
HCustomeCharts,
|
||||
HText,
|
||||
HVideo,
|
||||
HTodo,
|
||||
HCommonFunc,
|
||||
HTimeAxis
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cardData: {},
|
||||
current: 0,
|
||||
tabCurrent: 0,
|
||||
key: +new Date(),
|
||||
tabsClass: '',
|
||||
activeItemStyle: {
|
||||
'background-color': '#fff',
|
||||
},
|
||||
chartList
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
activeData() {
|
||||
const activeData = this.item;
|
||||
if (activeData.titleI18nCode) activeData.title = this.$t(activeData.titleI18nCode, activeData.title);
|
||||
if (activeData.card.cardRightBtnI18nCode) activeData.card.cardRightBtn =
|
||||
this.$t(activeData.card.cardRightBtnI18nCode, activeData.card.cardRightBtn);
|
||||
if (activeData.jnpfKey === 'tab') {
|
||||
for (let i = 0; i < activeData.children.length; i++) {
|
||||
if (activeData.children[i].titleI18nCode) activeData.children[i].title =
|
||||
this.$t(activeData.children[i].titleI18nCode, activeData.children[i].title);
|
||||
}
|
||||
}
|
||||
if (['todo', 'commonFunc', 'dataBoard'].includes(activeData.jnpfKey)) {
|
||||
for (let i = 0; i < activeData.option.defaultValue.length; i++) {
|
||||
const e = activeData.option.defaultValue[i];
|
||||
if (e.fullNameI18nCode) e.fullName = this.$t(e.fullNameI18nCode, e.fullName);
|
||||
}
|
||||
}
|
||||
if (activeData.jnpfKey === 'carousel') {
|
||||
for (let i = 0; i < activeData.option.defaultValue.length; i++) {
|
||||
const e = activeData.option.defaultValue[i];
|
||||
if (e.textDefaultValueI18nCode) {
|
||||
e.textDefaultValue = this.$t(e.textDefaultValueI18nCode, e.textDefaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeData.jnpfKey === 'text' && activeData.dataType === 'static' && activeData.option
|
||||
.defaultValueI18nCode) {
|
||||
activeData.option.defaultValue =
|
||||
this.$t(activeData.option.defaultValueI18nCode, activeData.option.defaultValue);
|
||||
}
|
||||
if (activeData.jnpfKey === 'image' && activeData.option.textDefaultValueI18nCode) {
|
||||
activeData.option.textDefaultValue =
|
||||
this.$t(activeData.option.textDefaultValueI18nCode, activeData.option.textDefaultValue);
|
||||
}
|
||||
if (['tableList', 'notice'].includes(activeData.jnpfKey)) {
|
||||
for (let i = 0; i < activeData.option.columnData.length; i++) {
|
||||
const e = activeData.option.columnData[i];
|
||||
if (e.fullNameI18nCode) e.fullName = this.$t(e.fullNameI18nCode, e.fullName);
|
||||
}
|
||||
}
|
||||
if (activeData.jnpfKey === 'rankList') {
|
||||
for (let i = 0; i < activeData.option.columnOptions.length; i++) {
|
||||
const e = activeData.option.columnOptions[i];
|
||||
if (e.labelI18nCode) e.label = this.$t(e.labelI18nCode, e.label);
|
||||
}
|
||||
}
|
||||
if (chartList.includes(activeData.jnpfKey)) {
|
||||
if (activeData.option.titleTextI18nCode) activeData.option.titleText =
|
||||
this.$t(activeData.option.titleTextI18nCode, activeData.option.titleText);
|
||||
if (activeData.option.titleSubtextI18nCode) activeData.option.titleSubtext =
|
||||
this.$t(activeData.option.titleSubtextI18nCode, activeData.option.titleSubtext);
|
||||
if (activeData.option.xAxisNameI18nCode) activeData.option.xAxisName =
|
||||
this.$t(activeData.option.xAxisNameI18nCode, activeData.option.xAxisName);
|
||||
if (activeData.option.yAxisNameI18nCode) activeData.option.yAxisName =
|
||||
this.$t(activeData.option.yAxisNameI18nCode, activeData.option.yAxisName);
|
||||
}
|
||||
return activeData
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.item.jnpfKey === 'tab') {
|
||||
const list = this.item.children
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (this.item.active == list[i].name) {
|
||||
this.tabCurrent = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (this.item.type === "border-card" || this.item.type === "card") {
|
||||
this.tabsClass = 'htabs'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(index) {
|
||||
this.current = index;
|
||||
},
|
||||
onTabChange(index) {
|
||||
if (this.tabCurrent === index) return
|
||||
this.tabCurrent = index;
|
||||
this.key = +new Date()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
381
pages/portal/mpPortal/index.vue
Normal file
@@ -0,0 +1,381 @@
|
||||
<template>
|
||||
<view class="menhu-v">
|
||||
<uni-nav-bar class='nav' :fixed="true" :statusBar="true" :border="false">
|
||||
<!-- 左边插槽 -->
|
||||
<template #left>
|
||||
<view class="">
|
||||
<uni-icons class='icon-ym icon-ym-app-role-toggle' color="#222222" size="20"
|
||||
@click="showSelectBox(0)" />
|
||||
</view>
|
||||
</template>
|
||||
<template #default>
|
||||
<view class="nav-left">
|
||||
<view class="nav-left-text">
|
||||
JNPF快速开发平台
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
<view class="content">
|
||||
<view v-if="userInfo.appPortalId">
|
||||
<view class="portal-select">
|
||||
<view class="u-flex portal-select-inner" @click.stop="showSelectBox(1)">
|
||||
<text class="portal-select-text u-line-1">{{portalTitle}}</text>
|
||||
<uni-icons class='right-icons' type="down" color="#000000" size="14"
|
||||
v-if="portalList.length > 0 && userInfo.appPortalId"
|
||||
:class="{'select-right-icons':showSelect && type ==1}" />
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" :down="downOption"
|
||||
@up="upCallback" :up="upOption" :bottombar="false" top='10'>
|
||||
<view class="portal-v" v-if="authConfig.type==0">
|
||||
<view v-if="formData.length">
|
||||
<view class="portal-box" v-for="(item,index) in formData" :key="index">
|
||||
<portalItem :item='item' ref="portalItem" :key="key" v-if="item.show" />
|
||||
</view>
|
||||
</view>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
<view v-if="authConfig.type==1">
|
||||
<view v-if="authConfig.linkType==1" style="height:calc(100vh - 100px)">
|
||||
<web-view :src="authConfig.customUrl" v-if="showWebView"></web-view>
|
||||
</view>
|
||||
<view v-else class="portal-v portal-nodata">
|
||||
<view class="u-flex-col" style="align-items: center;">
|
||||
<u-image width="280rpx" height="280rpx" :src="emptyImg"></u-image>
|
||||
<text class="u-m-t-20" style="color: #909399;">当前内容无法在APP上显示,请前往PC门户查看~~</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
<view class="portal-v" v-else>
|
||||
<view class="portal-box">
|
||||
<defaultPortal></defaultPortal>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <u-popup v-model="showSelect" mode="top" class="select-box" height="600rpx">
|
||||
<view :style="{'margin-top':statusBarHeight+88+'rpx'}"></view>
|
||||
<view v-for="(item,index) in portalList" :key="index" class="select-item" @click="selectItem(item,index)">
|
||||
<text class="u-m-r-12 u-font-40"
|
||||
:class="[item.icon,{'currentItem':item.id === userInfo.appPortalId}]" />
|
||||
<text class="item-text sysName">{{item.fullName}}</text>
|
||||
<u-icon name="checkbox-mark " class="currentItem" v-if="item.id === userInfo.appPortalId"></u-icon>
|
||||
</view>
|
||||
</u-popup> -->
|
||||
<u-popup v-model="showSelect" mode="bottom" class="select-box" height="600rpx">
|
||||
<view class="search-box" v-if="type == 1">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" bg-color="#f0f2f6" shape="square" search-icon-color="#909399" />
|
||||
</view>
|
||||
<view v-for="(item,index) in portalList" :key="index" class="select-item" @click="selectItem(item,index)">
|
||||
<text class="u-m-r-12 u-font-30"
|
||||
:class="[item.icon,{'currentItem':item.isDefault || item.id === item.appPortalId }]" />
|
||||
<text class="item-text sysName"
|
||||
:class="{'currentItem':item.isDefault || item.id === item.appPortalId}">{{item.fullName}}</text>
|
||||
<u-icon name="checkbox-mark " class="currentItem"
|
||||
v-if="item.isDefault || item.id === item.appPortalId"></u-icon>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
var wv; //计划创建的webview
|
||||
import {
|
||||
PortalList,
|
||||
SetPortal,
|
||||
auth
|
||||
} from '@/api/portal/portal'
|
||||
import {
|
||||
getUserOrganizes
|
||||
} from '@/api/common'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins"
|
||||
import IndexMixin from '@/pages/index/mixin'
|
||||
import chat from '@/libs/chat'
|
||||
import portalItem from '@/pages/portal/components/index.vue'
|
||||
import defaultPortal from '@/pages/portal/components/defaultPortal.vue'
|
||||
import emptyImg from '@/static/image/defPortal.png'
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
|
||||
export default {
|
||||
mixins: [MescrollMixin, IndexMixin],
|
||||
components: {
|
||||
portalItem,
|
||||
defaultPortal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showWebView: true,
|
||||
emptyImg: emptyImg,
|
||||
key: +new Date(),
|
||||
formData: [],
|
||||
portalTitle: '门户',
|
||||
statusBarHeight: '',
|
||||
showSelect: false,
|
||||
portalList: [],
|
||||
id: '',
|
||||
userInfo: {},
|
||||
downOption: {
|
||||
use: true,
|
||||
auto: true
|
||||
},
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 50,
|
||||
time: null
|
||||
},
|
||||
empty: {
|
||||
use: false,
|
||||
},
|
||||
textNoMore: this.$t('app.apply.noMoreData'),
|
||||
},
|
||||
authConfig: {},
|
||||
token: '',
|
||||
type: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isPortalListValid() {
|
||||
return Array.isArray(this.portalList) && this.portalList.length;
|
||||
},
|
||||
columnList() {
|
||||
return this.portalList.filter((o) => (o.fullName && o.fullName.match(this.keyword)))
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
onLoad(e) {
|
||||
uni.setStorageSync('token', e.token)
|
||||
this.$nextTick(() => {
|
||||
this.userInfo = uni.getStorageSync('userInfo') || {}
|
||||
if (!this.userInfo.appPortalId) return
|
||||
this.getPortalList()
|
||||
})
|
||||
const chatStore = useChatStore()
|
||||
if (!chatStore.getSocket) chat && chat.initSocket()
|
||||
uni.$on('refresh', () => {
|
||||
this.formData = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
upCallback(keyword) {
|
||||
auth(this.userInfo.appPortalId).then(res => {
|
||||
this.authConfig = res.data || {}
|
||||
let data = JSON.parse(res.data.formData) || {};
|
||||
this.formData = []
|
||||
this.formData = data.layout ? JSON.parse(JSON.stringify(data.layout)) : []
|
||||
this.handelFormData(data)
|
||||
if (data.refresh.autoRefresh) {
|
||||
setInterval(() => {
|
||||
uni.$emit('proRefresh')
|
||||
}, data.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
this.mescroll.endSuccess(this.formData.length);
|
||||
this.key = +new Date()
|
||||
}).catch(() => {
|
||||
this.mescroll.endSuccess(0);
|
||||
this.mescroll.endErr();
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
handelFormData(data) {
|
||||
const loop = (list) => {
|
||||
list.forEach(o => {
|
||||
o.allRefresh = data.refresh
|
||||
o.show = false
|
||||
o.platform = 'mp'
|
||||
if (o.visibility && o.visibility.length && o.visibility.includes('app')) o.show =
|
||||
true
|
||||
if (o.children && o.children.length) loop(o.children)
|
||||
})
|
||||
this.key = +new Date()
|
||||
}
|
||||
loop(this.formData)
|
||||
this.dataList = this.formData.filter(o => o.show)
|
||||
if (this.dataList.length < 1) {
|
||||
this.formData = this.dataList
|
||||
this.mescroll.endSuccess(this.dataList.length);
|
||||
}
|
||||
},
|
||||
getPortalList() {
|
||||
PortalList().then(res => {
|
||||
let list = res.data.list || [];
|
||||
this.portalList = []
|
||||
list.map(o => {
|
||||
o.children && this.portalList.push(...o.children)
|
||||
this.portalList.forEach(o => {
|
||||
o.appPortalId = this.userInfo.appPortalId
|
||||
if (o.id === o.appPortalId) this.portalTitle = o.fullName
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
showSelectBox(type) {
|
||||
this.type = type;
|
||||
if (type === 0) {
|
||||
getUserOrganizes().then(res => {
|
||||
this.portalList = res.data;
|
||||
this.portalList.forEach(o => {
|
||||
o.icon = 'icon-ym icon-ym-flow-node-condition';
|
||||
});
|
||||
if (this.isPortalListValid) this.showSelect = !this.showSelect;
|
||||
});
|
||||
} else {
|
||||
if (this.isPortalListValid) this.showSelect = !this.showSelect;
|
||||
|
||||
this.getPortalList();
|
||||
}
|
||||
},
|
||||
getStatusBarHeight() {
|
||||
let that = this;
|
||||
wx.getSystemInfo({
|
||||
success: function(res) {
|
||||
that.statusBarHeight = res.statusBarHeight;
|
||||
},
|
||||
});
|
||||
},
|
||||
selectItem(item, index) {
|
||||
SetPortal(item.id).then(res => {
|
||||
this.portalTitle = this.portalList[index].fullName
|
||||
this.userInfo.appPortalId = item.id
|
||||
this.mescroll.resetUpScroll();
|
||||
this.showSelectBox()
|
||||
uni.setStorageSync('userInfo', this.userInfo)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.menhu-v {
|
||||
.portal-v {
|
||||
padding: 0 20rpx
|
||||
}
|
||||
|
||||
.nav {
|
||||
z-index: 99999;
|
||||
|
||||
:deep(.uni-navbar__content) {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
:deep(.uni-navbar__header-container) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.nav-left-text {
|
||||
font-weight: 700;
|
||||
font-size: 32rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.right-icons {
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
margin-left: 4px;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.select-right-icons {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.portal-select {
|
||||
background-color: #fff;
|
||||
height: 80rpx;
|
||||
padding-left: 20rpx;
|
||||
line-height: 80rpx;
|
||||
|
||||
.portal-select-inner {
|
||||
width: 200rpx;
|
||||
height: 100%;
|
||||
|
||||
.portal-select-text {
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.right-icons {
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
margin-left: 4px;
|
||||
transition-duration: 0.3s;
|
||||
color: #606266 !important;
|
||||
}
|
||||
|
||||
.select-right-icons {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.select-box {
|
||||
overflow-y: scroll;
|
||||
|
||||
.currentItem {
|
||||
color: #2979FF;
|
||||
}
|
||||
|
||||
.select-item {
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
font-size: 30rpx;
|
||||
color: #303133;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 2%;
|
||||
top: 0;
|
||||
box-sizing: border-box;
|
||||
width: 96%;
|
||||
height: 1px;
|
||||
transform: scale(1, .3);
|
||||
border: 0 solid #e4e7ed;
|
||||
z-index: 2;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.sysName {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.portal-nodata) {
|
||||
position: absolute;
|
||||
top: 450rpx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 100;
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
</style>
|
||||
145
pages/portal/scanPortal/index.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<view class="scan-v">
|
||||
<!-- #ifndef MP -->
|
||||
<mescroll-body ref="mescrollRef" @down="downCallback" :down="downOption" :sticky="true" @up="upCallback"
|
||||
:up="upOption" :bottombar="false" style="min-height: 100%" @init="mescrollInit">
|
||||
<view class="portal-v">
|
||||
<view v-if="formData.length">
|
||||
<view class="portal-box" v-for="(item,index) in formData" :key="index">
|
||||
<portalItem :item='item' ref="portalItem" :portalData="formData" :key="key"></portalItem>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="!formData.length && portalConfig.linkType == 1 && portalConfig.customUrl">
|
||||
<web-view :src="portalConfig.customUrl" style="height: 100vh;"></web-view>
|
||||
</view>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
<view>
|
||||
<web-view :src="mpPortalUrl"></web-view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
// #ifndef MP
|
||||
import portalItem from '@/pages/portal/components/index.vue'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
|
||||
// #endif
|
||||
import {
|
||||
getPreviewPortal,
|
||||
auth
|
||||
} from '@/api/portal/portal.js'
|
||||
export default {
|
||||
// #ifndef MP
|
||||
mixins: [MescrollMixin],
|
||||
components: {
|
||||
portalItem
|
||||
},
|
||||
// #endif
|
||||
data() {
|
||||
return {
|
||||
mpPortalUrl: '',
|
||||
id: '',
|
||||
show: false,
|
||||
formData: [],
|
||||
dataList: [],
|
||||
fullName: '',
|
||||
downOption: {
|
||||
use: true,
|
||||
auto: true
|
||||
},
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 50,
|
||||
time: null
|
||||
},
|
||||
empty: {
|
||||
use: false,
|
||||
},
|
||||
textNoMore: this.$t('app.apply.noMoreData'),
|
||||
},
|
||||
portalType: 1,
|
||||
token: "",
|
||||
portalConfig: {},
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.fullName = e.fullName
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.fullName || '门户预览'
|
||||
})
|
||||
// #ifdef MP
|
||||
this.token = uni.getStorageSync('token')
|
||||
this.mpPortalUrl = this.define.baseURL + '/pages/portal/applyPortal/index?id=' + e.id + "&token=" + this.token
|
||||
// #endif
|
||||
// #ifndef MP
|
||||
this.id = e.id
|
||||
this.portalType = e.portalType
|
||||
uni.$on('refresh', () => {
|
||||
this.formData = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
upCallback(keyword) {
|
||||
const method = this.portalType == 1 ? auth : getPreviewPortal
|
||||
if (this.portalType != 1) this.mescroll.lockDownScroll(true);
|
||||
method(this.id).then(res => {
|
||||
this.portalConfig = res.data || {}
|
||||
let data = res.data.formData ? JSON.parse(res.data.formData) : {};
|
||||
this.formData = data.layout ? JSON.parse(JSON.stringify(data.layout)) : [];
|
||||
this.mescroll.endSuccess(this.formData.length);
|
||||
if (!this.formData.length) return
|
||||
this.handelFormData(data)
|
||||
}).catch(() => {
|
||||
this.mescroll.endSuccess(0);
|
||||
this.mescroll.endErr();
|
||||
})
|
||||
},
|
||||
handelFormData(data) {
|
||||
const loop = (list) => {
|
||||
list.forEach(o => {
|
||||
o.allRefresh = data.refresh
|
||||
o.show = false
|
||||
if (o.visibility && o.visibility.length && o.visibility.includes('app')) o.show =
|
||||
true
|
||||
if (o.children && o.children.length) loop(o.children)
|
||||
})
|
||||
this.key = +new Date()
|
||||
}
|
||||
loop(this.formData)
|
||||
this.dataList = this.formData.filter(o => o.show)
|
||||
if (this.dataList.length < 1) {
|
||||
this.formData = this.dataList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.portal-v {
|
||||
// width: 100%;
|
||||
// height: 100vh;
|
||||
|
||||
}
|
||||
|
||||
.portal-nodata {
|
||||
position: absolute;
|
||||
top: 450rpx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 100;
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
</style>
|
||||
BIN
pages/portal/static/image/1.png
Normal file
|
After Width: | Height: | Size: 1011 B |
BIN
pages/portal/static/image/2.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
pages/portal/static/image/3.png
Normal file
|
After Width: | Height: | Size: 944 B |
BIN
pages/portal/static/image/5.png
Normal file
|
After Width: | Height: | Size: 958 B |
BIN
pages/portal/static/image/champion.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
pages/portal/static/image/champion2.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
pages/portal/static/image/gg.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
pages/portal/static/image/medal0.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
pages/portal/static/image/medal1.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
pages/portal/static/image/medal2.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
pages/portal/static/image/ordinary0.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
pages/portal/static/image/ordinary1.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
pages/portal/static/image/ordinary2.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
pages/portal/static/image/portal-nodata.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
pages/portal/static/image/runnerUp.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
pages/portal/static/image/runnerUp2.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
pages/portal/static/image/thirdPlace.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
pages/portal/static/image/thirdPlace3.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
pages/portal/static/image/tz.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |