feat: 新增用电量 地图

This commit is contained in:
huanghao1412 2024-07-05 17:28:23 +08:00
parent 35779870be
commit 124240e552
16 changed files with 605 additions and 76 deletions

View File

@ -51,7 +51,6 @@ export const publicInterface = async (paramType:string, interfaceType:string, pa
access_token = await getToken() as string
}
else {
console.log(import.meta.env, 777)
access_token = import.meta.env.VITE_DEV_TOKEN
}
const res = await http(RequestHttpEnum.POST)<any>(paramType, {

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -53,13 +53,13 @@ export const option = {
type: 'effectScatter',
coordinateSystem: 'geo',
symbolSize: 4,
legendHoverLink: true,
legendHoverLink: false,
showEffectOn: 'render',
rippleEffect: {
scale: 6,
color: '#FFFFFF',
brushType: 'fill'
},
// rippleEffect: {
// scale: 6,
// color: '#FFFFFF',
// brushType: 'fill'
// },
tooltip: {
show: true,
backgroundColor: 'rgba(0,0,0,.6)',
@ -78,8 +78,9 @@ export const option = {
textShadowBlur: 10,
textBorderWidth: 0,
color: '#FFFFFF',
show: true
show: false
},
symbol: 'none',
itemStyle: {
color: '#FFFFFF',
borderColor: 'rgba(225,255,255,2)',
@ -110,7 +111,7 @@ export const option = {
}
},
label: {
show: false,
show: true,
color: '#FFFFFF',
fontSize: 12
},
@ -121,13 +122,13 @@ export const option = {
fontSize: 12
},
itemStyle: {
areaColor: '#389BB7',
shadowColor: '#389BB7',
areaColor: '#4196FF',
shadowColor: '#1C58EE54',
borderWidth: 1
}
},
itemStyle: {
borderColor: '#93EBF8',
borderColor: '#00DEFFFF',
borderWidth: 1,
areaColor: {
type: 'radial',
@ -152,32 +153,39 @@ export const option = {
shadowBlur: 10
}
},
{
type: 'lines',
zlevel: 2,
effect: {
show: true,
period: 4, //箭头指向速度,值越小速度越快
trailLength: 0.4, //特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'arrow', //箭头图标
symbolSize: 7 //图标大小
},
lineStyle: {
normal: {
color: '#4fb6d2',
width: 1, //线条宽度
opacity: 0.1, //尾迹线条透明度
curveness: 0.3 //尾迹线条曲直度
}
},
data: []
}
// {
// type: 'lines',
// zlevel: 2,
// effect: {
// show: true,
// period: 4, //箭头指向速度,值越小速度越快
// trailLength: 0.4, //特效尾迹长度[0,1]值越大,尾迹越长重
// symbol: 'arrow', //箭头图标
// symbolSize: 7 //图标大小
// },
// lineStyle: {
// normal: {
// color: '#4fb6d2',
// width: 1, //线条宽度
// opacity: 0.1, //尾迹线条透明度
// curveness: 0.3 //尾迹线条曲直度
// }
// },
// data: []
// }
]
}
export const customData = {
// k: 名字 v: 数值
dataMap: '{}'
}
export const MapDefaultConfig = { ...option }
export default class Config extends PublicConfigClass implements CreateComponentType {
public key: string = MapBaseConfig.key
public attr = { ...chartInitConfig, w: 750, h: 800, zIndex: -1 }
public chartConfig = cloneDeep(MapBaseConfig)
public option = echartOptionProfixHandle(option, includes)
public customData = cloneDeep(customData)
}

View File

@ -81,7 +81,7 @@
</SettingItem>
</SettingItemBox>
<SettingItemBox name="悬浮 (预览可见)">
<SettingItemBox name="悬浮(预览可见)">
<SettingItem name="禁用">
<n-space>
<n-switch v-model:value="seriesList[1].emphasis.disabled" size="small"></n-switch>
@ -194,47 +194,47 @@
</SettingItem>
</SettingItemBox>
</CollapseItem>
<CollapseItem name="标记" :expanded="true">
<SettingItemBox name="样式">
<SettingItem name="大小">
<n-input-number v-model:value="seriesList[0].symbolSize" size="small" :min="0"></n-input-number>
</SettingItem>
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- <CollapseItem name="标记" :expanded="true">-->
<!-- <SettingItemBox name="样式">-->
<!-- <SettingItem name="大小">-->
<!-- <n-input-number v-model:value="seriesList[0].symbolSize" size="small" :min="0"></n-input-number>-->
<!-- </SettingItem>-->
<!-- <SettingItem name="颜色">-->
<!-- <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>-->
<!-- </SettingItem>-->
<!-- </SettingItemBox>-->
<SettingItemBox name="文本">
<SettingItem name="显示">
<n-space>
<n-switch v-model:value="seriesList[0].label.show" size="small"></n-switch>
</n-space>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number v-model:value="seriesList[0].label.fontSize" size="small" :min="0"></n-input-number>
</SettingItem>
<SettingItem name="字体颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].label.color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- <SettingItemBox name="文本">-->
<!-- <SettingItem name="显示">-->
<!-- <n-space>-->
<!-- <n-switch v-model:value="seriesList[0].label.show" size="small"></n-switch>-->
<!-- </n-space>-->
<!-- </SettingItem>-->
<!-- <SettingItem name="字体大小">-->
<!-- <n-input-number v-model:value="seriesList[0].label.fontSize" size="small" :min="0"></n-input-number>-->
<!-- </SettingItem>-->
<!-- <SettingItem name="字体颜色">-->
<!-- <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].label.color"></n-color-picker>-->
<!-- </SettingItem>-->
<!-- </SettingItemBox>-->
<SettingItemBox name="涟漪">
<SettingItem name="涟漪大小">
<n-input-number
v-model:value="seriesList[0].rippleEffect.scale"
:min="1"
size="small"
placeholder="请输入涟漪大小"
></n-input-number>
</SettingItem>
<SettingItem name="涟漪颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].rippleEffect.color"></n-color-picker>
</SettingItem>
<SettingItem name="涟漪的绘制方式">
<n-select size="small" v-model:value="seriesList[0].rippleEffect.brushType" :options="rippleEffectOptions" />
</SettingItem>
</SettingItemBox>
</CollapseItem>
<!-- <SettingItemBox name="涟漪">-->
<!-- <SettingItem name="涟漪大小">-->
<!-- <n-input-number-->
<!-- v-model:value="seriesList[0].rippleEffect.scale"-->
<!-- :min="1"-->
<!-- size="small"-->
<!-- placeholder="请输入涟漪大小"-->
<!-- ></n-input-number>-->
<!-- </SettingItem>-->
<!-- <SettingItem name="涟漪颜色">-->
<!-- <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].rippleEffect.color"></n-color-picker>-->
<!-- </SettingItem>-->
<!-- <SettingItem name="涟漪的绘制方式">-->
<!-- <n-select size="small" v-model:value="seriesList[0].rippleEffect.brushType" :options="rippleEffectOptions" />-->
<!-- </SettingItem>-->
<!-- </SettingItemBox>-->
<!-- </CollapseItem>-->
<CollapseItem v-if="seriesList[2]" name="飞线" :expanded="true">
<SettingItemBox name="箭头">

View File

@ -0,0 +1,14 @@
<template>
<setting-item-box name="数据映射 {&quot;k&quot;: &quot;v&quot;}" :alone="true">
<n-input v-model:value="props.customData.dataMap" size="small" placeholder="请输入"/>
</setting-item-box>
</template>
<script lang="ts" setup>
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData'])
</script>
<style lang="scss" scoped>
</style>

View File

@ -5,6 +5,7 @@ export const MapBaseConfig: ConfigType = {
key: 'MapBase',
chartKey: 'VMapBase',
conKey: 'VCMapBase',
conDataKey: 'VCDMapBase',
title: '地图(可选省份)',
category: ChatCategoryEnum.MAP,
categoryName: ChatCategoryEnumName.MAP,

View File

@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
import { PropType, reactive, watch, ref, nextTick, toRefs } from 'vue'
import { PropType, reactive, watch, ref, nextTick, toRefs, computed, Ref } from 'vue'
import config, { includes } from './config'
import VChart from 'vue-echarts'
import { icon } from '@/plugins'
@ -43,6 +43,7 @@ import { isPreview } from '@/utils'
import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
import mapChinaJson from './mapGeojson/china.json'
import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
import { customData as customDataConfig } from './config'
const props = defineProps({
themeSetting: {
@ -59,6 +60,10 @@ const props = defineProps({
}
})
const customData: Ref<typeof customDataConfig> = computed(() => {
return props.chartConfig.customData as typeof customDataConfig
})
const { ArrowBackIcon } = icon.ionicons5
let levelHistory: any = ref([])
@ -79,6 +84,16 @@ use([
const option = reactive({
value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
props.chartConfig.option.series[1].tooltip.formatter = (v: any) => {
let obj = JSON.parse(customData.value.dataMap)
let value: any
if(obj && JSON.stringify(obj) !== '{}') value = obj[v.name] || '-'
else value = v.value
let str = `<div style="display: flex;align-items: center"><span style="margin-right: 20px;">${v.name}</span><span>${value}</span></div>`
return str
}
const vChartRef = ref<typeof VChart>()
//json

View File

@ -1,4 +1,4 @@
import { MapBaseConfig } from './MapBase/index'
import { MapAmapConfig } from './MapAmap/index'
export default [MapBaseConfig, MapAmapConfig]
export default [MapBaseConfig]

View File

@ -3,7 +3,7 @@ import Pies from './Pies'
import Lines from './Lines'
// import Scatters from './Scatters'
import Mores from './Mores'
// import Maps from './Maps'
import Maps from './Maps'
// export const ChartList = [...Bars, ...Lines, ...Pies, ...Scatters, ...Maps, ...Mores]
export const ChartList = [...Bars, ...Lines, ...Pies, ...Mores]
export const ChartList = [...Bars, ...Lines, ...Pies, ...Maps, ...Mores]

View File

@ -0,0 +1,31 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { ElectricityConsumptionConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {}
export const customData = {
title: '近7日用电量',
title1: '当月用电量',
title2: '年用电量',
barId1: null,
barId2: null,
barName1: '1号楼',
barName2: '2号楼',
enable: false,
showInterval: true,
}
export default class Config extends PublicConfigClass implements CreateComponentType {
constructor() {
super();
this.attr.w = 450
this.attr.h = 300
this.request.requestInterval = 15
}
public key = ElectricityConsumptionConfig.key
public chartConfig = cloneDeep(ElectricityConsumptionConfig)
public option = cloneDeep(option)
public customData = cloneDeep(customData)
}

View File

@ -0,0 +1,23 @@
<template>
</template>
<script setup lang="ts">
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import {computed, PropType} from "vue";
import {GlobalThemeJsonType} from "@/settings/chartThemes";
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const config = computed(() => {
return props.optionData
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,37 @@
<template>
<setting-item-box name="标题1" :alone="true">
<n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="标题2" :alone="true">
<n-input v-model:value="props.customData.title1" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="标题3" :alone="true">
<n-input v-model:value="props.customData.title2" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="启用数据">
<n-space>
<n-switch v-model:value="props.customData.enable" />
</n-space>
</setting-item-box>
<setting-item-box name="柱1-ID" :alone="true">
<n-input-number v-model:value="props.customData.barId1" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="柱1-名字" :alone="true">
<n-input v-model:value="props.customData.barName1" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="柱2-ID" :alone="true">
<n-input-number v-model:value="props.customData.barId2" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="柱2-名字" :alone="true">
<n-input v-model:value="props.customData.barName1" size="small" placeholder="请输入"/>
</setting-item-box>
</template>
<script lang="ts" setup>
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const ElectricityConsumptionConfig: ConfigType = {
key: 'ElectricityConsumption',
chartKey: 'VElectricityConsumption',
conKey: 'VCElectricityConsumption',
// VCD开头
conDataKey: 'VCDElectricityConsumption',
title: '用电量',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'ElectricityConsumption.png'
}

View File

@ -0,0 +1,381 @@
<template>
<div style="overflow: visible;">
<BorderBox :title="title">
<div class="box">
<n-radio-group class="radio" v-model:value="radio.value" size="small">
<n-radio-button
v-for="it in radio.options"
:key="it.value"
:value="it.value"
:label="it.label"
/>
</n-radio-group>
<v-chart ref="vChartRef" :option="echart6Options" autoresize></v-chart>
</div>
</BorderBox>
</div>
</template>
<script setup lang="ts">
import BorderBox from '../components/BorderBox.vue'
import VChart from 'vue-echarts'
import {computed, PropType, Ref, onMounted, ref, watch, onUnmounted} from "vue";
import { customData as customDataConfig } from './config'
import { CreateComponentType } from '@/packages/index.d'
import { publicInterface } from '@/api/path/business.api'
import {isPreview} from '@/utils'
import moment from 'moment'
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const customData: Ref<typeof customDataConfig> = computed(() => {
return props.chartConfig.customData as typeof customDataConfig
})
const radio = ref({
value: '周',
options: [
{label: '周', value: '周'},
{label: '月', value: '月'},
{label: '年', value: '年'},
]
})
let title = computed(() => {
let v = ''
if(radio.value.value === '周') return v = customData.value.title
else if(radio.value.value === '月') return v = customData.value.title1
else if(radio.value.value === '年') return v = customData.value.title2
return v
})
let buildingOne7DaysData: Ref<number[]> = ref([])
let buildingTen7DaysData: Ref<number[]> = ref([])
const getWeekData = (i: number) => {
let params = {
strategy_ids: [(customData.value as any)[`barId${i + 1}`]]
}
publicInterface('/dynamic_report/manager', 'query_err_report_by_one', params).then((res: any) => {
if (res.data) {
if (i === 0) {
buildingOne7DaysData.value = res.data.map((e: any) => parseFloat(e.value).toFixed(2))
} else {
buildingTen7DaysData.value = res.data.map((e: any) => parseFloat(e.value).toFixed(2))
}
} else {
if (i === 0) {
buildingOne7DaysData.value = [0, 0, 0, 0, 0, 0, 0]
} else {
buildingTen7DaysData.value = [0, 0, 0, 0, 0, 0, 0]
}
}
handleChart()
})
}
const getMonthData = (duration: number, start_time: string, end_time: string) => {
const params = {
duration, // 234
start_time,
end_time,
strategy_ids: [customData.value.barId1, customData.value.barId2],
}
publicInterface('/dynamic_report/err', 'err', params).then((res: any) => {
if (res.data && res.data.tables) {
const data = res.data.tables.data
buildingOne7DaysData.value = data.map((e: any) => {
if (e.field0) {
return e.field0
} else {
return 0
}
})
buildingTen7DaysData.value = data.map((e: any) => {
if (e.field1) {
return e.field1
} else {
return 0
}
})
}
handleChart()
})
}
let echart6Options:Ref<any> = ref({})
const vChartRef = ref()
const handleChart = () => {
let dateList:any = []
if (radio.value.value === '周') {
for (let i = 7; i > 0; i--) {
dateList.push(moment().subtract(i, 'day').startOf('day').format('M月D日'))
}
} else if (radio.value.value === '月') {
const startDate = moment().startOf('month').format('yyyy-MM-DD HH:mm:ss')
const endDate = moment().endOf('month').subtract(1, 'day').format('yyyy-MM-DD HH:mm:ss')
dateList.push(startDate)
let addNum = 1
while (dateList[dateList.length - 1] < endDate) {
//
dateList.push(moment(startDate).add(addNum, 'days').format('yyyy-MM-DD HH:mm:ss'))
addNum++
}
dateList = dateList.map((e: any) => moment(e).format('M月D日'))
} else if (radio.value.value === '年') {
dateList = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
}
echart6Options.value = {
color: ['#00ffff', '#395bf0'],
tooltip: {
trigger: 'axis',
axisPointer: { //
type: 'shadow' // 线'line' | 'shadow'
}
},
legend: {
show: true,
top: 0,
right: 10,
itemWidth: 10,
itemHeight: 10,
itemGap: 20,
textStyle: {
color: '#fff'
},
data: [customData.value.barName1, customData.value.barName2]
},
grid: {
top: '25%',
left: '3%',
right: '4%',
bottom: '15%',
containLabel: true
},
yAxis: {
name: 'kWh',
nameTextStyle: {
color: '#fff',
padding: [0, 20, 0, 0]
},
type: 'value',
// splitNumber: 4,
axisTick: {
show: false
},
axisLine: {
show: false,
lineStyle: {
color: '#363e83'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#363e83 '
}
},
axisLabel: {
formatter: '{value}',
textStyle: {
color: '#ccc',
fontWeight: 'normal',
fontSize: '12'
}
}
},
xAxis: [
{
type: 'category',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: 'rgba(22, 44, 127, .5)'
}
},
axisLabel: {
inside: false,
textStyle: {
color: '#ccc',
fontWeight: 'normal',
fontSize: '12'
},
interval: 0
},
data: dateList
}
],
series: [
{
name: customData.value.barName1,
type: 'bar',
// xAxisIndex: 1,
zlevel: 1,
itemStyle: {
normal: {
color: () => {
return {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: 'rgba(0, 246, 249, .3)'
},
{
offset: 1,
color: 'rgba(0, 246, 249, 1)'
}
]
}
}
}
},
barWidth: '20%',
data: buildingOne7DaysData.value
},
{
name: customData.value.barName2,
type: 'bar',
// xAxisIndex: 1,
zlevel: 1,
itemStyle: {
normal: {
color: () => {
return {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: 'rgba(63, 146, 250, .3)'
},
{
offset: 1,
color: 'rgba(63, 146, 250, 1)'
}
]
}
}
}
},
barWidth: '20%',
data: buildingTen7DaysData.value
}
],
dataZoom: [
{
show: true,
height: 5,
xAxisIndex: [0],
bottom: 10,
showDetail: false,
showDataShadow: false,
borderColor: 'transparent',
textStyle: {
fontSize: 0
},
startValue: 0,
endValue: 7, // 07
backgroundColor: 'rgba(0,0,0,0)',
borderWidth: 0,
handleSize: '0%',
handleStyle: {
color: '#d3dee5'
}
},
{
type: 'inside',
zoomLock: true,
startValue: 0,
endValue: 7 // 07
}
]
}
if (radio.value.value === '月') {
echart6Options.value.dataZoom[0].endValue = 7
echart6Options.value.dataZoom[0].show = true
} else {
echart6Options.value.dataZoom[0].endValue = 31
echart6Options.value.dataZoom[0].show = false
}
}
const getData = () => {
let v = radio.value.value
if(customData.value.enable) {
if(v === '周') {
getWeekData(0)
getWeekData(1)
}
else if(v === '月') {
getMonthData(3, moment().startOf('month').format('yyyy-MM-DD HH:mm:ss'), moment().endOf('month').format('yyyy-MM-DD HH:mm:ss'))
}
else if(v === '年') {
getMonthData(4, moment().startOf('year').format('yyyy-MM-DD HH:mm:ss'), moment().endOf('year').format('yyyy-MM-DD HH:mm:ss'))
}
}
}
watch(() => radio.value.value, getData)
watch(() => customData.value.enable, getData)
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
if(customData.value.enable) getData()
}, number)
}
})
onMounted(() => {
getData()
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
if(customData.value.enable) getData()
}, number)
})
onUnmounted(() => {
if(timer) clearInterval(timer as number)
})
</script>
<style lang="scss" scoped>
.box{
width: 100%;
height: 100%;
overflow: visible;
position: relative;
.radio{
position: absolute;
right: 0;
top: -40px;
}
}
</style>

View File

@ -13,6 +13,7 @@ import { VideoListConfig } from './VideoList'
import { AirConditioningTableConfig } from './AirConditioningTable'
import { SiteStatisticsConfig } from './SiteStatistics'
import { PowerCapacityConfig } from './PowerCapacity'
import { ElectricityConsumptionConfig } from './ElectricityConsumption'
export default [
// Theme1Config,
@ -30,4 +31,5 @@ export default [
AirConditioningTableConfig,
SiteStatisticsConfig,
PowerCapacityConfig,
ElectricityConsumptionConfig,
]

View File

@ -68,6 +68,7 @@ import {
NSelect,
NSlider,
NRadioGroup,
NRadioButton,
NRadio,
NSteps,
NStep,
@ -172,6 +173,7 @@ const naive = create({
NSlider,
NSelect,
NRadioGroup,
NRadioButton,
NRadio,
NSteps,
NStep,