初始提交

This commit is contained in:
2026-01-04 11:09:06 +08:00
commit 8fa31df250
1326 changed files with 213907 additions and 0 deletions

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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需要赋值为trueX轴配置里需要配置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
};
}
}
}

View 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>

View 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>