初次提交
210
src/components/ChartDialog/components/chart.vue
Normal file
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div class="charts">
|
||||
<Chart v-if="chartShow === 'chart'" :options="powerChart_options" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
isShow: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
powerChart_options: {
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
}
|
||||
},
|
||||
name: [],
|
||||
seriesList: [],
|
||||
Arr: [
|
||||
|
||||
],
|
||||
unit: '',
|
||||
chartShow: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler(value) {
|
||||
if (value.length) {
|
||||
const dateArr = []
|
||||
const digitalArr = []
|
||||
value.forEach((el) => {
|
||||
dateArr.push(el.date)
|
||||
digitalArr.push(this.title === 'CO2减排(吨)' ? this.forToFix(el.digital / 1000) : el.digital)
|
||||
})
|
||||
this.powerChart_options = {
|
||||
title: {
|
||||
text: this.title,
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
|
||||
boundaryGap: false,
|
||||
axisLabel: {
|
||||
interval: dateArr.length > 0 ? parseInt(dateArr.length / 5) : 0,
|
||||
showMaxLabel: true,
|
||||
// showMinLabel: true,
|
||||
formatter: (value, index) => {
|
||||
if (index !== 0 && index !== dateArr.length - 1) {
|
||||
const r = value.split(':')
|
||||
r[1] = '00'
|
||||
return r[0] + ':' + r[1]
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: { // lineStyle里面写y轴那一条线的样式
|
||||
color: '#123f63',
|
||||
width: 2 // 轴线的粗细 我写的是2 最小为0,值为0的时候线隐藏
|
||||
}
|
||||
},
|
||||
data: dateArr
|
||||
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(0,0,0,0,)',
|
||||
borderColor: 'rgba(0,0,0,0,);',
|
||||
borderWidth: 0,
|
||||
textStyle: {
|
||||
width: 160,
|
||||
height: 250,
|
||||
lineHeight: 24,
|
||||
color: '#ffffff',
|
||||
fontSize: '14',
|
||||
fontFamily: 'SourceHanSansCN-Normal'
|
||||
},
|
||||
formatter: params => {
|
||||
// 获取xAxis data中的数据
|
||||
let dataStr = `<div><p style="font-weight:bold;margin:0 8px 15px;">${params[0].name}</p></div>`
|
||||
params.forEach(item => {
|
||||
dataStr += `<div>
|
||||
<div style="margin: 0 8px;">
|
||||
<span style="display:inline-block;margin-right:5px;width:10px;height:10px;"></span>
|
||||
<span style="float:left;color:#00C8FF;">${item.data === null ? '' : item.data}</span>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
const div = `<div style='border: 1px solid ;
|
||||
border-image: linear-gradient(130deg, #FFFFFF 0%, rgba(201,255,243,0.00) 22%, rgba(201,255,243,0.00) 75%, rgba(201,255,243,0.00) 80%, #FFFFFF 99%, #FFFFFF 99%) 1;
|
||||
box-shadow: inset 0px 2px 16px 0px rgba(0, 148, 255, 0.4);' >${dataStr}</div>`
|
||||
return div
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
showSymbol: false,
|
||||
data: digitalArr,
|
||||
type: 'line',
|
||||
smooth: true
|
||||
}
|
||||
]
|
||||
}
|
||||
} else {
|
||||
this.powerChart_options = {
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
isShow: {
|
||||
handler(value) {
|
||||
this.chartShow = value
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.handler()
|
||||
|
||||
},
|
||||
mounted() {
|
||||
// this.powerChart_options = {
|
||||
// xAxis: {
|
||||
// type: 'category',
|
||||
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value'
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
// type: 'line',
|
||||
// smooth: true
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
},
|
||||
|
||||
methods: {
|
||||
handler() {
|
||||
|
||||
},
|
||||
forToFix(value) {
|
||||
// 保留两位
|
||||
if (value) {
|
||||
return value.toFixed(2) + ''
|
||||
} else {
|
||||
return 0 + ''
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.charts {
|
||||
height: 350px;
|
||||
// border: 1px solid #123f63;
|
||||
}
|
||||
</style>
|
||||
409
src/components/ChartDialog/index.vue
Normal file
@ -0,0 +1,409 @@
|
||||
<template>
|
||||
<div class="base-dialog">
|
||||
<el-dialog
|
||||
:append-to-body="false"
|
||||
center
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="visible"
|
||||
custom-class="saveAsDialog"
|
||||
>
|
||||
<div slot="title">
|
||||
<div class="new-dialog-header">{{ title }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-date-picker
|
||||
v-model="dataTime"
|
||||
class="input-box"
|
||||
type="datetimerange"
|
||||
:picker-options="pickerOptionsStart"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="changeDate"
|
||||
/>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="on_refresh"
|
||||
>{{ $t("plant.plantManager.search") }}</el-button>
|
||||
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane label="列表" name="table">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-table :data="table_data" height="400" border>
|
||||
<el-table-column prop="date" label="日期" />
|
||||
<el-table-column prop="digital" :label="colName">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="colName !== 'CO2减排(吨)'">
|
||||
{{ scope.row.digital }}
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ forToFix(scope.row.digital / 1000) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div>
|
||||
<Pagingbar>
|
||||
<div slot="page">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="pageSizes"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</Pagingbar>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="图形" name="chart">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<Chart
|
||||
:is-show="activeName"
|
||||
:options="powerChart_options"
|
||||
:title="colName"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<!-- <slot />
|
||||
<div v-if="isShowFooter" slot="footer">
|
||||
<el-button @click="visible = false">{{ cancelName }}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="confirmBtn"
|
||||
>{{ confirmName }}</el-button>
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Chart from './components/chart.vue'
|
||||
import { GetPvPanelCurve, GetPvPanelList } from '@/api/surveillance/inverter/index'
|
||||
import { pageSize, pageSizes } from '@/config'
|
||||
import Pagingbar from '@/components/Pagingbar'
|
||||
export default {
|
||||
components: {
|
||||
Chart,
|
||||
Pagingbar
|
||||
},
|
||||
props: {
|
||||
title: { // 标题
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isShow: { // 弹窗是否展示
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: { // 弹窗宽度
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
cancelName: { // 取消按钮名称
|
||||
type: String,
|
||||
default: '取 消'
|
||||
},
|
||||
confirmName: { // 确定按钮名称
|
||||
type: String,
|
||||
default: '确 定'
|
||||
},
|
||||
isShowFooter: { // 是否自定底部
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
appendToBody: { // 是否将自身插入至 body 元素,有嵌套的弹窗时一定要设置
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 设备字段
|
||||
col: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 设备id
|
||||
srcId: {
|
||||
type: [Number, String],
|
||||
default: 0 || ''
|
||||
},
|
||||
colName: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'table',
|
||||
timeIntervalOption: [{ label: '近一天', val: 'day' }, { label: '近一周', val: 'week' }, { label: '近一月', val: 'month' }],
|
||||
timeInterval: '',
|
||||
table_data: [],
|
||||
dataTime: null,
|
||||
powerChart_options: [],
|
||||
filters: {
|
||||
stationId: null,
|
||||
endTime: null,
|
||||
beginTime: null,
|
||||
mark: null
|
||||
},
|
||||
result1: null,
|
||||
result: null,
|
||||
// 当前页码
|
||||
currentPage: 1,
|
||||
// 数据总条目
|
||||
total: 0,
|
||||
// 每页显示多少条数据
|
||||
pageSize: pageSize,
|
||||
pageSizes: pageSizes,
|
||||
pickerOptionsStart: {
|
||||
// 时间不能大于当前时间
|
||||
disabledDate: (time) => {
|
||||
return time.getTime() > Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get() {
|
||||
return this.isShow
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:isShow', false)
|
||||
}
|
||||
},
|
||||
currentStation() {
|
||||
return this.$store.getters.currentStation || undefined
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible(val) { // 在此做显示与隐藏的交互
|
||||
if (val === false) {
|
||||
this.table_data = []
|
||||
// this.dataTime = null
|
||||
this.powerChart_options = []
|
||||
this.filters.beginTime = this.result
|
||||
this.filters.endTime = this.result1
|
||||
this.dataTime = [this.result, this.result1]
|
||||
// this.filters.endTime = null
|
||||
// this.filters.beginTime = null
|
||||
// 重置操作
|
||||
} else {
|
||||
this.currentPage = 1
|
||||
this.pageSize = pageSize
|
||||
this.activeName = 'table'
|
||||
const now = Date.now()
|
||||
const twentyFourHoursAgo = now - 24 * 60 * 60 * 1000
|
||||
const twentyFourHoursAgoDate = new Date(twentyFourHoursAgo)
|
||||
const year = twentyFourHoursAgoDate.getFullYear().toString().padStart(4, '0')
|
||||
const month = (twentyFourHoursAgoDate.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = twentyFourHoursAgoDate.getDate().toString().padStart(2, '0')
|
||||
const hour = twentyFourHoursAgoDate.getHours().toString().padStart(2, '0')
|
||||
const minute = twentyFourHoursAgoDate.getMinutes().toString().padStart(2, '0')
|
||||
const second = twentyFourHoursAgoDate.getSeconds().toString().padStart(2, '0')
|
||||
this.result = `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
||||
|
||||
const now1 = new Date()
|
||||
const year1 = now1.getFullYear()
|
||||
const month1 = (now1.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day1 = now1.getDate().toString().padStart(2, '0')
|
||||
const hour1 = now1.getHours().toString().padStart(2, '0')
|
||||
const minute1 = now1.getMinutes().toString().padStart(2, '0')
|
||||
const second1 = now1.getSeconds().toString().padStart(2, '0')
|
||||
this.result1 = `${year1}-${month1}-${day1} ${hour1}:${minute1}:${second1}`
|
||||
this.filters.beginTime = this.result
|
||||
this.filters.endTime = this.result1
|
||||
this.dataTime = [this.result, this.result1]
|
||||
this.$forceUpdate()
|
||||
this.GetPvPanelList()
|
||||
this.GetColHistoricalDetails()
|
||||
// 展示时操作
|
||||
}
|
||||
},
|
||||
currentStation: {
|
||||
handler(val) {
|
||||
this.filters.stationId = val.id
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
forToFix(value) {
|
||||
// 保留两位
|
||||
if (value) {
|
||||
return value.toFixed(2) + ''
|
||||
} else {
|
||||
return 0 + ''
|
||||
}
|
||||
},
|
||||
// 页码选择
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val
|
||||
this.GetPvPanelList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.currentPage = 1
|
||||
this.pageSize = val
|
||||
this.GetPvPanelList()
|
||||
},
|
||||
// confirmBtn() { // 触发保存
|
||||
// const data = {}
|
||||
// this.$emit('handleSave', data)
|
||||
// },
|
||||
on_refresh() {
|
||||
this.currentPage = 1
|
||||
this.GetPvPanelList()
|
||||
this.GetColHistoricalDetails()
|
||||
},
|
||||
async GetColHistoricalDetails() {
|
||||
if (this.colName === '输入电压(V)') {
|
||||
this.filters.mark = 1
|
||||
}
|
||||
if (this.colName === '输入电流(A)') {
|
||||
this.filters.mark = 2
|
||||
}
|
||||
let params = {}
|
||||
|
||||
try {
|
||||
params = {
|
||||
stationId: this.filters.stationId,
|
||||
endTime: this.filters.endTime,
|
||||
beginTime: this.filters.beginTime,
|
||||
col: this.col
|
||||
}
|
||||
const res = await GetPvPanelCurve(params)
|
||||
this.powerChart_options = res.data
|
||||
} catch (error) {
|
||||
this.$notify({
|
||||
title: '查询曲线失败',
|
||||
message: error.msg,
|
||||
type: 'warning',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
async GetPvPanelList() {
|
||||
const params = {
|
||||
pageNum: this.currentPage,
|
||||
pageSize: this.pageSize,
|
||||
stationId: this.filters.stationId,
|
||||
endTime: this.filters.endTime,
|
||||
beginTime: this.filters.beginTime,
|
||||
col: this.col
|
||||
}
|
||||
try {
|
||||
const res = await GetPvPanelList(params)
|
||||
this.table_data = res.data.list
|
||||
this.total = res.data.totalRows
|
||||
} catch (error) {
|
||||
this.$notify({
|
||||
title: '查询列表失败',
|
||||
message: error.msg,
|
||||
type: 'warning',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
handleClick() {
|
||||
|
||||
},
|
||||
changeTimeInterval(val) {
|
||||
|
||||
},
|
||||
changeDate(val) {
|
||||
this.filters.beginTime = val[0]
|
||||
this.filters.endTime = val[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.base-dialog {
|
||||
min-width: 300px;
|
||||
.top-search {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
// background: $card-background;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
|
||||
.serach-item {
|
||||
color: $text-color;
|
||||
.input-box {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.charts {
|
||||
width: 100%;
|
||||
min-height: 450px;
|
||||
// // border: 1px solid #123f63;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .el-dialog {
|
||||
border: 1px solid #0094ff;
|
||||
}
|
||||
/deep/ .el-dialog__header {
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.new-dialog-header {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
/deep/ .el-tabs__nav-wrap::after {
|
||||
height: 1px;
|
||||
background-color: #4f6e84;
|
||||
}
|
||||
/deep/.saveAsDialog {
|
||||
min-width: 750px;
|
||||
}
|
||||
/deep/.el-tabs__active-bar {
|
||||
background-color: #0094ff !important;
|
||||
// width: 50px!important;
|
||||
// transform: translateX(55px);
|
||||
}
|
||||
/deep/ .el-tabs__item {
|
||||
color: #616161 !important;
|
||||
}
|
||||
/deep/ .el-tabs__item.is-active {
|
||||
//切换活动项的文字颜色
|
||||
color: #ffffff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
106
src/components/ColListData/index.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="top-left-container">
|
||||
<div v-for="item in colListData" :key="item[labelKey]" :class="item.value ? 'error-item-wrap' : 'item-wrap'">
|
||||
<el-tooltip :content="item[labelKey]" placement="top" effect="dark">
|
||||
<div class="label">{{ item[labelKey] }}</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
colListData: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.top-left-container {
|
||||
width: 100%;
|
||||
padding: 10px 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.item-wrap {
|
||||
width: 49%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
justify-content: center;
|
||||
background: url(../../assets/images/right-item.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.error-item-wrap {
|
||||
width: 48%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
justify-content: center;
|
||||
background: url(../../assets/images/error-right-item.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-family: Source Han Sans CN;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
color: #ceebff;
|
||||
padding: 0 6px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
}
|
||||
|
||||
.value {
|
||||
font-family: DIN;
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
margin-top: 16px;
|
||||
text-shadow: 0px 0px 10px 0px #0094ff;
|
||||
|
||||
.naomal {
|
||||
font-family: DIN;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 0px 10px 0px #0094ff;
|
||||
}
|
||||
|
||||
.total {
|
||||
font-family: DIN;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
235
src/components/DispositionChartData/index.vue
Normal file
@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<div class="disposition-component">
|
||||
<chartDynamic
|
||||
ref="pointDialog"
|
||||
:page-location="pageLocation"
|
||||
:div-location="divLocation"
|
||||
:col-select-table-data="col_table_data"
|
||||
:permission-id="permissionId"
|
||||
:table-data="table_data"
|
||||
:disposition-show="dispositionShow"
|
||||
:station-id="stationId"
|
||||
:point-type-list="pointTypeList"
|
||||
:symbol-type="symbolType"
|
||||
:device-id="deviceId"
|
||||
:submit-site-loading="submitSiteLoading"
|
||||
@UpdataTableData="UpdataTableData"
|
||||
@clear="clear"
|
||||
@openDevDialog="openDevDialog"
|
||||
@confirm="confirm"
|
||||
@close="close"
|
||||
/>
|
||||
<colSelectDialog
|
||||
ref="dialog"
|
||||
:is-show="colDialog"
|
||||
:dev-tree-data="devTreeData"
|
||||
:col-tree-data="colTreeData"
|
||||
@changeSensType="changeSensType"
|
||||
@GetDeviceId="GetDeviceId"
|
||||
@GetQueryPoint="GetQueryPoint"
|
||||
@GetResultData="GetResultData"
|
||||
@Close="CloseCol"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GetTreeTrueDevices } from '@/api/system/virtual-device-col'
|
||||
import { GetQueryPointList } from '@/api/surveillance/battery-analysis'
|
||||
import { AddCurveList, GetCurveConfig } from '@/api/home-page'
|
||||
export default {
|
||||
name: 'DispositionComponent',
|
||||
props: {
|
||||
dispositionShow: { // 弹窗是否展示
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pageLocation: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
divLocation: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
deviceId: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
permissionId: null,
|
||||
otherPermissionId: null,
|
||||
table_data: [],
|
||||
devTreeData: [],
|
||||
dev_loading: false,
|
||||
sensType: 2,
|
||||
srcId: null,
|
||||
colDialog: false,
|
||||
colTableData: [],
|
||||
col_table_data: [],
|
||||
colTreeData: [],
|
||||
stationId: null,
|
||||
submitSiteLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentStation() {
|
||||
return this.$store.getters.currentStation || undefined
|
||||
},
|
||||
pointTypeList() {
|
||||
return this.$store.getters.dicts['pointType'] || []
|
||||
},
|
||||
symbolType() {
|
||||
return this.$store.getters.dicts['symbolType'] || []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dispositionShow: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
if (this.$store.getters.menuList.length && this.stationId !== 720) {
|
||||
this.permissionId = this.$store.getters.menuList.find((item) => {
|
||||
return item.url === this.$route.path
|
||||
}).id
|
||||
}
|
||||
this.getCurveConfig()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
currentStation: {
|
||||
handler(val) {
|
||||
if (val && val.id) {
|
||||
this.stationId = val.id
|
||||
this.FindIntegratedCabinets()
|
||||
if (this.$store.getters.menuList.length && val.id !== 720) {
|
||||
this.permissionId = this.$store.getters.menuList.find((item) => {
|
||||
return item.url === this.$route.path
|
||||
}).id
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
clear() {
|
||||
this.col_table_data = []
|
||||
this.colTreeData = []
|
||||
this.$refs.dialog.clearAll()
|
||||
},
|
||||
async confirm(params) {
|
||||
this.submitSiteLoading = true
|
||||
try {
|
||||
await AddCurveList(params)
|
||||
this.$message.success(this.$t('componentLang.operateSuccess'))
|
||||
this.close()
|
||||
this.$emit('getData')
|
||||
} catch (error) {
|
||||
// this.$message.error('新增失败')
|
||||
} finally {
|
||||
this.submitSiteLoading = false
|
||||
}
|
||||
},
|
||||
async GetQueryPoint() {
|
||||
if (this.srcId[0]) {
|
||||
this.$refs.dialog.load_data_org2 = true
|
||||
const params = {
|
||||
sensType: this.sensType,
|
||||
srcId: this.srcId[0],
|
||||
stationId: this.stationId
|
||||
}
|
||||
try {
|
||||
const res = await GetQueryPointList(params)
|
||||
const option = res.data
|
||||
// 将指标的数据处理成树
|
||||
if (option.length > 0) {
|
||||
option.forEach((el) => {
|
||||
el.colName = el.deviceName
|
||||
el.col = el.srcId
|
||||
})
|
||||
option[0].deviceTypeColList.forEach((item) => {
|
||||
item.flgId = this.srcId[0] + item.col
|
||||
})
|
||||
this.colTreeData = option[0].deviceTypeColList
|
||||
} else {
|
||||
this.colTreeData = []
|
||||
}
|
||||
} catch (error) {
|
||||
// console.log(error)
|
||||
} finally {
|
||||
this.$refs.dialog.load_data_org2 = false
|
||||
}
|
||||
}
|
||||
},
|
||||
openDevDialog() {
|
||||
this.colDialog = true
|
||||
this.colTreeData = []
|
||||
this.$refs.dialog.clearAll()
|
||||
},
|
||||
async FindIntegratedCabinets() {
|
||||
this.dev_loading = true
|
||||
try {
|
||||
const res = await GetTreeTrueDevices({ stationId: this.stationId })
|
||||
this.devTreeData = res.data
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
} finally {
|
||||
this.dev_loading = false
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
async getCurveConfig() {
|
||||
const params = {
|
||||
pageLocation: this.pageLocation,
|
||||
permissionId: this.permissionId,
|
||||
divLocation: this.divLocation,
|
||||
stationId: this.stationId,
|
||||
deviceId: this.deviceId
|
||||
}
|
||||
const res = await GetCurveConfig(params)
|
||||
if (res.data.length) {
|
||||
res.data.forEach((item) => {
|
||||
item.dragId = Math.floor(Math.random() * 1000000) + 1
|
||||
})
|
||||
}
|
||||
this.table_data = res.data
|
||||
},
|
||||
changeSensType(val) {
|
||||
this.sensType = val
|
||||
this.GetQueryPoint()
|
||||
},
|
||||
GetDeviceId(srcId) {
|
||||
// console.log(srcId)
|
||||
this.srcId = [srcId]
|
||||
},
|
||||
UpdataTableData(tableData) {
|
||||
this.col_table_data = tableData
|
||||
},
|
||||
GetResultData(newArr, tableData, colName) {
|
||||
console.log(1111, tableData, this.col_table_data)
|
||||
|
||||
this.colTableData = tableData
|
||||
tableData.forEach((item) => {
|
||||
this.col_table_data.push({ ...item, curveName: item.colName })
|
||||
})
|
||||
},
|
||||
CloseCol(data) {
|
||||
this.colTableData = data.tableData
|
||||
this.colDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
237
src/components/DispositionPointData/index.vue
Normal file
@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<div class="disposition-component">
|
||||
<pointDynamic
|
||||
ref="pointDialog"
|
||||
:page-location="pageLocation"
|
||||
:div-location="divLocation"
|
||||
:col-select-table-data="col_table_data"
|
||||
:permission-id="permissionId"
|
||||
:table-data="table_data"
|
||||
:disposition-show="dispositionShow"
|
||||
:station-id="stationId"
|
||||
:point-type-list="pointTypeList"
|
||||
:symbol-type="symbolType"
|
||||
:device-id="deviceId"
|
||||
:submit-site-loading="submitSiteLoading"
|
||||
@UpdataTableData="UpdataTableData"
|
||||
@clear="clear"
|
||||
@openDevDialog="openDevDialog"
|
||||
@confirm="confirm"
|
||||
@close="close"
|
||||
/>
|
||||
<colSelectDialog
|
||||
ref="dialog"
|
||||
:is-show="colDialog"
|
||||
:dev-tree-data="devTreeData"
|
||||
:col-tree-data="colTreeData"
|
||||
@changeSensType="changeSensType"
|
||||
@GetDeviceId="GetDeviceId"
|
||||
@GetQueryPoint="GetQueryPoint"
|
||||
@GetResultData="GetResultData"
|
||||
@Close="CloseCol"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GetTreeTrueDevices } from '@/api/system/virtual-device-col'
|
||||
import { GetQueryPointList } from '@/api/surveillance/battery-analysis'
|
||||
import { AddPointList, GetPointConfig } from '@/api/home-page'
|
||||
export default {
|
||||
name: 'DispositionComponent',
|
||||
props: {
|
||||
dispositionShow: { // 弹窗是否展示
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pageLocation: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
divLocation: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
deviceId: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
permissionId: null,
|
||||
otherPermissionId: null,
|
||||
table_data: [],
|
||||
devTreeData: [],
|
||||
dev_loading: false,
|
||||
sensType: 2,
|
||||
srcId: null,
|
||||
colDialog: false,
|
||||
colTableData: [],
|
||||
col_table_data: [],
|
||||
colTreeData: [],
|
||||
stationId: null,
|
||||
submitSiteLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentStation() {
|
||||
return this.$store.getters.currentStation || undefined
|
||||
},
|
||||
pointTypeList() {
|
||||
return this.$store.getters.dicts['pointType'] || []
|
||||
},
|
||||
symbolType() {
|
||||
return this.$store.getters.dicts['symbolType'] || []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dispositionShow: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
if (this.$store.getters.menuList.length && this.stationId !== 720) {
|
||||
this.permissionId = this.$store.getters.menuList.find((item) => {
|
||||
return item.url === this.$route.path
|
||||
}).id
|
||||
}
|
||||
this.getCurveConfig()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
currentStation: {
|
||||
handler(val) {
|
||||
if (val && val.id) {
|
||||
this.stationId = val.id
|
||||
this.FindIntegratedCabinets()
|
||||
if (this.$store.getters.menuList.length && val.id !== 720) {
|
||||
this.permissionId = this.$store.getters.menuList.find((item) => {
|
||||
return item.url === this.$route.path
|
||||
}).id
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
clear() {
|
||||
this.col_table_data = []
|
||||
this.colTreeData = []
|
||||
this.$refs.dialog.clearAll()
|
||||
},
|
||||
async confirm(params) {
|
||||
this.submitSiteLoading = true
|
||||
try {
|
||||
await AddPointList(params)
|
||||
this.$message.success(this.$t('componentLang.operateSuccess'))
|
||||
this.close()
|
||||
this.$emit('getData')
|
||||
} catch (error) {
|
||||
// this.$message.error('新增失败')
|
||||
} finally {
|
||||
this.submitSiteLoading = false
|
||||
}
|
||||
},
|
||||
async GetQueryPoint() {
|
||||
if (this.srcId[0]) {
|
||||
this.$refs.dialog.load_data_org2 = true
|
||||
const params = {
|
||||
sensType: this.sensType,
|
||||
srcId: this.srcId[0],
|
||||
stationId: this.stationId
|
||||
}
|
||||
try {
|
||||
const res = await GetQueryPointList(params)
|
||||
const option = res.data
|
||||
// 将指标的数据处理成树
|
||||
if (option.length > 0) {
|
||||
option.forEach((el) => {
|
||||
el.colName = el.deviceName
|
||||
el.col = el.srcId
|
||||
})
|
||||
option[0].deviceTypeColList.forEach((item) => {
|
||||
item.flgId = this.srcId[0] + item.col
|
||||
})
|
||||
this.colTreeData = option[0].deviceTypeColList
|
||||
} else {
|
||||
this.colTreeData = []
|
||||
}
|
||||
} catch (error) {
|
||||
// console.log(error)
|
||||
} finally {
|
||||
this.$refs.dialog.load_data_org2 = false
|
||||
}
|
||||
}
|
||||
},
|
||||
openDevDialog() {
|
||||
this.colDialog = true
|
||||
this.colTreeData = []
|
||||
this.$refs.dialog.clearAll()
|
||||
},
|
||||
async FindIntegratedCabinets() {
|
||||
this.dev_loading = true
|
||||
try {
|
||||
const res = await GetTreeTrueDevices({ stationId: this.stationId })
|
||||
this.devTreeData = res.data
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
} finally {
|
||||
this.dev_loading = false
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
async getCurveConfig() {
|
||||
const params = {
|
||||
pageLocation: this.pageLocation,
|
||||
permissionId: this.permissionId,
|
||||
divLocation: this.divLocation,
|
||||
stationId: this.stationId,
|
||||
deviceId: this.deviceId
|
||||
}
|
||||
const res = await GetPointConfig(params)
|
||||
if (res.data.length) {
|
||||
res.data.forEach((item) => {
|
||||
item.dragId = Math.floor(Math.random() * 1000000) + 1
|
||||
})
|
||||
}
|
||||
this.table_data = res.data
|
||||
},
|
||||
changeSensType(val) {
|
||||
this.sensType = val
|
||||
this.GetQueryPoint()
|
||||
},
|
||||
GetDeviceId(srcId) {
|
||||
// console.log(srcId)
|
||||
this.srcId = [srcId]
|
||||
},
|
||||
UpdataTableData(tableData) {
|
||||
this.col_table_data = tableData
|
||||
},
|
||||
GetResultData(newArr, tableData, colName) {
|
||||
this.colTableData = tableData
|
||||
tableData.forEach((item) => {
|
||||
this.col_table_data.push({
|
||||
...item,
|
||||
id: undefined,
|
||||
name: item.colName
|
||||
})
|
||||
})
|
||||
},
|
||||
CloseCol(data) {
|
||||
this.colTableData = data.tableData
|
||||
this.colDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
76
src/components/FlowToolBarNew/flowAbortWindow/index.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<section>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="$t('task.dialogVoid')"
|
||||
:visible.sync="flowAbortVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
size="tiny"
|
||||
center
|
||||
width="30%"
|
||||
>
|
||||
<div class="panel-body">
|
||||
<el-form ref="formModel" :model="oponionForm" label-width="140px" :rules="rule">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<div>
|
||||
<el-form-item
|
||||
:label="$t('task.voidOpinion') + ':'"
|
||||
prop="opinion"
|
||||
>
|
||||
<el-input v-model="oponionForm.opinion" type="textarea" :rows="4" size="small" :placeholder="$t('task.pleaseInput')" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click.native="handCancelAction">{{ $t('task.cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="loading" @click.native="handOkAction">{{ $t('task.void') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
flowAbortVisible: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
oponionForm: {
|
||||
opinion: ''
|
||||
|
||||
},
|
||||
rule: {
|
||||
opinion: [{ required: true, message: this.$t('task.pleaseInput') }]
|
||||
},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handCancelAction() {
|
||||
this.$emit('cancelaction')
|
||||
this.$refs.formModel.resetFields()
|
||||
},
|
||||
handOkAction() {
|
||||
this.$refs.formModel.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('flowabortokaction', this.oponionForm.opinion)
|
||||
this.$refs.formModel.resetFields()
|
||||
} else {
|
||||
console.log('error submit!!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
152
src/components/FlowToolBarNew/flowBackWindow/index.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<section>
|
||||
<el-dialog
|
||||
|
||||
:append-to-body="true"
|
||||
:title="$t('task.dialogBack')"
|
||||
:visible.sync="flowBackVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
size="tiny"
|
||||
center
|
||||
>
|
||||
<div class="panel-body" style="">
|
||||
<el-form ref="formModel" label-width="140px" :model="formModel" :rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item :label="$t('task.backNodeCode') + ':'" prop="backNodeCode">
|
||||
<el-select v-model="formModel.backNodeCode" :placeholder="$t('task.pleaseSelect')" size="small" style="width:100%;">
|
||||
<el-option
|
||||
v-for="item in flowData.nextNodeList"
|
||||
:key="item.taskDefinitionKey"
|
||||
:label="item.name"
|
||||
:value="item.taskDefinitionKey"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div>
|
||||
<el-form-item :label="$t('task.taskTheme') + ':'">
|
||||
<el-input v-model="flowData.bizData.title" size="small" readonly />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div style="margin: 5px 0; height: 30px;">
|
||||
<el-form-item :label="$t('task.commonOption') + ':'">
|
||||
<el-radio-group v-model="option">
|
||||
<el-radio :label="1">{{ $t('task.disagree') }}</el-radio>
|
||||
<el-radio :label="2">{{ $t('task.pleaseEdit') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div>
|
||||
<el-form-item :label="$t('task.backOption') + ':'">
|
||||
<el-input v-model="optionsText" type="textarea" :rows="3" size="small" :placeholder="$t('task.pleaseInput')" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click.native="handCancelAction">{{ $t('task.cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="loading" @click.native="handOkAction">{{ $t('task.back') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
flowBackVisible: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
workItemTitle: '',
|
||||
backNodeName: '',
|
||||
option: 2,
|
||||
optionsText: this.$t('task.pleaseEdit'),
|
||||
value: '',
|
||||
formModel: {
|
||||
backNodeCode: ''
|
||||
},
|
||||
rules: {
|
||||
backNodeCode: [
|
||||
{ required: true, message: this.$t('task.pleaseSelect'), trigger: 'change' }
|
||||
]
|
||||
},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
option(val) {
|
||||
if (val === 1) {
|
||||
this.optionsText = this.$t('task.disagree')
|
||||
} else if (val === 2) {
|
||||
this.optionsText = this.$t('task.pleaseEdit')
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
handCancelAction() {
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
getBackNode(val) {
|
||||
let obj = {}
|
||||
obj = this.flowData.nextNodeList.find((item) => {
|
||||
return item.id === val
|
||||
})
|
||||
this.backNodeName = obj.name
|
||||
},
|
||||
handOkAction() {
|
||||
this.$refs.formModel.validate((valid) => {
|
||||
if (valid) {
|
||||
console.log(this.flowData)
|
||||
const index = this.flowData.nextNodeList.findIndex(item => item.taskDefinitionKey === this.formModel.backNodeCode)
|
||||
const data = {
|
||||
processInstId: this.flowData.nextNodeList[index].processInstId,
|
||||
taskInstIds: this.flowData.nextNodeList[index].taskInstId,
|
||||
suggestion: this.optionsText,
|
||||
taskDefinitionKey: this.flowData.nextNodeList[index].taskDefinitionKey
|
||||
}
|
||||
this.$emit('flowBackOkAction', data)
|
||||
} else {
|
||||
console.log('error submit!!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
// /deep/.el-input__inner{
|
||||
// border-color:$dialogBorder !important;
|
||||
// background: #fff;
|
||||
// color: #333;
|
||||
// }
|
||||
|
||||
// /deep/.el-textarea__inner{
|
||||
// border-color:$dialogBorder !important;
|
||||
// background: #fff;
|
||||
// color: #333;
|
||||
// }
|
||||
</style>
|
||||
57
src/components/FlowToolBarNew/flowCompleteWindow/index.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<section>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="$t('task.dialogFinish')"
|
||||
:visible.sync="flowCompleteVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
size="tiny"
|
||||
>
|
||||
<div class="panel-body">
|
||||
<el-form label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<div>
|
||||
<el-form-item :label="$t('task.finishOption') + ':'">
|
||||
<el-input v-model="opinion" type="textarea" :rows="3" size="small" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click.native="handCancelAction">{{ $t('task.cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="loading" @click.native="handOkAction">{{ $t('task.sure') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
flowCompleteVisible: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
opinion: '',
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handCancelAction() {
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
handOkAction() {
|
||||
const data = {
|
||||
remark: this.opinion,
|
||||
candidateUserList: [],
|
||||
type: 1
|
||||
}
|
||||
this.$emit('flowCompleteAction', data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
498
src/components/FlowToolBarNew/flowOpinionWindow/index.vue
Normal file
@ -0,0 +1,498 @@
|
||||
<template>
|
||||
<section>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
width="60%"
|
||||
:title="$t('task.dialogTrank')"
|
||||
:visible.sync="flowOpinionVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
:center="true"
|
||||
>
|
||||
<!-- <el-radio-group v-model="options" style="margin-bottom: 20px">
|
||||
<el-radio :label="1">请尽快办理</el-radio>
|
||||
<el-radio :label="2">办理</el-radio>
|
||||
<el-radio :label="3">同意</el-radio>
|
||||
</el-radio-group> -->
|
||||
<el-table
|
||||
:span="24"
|
||||
:data="opinionData"
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
border
|
||||
:cell-style="{ 'text-align': 'center' }"
|
||||
:header-cell-style="{ 'text-align': 'center' }"
|
||||
>
|
||||
<el-table-column :label="$t('task.taskTitle')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.orderForm.title }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="userName" :label="$t('task.disposeUser')" />
|
||||
<el-table-column :label="$t('task.pendingUser')" align="left" min-width="150" :show-overflow-tooltip="true">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.candidates ? row.candidates.join(',') : row.candidates }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="candidates" label="待处理人" /> -->
|
||||
<el-table-column prop="name" :label="$t('task.status')" />
|
||||
|
||||
<el-table-column :label="$t('task.orderType')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ workOrderType(scope.row.orderForm.orderType) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('task.suggestion')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.suggestion }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('task.endTime')" :width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.endTime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('task.operate')">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
icon="el-icon-view"
|
||||
@click="handleShow(scope.row.orderForm)"
|
||||
>
|
||||
{{ $t('task.lookDetail') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button
|
||||
size="small"
|
||||
@click.native="handCancelAction"
|
||||
>{{ $t('task.close') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:title="$t('task.orderDetail')"
|
||||
:visible.sync="FormVisable"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
:center="true"
|
||||
>
|
||||
|
||||
<div class="form">
|
||||
<el-form
|
||||
ref="formModel"
|
||||
:model="formModel"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item :label="$t('task.title')" prop="title">
|
||||
<el-input v-model="formModel.title" :placeholder="$t('task.pleaseInput')" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('task.orderType')" prop="orderType">
|
||||
<el-select v-model="formModel.orderType" :placeholder="$t('task.pleaseSelect')" disabled>
|
||||
<el-option
|
||||
v-for="item in orderTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('task.plannedTime')" prop="plannedTime">
|
||||
<el-date-picker
|
||||
v-model="formModel.plannedTime"
|
||||
disabled
|
||||
type="datetime"
|
||||
:placeholder="$t('task.pleaseSelect')"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="priority" :label="$t('task.priority')">
|
||||
<el-select v-model="formModel.priority" :placeholder="$t('task.pleaseSelect')" disabled>
|
||||
<el-option
|
||||
v-for="item in priorityOptions"
|
||||
:key="item.id"
|
||||
:label="item.value"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="stationId" :label="$t('task.station')">
|
||||
<el-select
|
||||
v-model="formModel.stationId"
|
||||
disabled
|
||||
:placeholder="$t('task.pleaseSelect')"
|
||||
@change="selectStation"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in stationOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="deviceId" :label="$t('task.device')">
|
||||
<el-select v-model="formModel.deviceId" disabled :placeholder="$t('task.pleaseSelect')" @change="selectDevice">
|
||||
<el-option
|
||||
v-for="item in deviceOptions"
|
||||
:key="item.srcId"
|
||||
:label="item.deviceName"
|
||||
:value="item.srcId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="eventId" :label="$t('task.event')">
|
||||
<el-select v-model="formModel.eventId" disabled :placeholder="$t('task.pleaseSelect')">
|
||||
<el-option
|
||||
v-for="item in warningOptions"
|
||||
:key="item.id"
|
||||
:label="item.description"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="remark" :label="$t('task.remark')">
|
||||
<el-input
|
||||
v-model="formModel.remark"
|
||||
readonly
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 4, maxRows: 6 }"
|
||||
:placeholder="$t('task.pleaseInput')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" :offset="0">
|
||||
<el-form-item :label="$t('task.imgTip')">
|
||||
<uploadPanel
|
||||
ref="_upload"
|
||||
readonly
|
||||
:biz-type="uploadData"
|
||||
:biz-code="announcemnetNum"
|
||||
:upload-param="uploadData"
|
||||
:upload-url="uploadUrl"
|
||||
:delete-url="deleteUrl"
|
||||
@uploadSuccess="uploadSuccess"
|
||||
@beforeUpload="beforeUpload"
|
||||
@uploadError="uploadError"
|
||||
@beforeRemove="beforeUpload"
|
||||
@removeSuccess="uploadError"
|
||||
>
|
||||
<div class="upload-icon">
|
||||
<i class="iconfont icon-icon_attachment" />
|
||||
</div>
|
||||
</uploadPanel>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:visible.sync="dialogVisible"
|
||||
>
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
</el-dialog>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button
|
||||
size="small"
|
||||
@click.native="handCancelShow"
|
||||
>{{ $t('task.close') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uploadPanel from '@/components/WorderOrderUploadPanel/index.vue'
|
||||
import {
|
||||
getDevice,
|
||||
warningDropDownList
|
||||
} from '@/api/trouble-shooting-detail'
|
||||
import { GetDictListByType } from '@/api/system/dictionary'
|
||||
import { parseTime } from '@/utils'
|
||||
export default {
|
||||
components: { uploadPanel },
|
||||
props: {
|
||||
flowOpinionVisible: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
opinionData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
instanceID: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flowsrc: '',
|
||||
options: 1,
|
||||
FormVisable: false,
|
||||
formModel: {
|
||||
title: '',
|
||||
orderType: '',
|
||||
plannedTime: '',
|
||||
priority: '',
|
||||
stationId: '',
|
||||
deviceId: '',
|
||||
eventId: ''
|
||||
|
||||
},
|
||||
uploadData: 'DELEVERY',
|
||||
announcemnetNum: '',
|
||||
pictureResps: [],
|
||||
dialogVisible: false,
|
||||
dialogImageUrl: '',
|
||||
uploadUrl: process.env.VUE_APP_BASE_API + '/business/outerApi/uploadFile/?bucket=workorder',
|
||||
deleteUrl: process.env.VUE_APP_BASE_API + '/business/outerApi/deleteFile/?bucket=workorder',
|
||||
orderTypeOptions: this.$t('task.orderTypeOptions'),
|
||||
warningOptions: [],
|
||||
deviceOptions: [],
|
||||
priorityOptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/** 电站列表 */
|
||||
stationOptions() {
|
||||
return this.$store.getters.stations || []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
opinionData: {
|
||||
handler(val) {
|
||||
console.log(val)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
instanceID: {
|
||||
handler: function(val, oldVal) {
|
||||
// this.flowsrc =
|
||||
// cfg.server_base_url +
|
||||
// '/wf/getProcessImageExecutionId?executionId=' +
|
||||
// val + '&Authorization=' + sessionStorage.getItem('token')
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.GetPriorityList()
|
||||
},
|
||||
methods: {
|
||||
async GetPriorityList() {
|
||||
const params = {
|
||||
type: 'priority'
|
||||
}
|
||||
const res = await GetDictListByType(params)
|
||||
this.priorityOptions = res.data.list
|
||||
},
|
||||
|
||||
async GetDeviceList(id) {
|
||||
const res = await getDevice(id)
|
||||
this.deviceOptions = res.data
|
||||
},
|
||||
|
||||
async getWarningList(stationId, deviceId) {
|
||||
const params = []
|
||||
params.push({ stationId, targetDevice: deviceId })
|
||||
const res = await warningDropDownList(params)
|
||||
this.warningOptions = res.data
|
||||
},
|
||||
|
||||
handCancelShow() {
|
||||
this.FormVisable = false
|
||||
this.formModel = {
|
||||
title: '',
|
||||
orderType: '',
|
||||
plannedTime: '',
|
||||
priority: '',
|
||||
stationId: '',
|
||||
deviceId: '',
|
||||
eventId: ''
|
||||
|
||||
}
|
||||
},
|
||||
selectStation() {
|
||||
|
||||
},
|
||||
selectDevice() {
|
||||
|
||||
},
|
||||
uploadSuccess() {
|
||||
this.formLoading = false
|
||||
},
|
||||
uploadError() {
|
||||
this.formLoading = false
|
||||
},
|
||||
beforeUpload() {
|
||||
this.formLoading = true
|
||||
},
|
||||
handleShow(form) {
|
||||
this.FormVisable = true
|
||||
this.formModel = form
|
||||
if (form.deviceId) {
|
||||
this.GetDeviceList(form.stationId)
|
||||
}
|
||||
if (form.eventId) {
|
||||
this.getWarningList(form.stationId, form.deviceId)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs._upload.setFileList(form.orderFiles)
|
||||
})
|
||||
},
|
||||
workOrderType(val) {
|
||||
if (val === 1) {
|
||||
return this.$t('task.orderType1')
|
||||
}
|
||||
if (val === 2) {
|
||||
return this.$t('task.orderType2')
|
||||
}
|
||||
if (val === 3) {
|
||||
return this.$t('task.orderType3')
|
||||
}
|
||||
},
|
||||
handCancelAction() {
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
dateFormat: function(row, column) {
|
||||
const date = row[column.property]
|
||||
if (date === undefined) {
|
||||
return ''
|
||||
}
|
||||
return parseTime(date, 'yyyy-MM-dd hh:mm:ss')
|
||||
},
|
||||
formatStatus(row, column) {
|
||||
if (row.status === 0) {
|
||||
return this.$t('task.refuse')
|
||||
} else if (row.status === 1) {
|
||||
return this.$t('task.agree')
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
taskConsumingFormat: function(row, column) {
|
||||
if (row.startTime != null && row.endTime != null) {
|
||||
const start = new Date(row.startTime)
|
||||
const end = new Date(row.endTime)
|
||||
const date = end - start
|
||||
if (date === undefined) {
|
||||
return ''
|
||||
}
|
||||
// 计算出相差天数
|
||||
const days = Math.floor(date / (24 * 3600 * 1000))
|
||||
// 计算出小时数
|
||||
const leave1 = date % (24 * 3600 * 1000) // 计算天数后剩余的毫秒数
|
||||
const hours = Math.floor(leave1 / (3600 * 1000))
|
||||
// 计算相差分钟数
|
||||
const leave2 = leave1 % (3600 * 1000) // 计算小时数后剩余的毫秒数
|
||||
const minutes = Math.floor(leave2 / (60 * 1000))
|
||||
// 计算相差秒数
|
||||
const leave3 = leave2 % (60 * 1000) // 计算分钟数后剩余的毫秒数
|
||||
const seconds = Math.round(leave3 / 1000)
|
||||
if (days === 0 && hours === 0) {
|
||||
return minutes + this.$t('task.m') + seconds + this.$t('task.s')
|
||||
} else if (days === 0) {
|
||||
return hours + this.$t('task.h') + minutes + this.$t('task.m') + seconds + this.$t('task.s')
|
||||
} else {
|
||||
return (
|
||||
days + this.$t('task.d') + hours + this.$t('task.h') + minutes + this.$t('task.m') + seconds + this.$t('task.s')
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
handOkAction() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
// /deep/.el-table {
|
||||
// background: $dialogBg !important;
|
||||
// }
|
||||
// /deep/ .el-table--border::after, .el-table--group::after, .el-table::before{
|
||||
|
||||
// background-color: $dialogBorder!important;
|
||||
|
||||
// }
|
||||
// /deep/.el-table--border th, .el-table--border td {
|
||||
// border-right: 1px solid $dialogBorder !important;
|
||||
// }
|
||||
// /deep/.el-table th.is-leaf, .el-table td{
|
||||
// border-bottom: 1px solid $dialogBorder !important;
|
||||
// }
|
||||
// /deep/ .el-table td, .el-table th.is-leaf,.el-table--border, .el-table--group{
|
||||
// border-color:$dialogBorder !important;
|
||||
// }
|
||||
// /deep/ .el-table--border .el-table__cell, .el-table__body-wrapper .el-table--border.is-scrolling-left.el-table__fixed{
|
||||
|
||||
// border-right: 1px solid $dialogBorder;
|
||||
|
||||
// }
|
||||
// /deep/.el-table__body-wrapper{
|
||||
// background: $dialogBg !important;
|
||||
// }
|
||||
// ::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td{
|
||||
// background: $dialogBg;
|
||||
// }
|
||||
// ::v-deep .el-table--enable-row-transition .el-table__body td{
|
||||
// border-right: 1px solid #14c4ef !important;
|
||||
// }
|
||||
.form {
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
|
||||
::v-deep.el-select,
|
||||
.el-date-editor.el-input,
|
||||
.el-date-editor.el-input__inner {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
283
src/components/FlowToolBarNew/flowToWindow/index.vue
Normal file
@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="$t('task.dialogTransfer')"
|
||||
center
|
||||
:visible.sync="flowtoVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
width="1000px"
|
||||
>
|
||||
<div class="panel-body">
|
||||
<el-form label-width="140px">
|
||||
<el-row>
|
||||
<el-col v-if="treeShow" :span="7" class="left-box">
|
||||
<el-input v-model="filterText" :placeholder="$t('task.keyName')" />
|
||||
<el-tree
|
||||
ref="tree2"
|
||||
style="height: 340px; overflow: auto"
|
||||
:check-strictly="false"
|
||||
node-key="id"
|
||||
show-checkbox
|
||||
element-loading-text="loading"
|
||||
:data="flowWinData.treeData"
|
||||
highlight-current
|
||||
:props="defaultProps"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
:default-expand-all="expandAll"
|
||||
:filter-node-method="filterNode"
|
||||
@check-change="checkchange"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node">
|
||||
<span>
|
||||
<i :class="orgIcon(data)" aria-hidden="true" />
|
||||
<span> {{ node.label }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</el-col>
|
||||
<el-col :span="treeShow ? 17 : 24" class="right-box">
|
||||
|
||||
<el-form-item :label="$t('task.taskTitle')+ ':'">
|
||||
<el-input
|
||||
v-model="flowWinData.title"
|
||||
size="small"
|
||||
readonly
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('task.commonOption') + ':'">
|
||||
<el-radio-group v-model="options">
|
||||
<el-radio :label="2">{{ $t('task.jkbl') }}</el-radio>
|
||||
<el-radio :label="3">{{ $t('task.bl') }}</el-radio>
|
||||
<el-radio :label="4">{{ $t('task.qys') }}</el-radio>
|
||||
<el-radio :label="5">{{ $t('task.qpj') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('task.suggestion') + ':'">
|
||||
<el-input
|
||||
v-model="optionsText"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
size="small"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="treeShow"
|
||||
:label="$t('task.userList') + ':'"
|
||||
:required="treeShow"
|
||||
>
|
||||
<el-table :data="candidateUserList" border height="200">
|
||||
<el-table-column
|
||||
prop="postName"
|
||||
:label="$t('task.postName')"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="realName"
|
||||
:label="$t('task.realName')"
|
||||
/>
|
||||
<el-table-column>
|
||||
<template slot-scope="scope">
|
||||
<div class="table-column-btn">
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
icon="el-icon-delete"
|
||||
class="btn-delete-table-text"
|
||||
@click="handleTableDel(scope.$index)"
|
||||
>
|
||||
{{ $t('task.delete') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button
|
||||
size="small"
|
||||
@click.native="handCancelAction"
|
||||
>{{ $t('task.cancel') }}</el-button>
|
||||
<el-button
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
:autofocus="true"
|
||||
size="small"
|
||||
@click.native="handOkAction"
|
||||
@keyup.enter="handOkAction"
|
||||
>{{ $t('task.transfer') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
flowtoVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
flowWinData: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: 2,
|
||||
optionsText: this.$t('task.jkbl'),
|
||||
strictlycheck: true,
|
||||
filterText: '',
|
||||
data2: [],
|
||||
defaultProps: {
|
||||
children: 'userList',
|
||||
label: 'realName'
|
||||
|
||||
},
|
||||
table_data: [],
|
||||
expandedKeys: [],
|
||||
expandAll: true,
|
||||
candidateUserList: [],
|
||||
treeShow: true,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options(val) {
|
||||
if (val === 2) {
|
||||
this.optionsText = this.$t('task.jkbl')
|
||||
} else if (val === 3) {
|
||||
this.optionsText = this.$t('task.bl')
|
||||
} else if (val === 4) {
|
||||
this.optionsText = this.$t('task.qys')
|
||||
} else if (val === 5) {
|
||||
this.optionsText = this.$t('task.qpj')
|
||||
}
|
||||
},
|
||||
filterText(val) {
|
||||
this.$refs.tree2.filter(val)
|
||||
}
|
||||
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleTableDel(index) {
|
||||
this.candidateUserList.splice(index, 1)
|
||||
this.$refs.tree2.setCheckedNodes(this.candidateUserList)
|
||||
},
|
||||
filterNode(value, data, node) {
|
||||
if (!value) {
|
||||
return true
|
||||
}
|
||||
const _array = []// 这里使用数组存储 只是为了存储值。
|
||||
this.getReturnNode(node, _array, value)
|
||||
let result = false
|
||||
_array.forEach((item) => {
|
||||
result = result || item
|
||||
})
|
||||
return result
|
||||
},
|
||||
getReturnNode(node, _array, value) {
|
||||
const isPass = node.data && node.data.realName && node.data.realName.indexOf(value) !== -1
|
||||
isPass ? _array.push(isPass) : ''
|
||||
this.index++
|
||||
if (!isPass && node.level !== 1 && node.parent) {
|
||||
this.getReturnNode(node.parent, _array, value)
|
||||
}
|
||||
},
|
||||
addToLeft() {},
|
||||
addToRight() {
|
||||
const orgs = this.$refs.tree2.getCheckedNodes().filter(function(v) {
|
||||
return v.orgkind === 'EMPLOYEE'
|
||||
})
|
||||
this.candidateUserList = orgs
|
||||
},
|
||||
handleDel(item, index) {
|
||||
this.candidateUserList.splice(index, 1)
|
||||
this.$refs.tree2.setCheckedNodes(this.candidateUserList)
|
||||
},
|
||||
handCancelAction() {
|
||||
this.filterText = ''
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
handOkAction() {
|
||||
if (this.treeShow) {
|
||||
if (this.candidateUserList.length === 0) {
|
||||
this.$message({
|
||||
message: this.$t('task.noUser'),
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
const checkOrg = []
|
||||
let n = 1
|
||||
this.table_data.forEach((v) => {
|
||||
checkOrg.push({
|
||||
orgID: v.id,
|
||||
userID: v.userid,
|
||||
displayName: v.text,
|
||||
sortno: n
|
||||
})
|
||||
n++
|
||||
})
|
||||
const data = {
|
||||
remark: this.optionsText,
|
||||
candidateUserList: this.candidateUserList,
|
||||
type: 1
|
||||
}
|
||||
this.$emit('flowtookaction', data)
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
checkchange() {
|
||||
this.candidateUserList = this.$refs.tree2.getCheckedNodes().filter((node) => {
|
||||
return node.deptId !== undefined
|
||||
})
|
||||
},
|
||||
orgIcon(data) {
|
||||
if (data.orgkind === 'COMPANY') {
|
||||
return 'iconfont icon-gongsi'
|
||||
} else if (data.orgkind === 'DEPARTMENT') {
|
||||
return 'iconfont icon-bumen'
|
||||
} else if (data.orgkind === 'GROUP') {
|
||||
return 'iconfont icon-a-weibiaoti-1_huaban1fuben19'
|
||||
} else if (data.orgkind === 'POST') {
|
||||
return 'iconfont icon-04geren'
|
||||
} else if (data.orgkind === 'EMPLOYEE') {
|
||||
return 'iconfont icon-04geren'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.left-box {
|
||||
padding: 0 30px 0 0;
|
||||
border-right: 1px solid $dialogLine;
|
||||
|
||||
}
|
||||
.right-box{
|
||||
padding: 0 0 0 30px;
|
||||
|
||||
}
|
||||
// /deep/.el-dialog .el-tree__empty-block {
|
||||
// background: $dialogBg !important;
|
||||
// }
|
||||
|
||||
/deep/.el-tag.el-tag--info{
|
||||
background-color:#043050 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
267
src/components/FlowToolBarNew/flowTransmitWindow/index.vue
Normal file
@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<section>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="$t('task.dialogTransmit')"
|
||||
:visible.sync="flowTransmitVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
width="1000px"
|
||||
center=""
|
||||
>
|
||||
<div class="panel-body" style="">
|
||||
<el-form label-width="140px">
|
||||
<el-row>
|
||||
<el-col :span="7" class="left-box">
|
||||
<el-input v-model="filterText" :placeholder="$t('task.keyName')" />
|
||||
<el-tree
|
||||
ref="tree2"
|
||||
style="height: 340px; overflow: auto"
|
||||
:check-strictly="false"
|
||||
node-key="id"
|
||||
show-checkbox
|
||||
element-loading-text="loading"
|
||||
:data="flowData.treeData"
|
||||
highlight-current
|
||||
:props="defaultProps"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
:default-expand-all="expandAll"
|
||||
:filter-node-method="filterNode"
|
||||
@check-change="checkchange"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node">
|
||||
<span>
|
||||
<i :class="orgIcon(data)" aria-hidden="true" />
|
||||
<span> {{ node.label }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</el-col>
|
||||
<el-col :span="17" class="right-box">
|
||||
<el-form-item :label="$t('task.commonOption') + ':'">
|
||||
<el-radio-group v-model="options">
|
||||
<el-radio :label="1">{{ $t('task.jkbl') }}</el-radio>
|
||||
<el-radio :label="2">{{ $t('task.bl') }}</el-radio>
|
||||
<el-radio :label="3">{{ $t('task.agree') }}</el-radio>
|
||||
<el-radio :label="4">{{ $t('task.tran') }}</el-radio>
|
||||
<el-radio :label="5">{{ $t('task.qsy') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('task.tranOptions') + ':'">
|
||||
<el-input v-model="optionsText" type="textarea" :rows="3" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('task.userList') + ':'"
|
||||
required
|
||||
>
|
||||
<el-table :data="candidateUserList" border height="200">
|
||||
<el-table-column
|
||||
prop="postName"
|
||||
:label="$t('task.postName')"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="realName"
|
||||
:label="$t('task.realName')"
|
||||
/>
|
||||
<el-table-column>
|
||||
<template slot-scope="scope">
|
||||
<div class="table-column-btn">
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
icon="el-icon-delete"
|
||||
class="btn-delete-table-text"
|
||||
@click="handleTableDel(scope.$index)"
|
||||
>
|
||||
{{ $t('task.delete') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click.native="handCancelAction">{{ $t('task.cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="loading" @click.native="handOkAction">{{ $t('task.tran') }}</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
flowTransmitVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
strictlycheck: true,
|
||||
filterText: '',
|
||||
optionsText: this.$t('task.jkbl'),
|
||||
options: 1,
|
||||
defaultProps: {
|
||||
children: 'userList',
|
||||
label: 'realName'
|
||||
|
||||
},
|
||||
table_data: [],
|
||||
expandedKeys: [],
|
||||
candidateUserList: [],
|
||||
expandAll: true,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
filterText(val) {
|
||||
this.$refs.tree2.filter(val)
|
||||
},
|
||||
options(val) {
|
||||
if (val === 1) {
|
||||
this.optionsText = this.$t('task.jkbl')
|
||||
} else if (val === 2) {
|
||||
this.optionsText = this.$t('task.bl')
|
||||
} else if (val === 3) {
|
||||
this.optionsText = this.$t('task.agree')
|
||||
} else if (val === 4) {
|
||||
this.optionsText = this.$t('task.tran')
|
||||
} else if (val === 5) {
|
||||
this.optionsText = this.$t('task.qsy')
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleTableDel(index) {
|
||||
this.candidateUserList.splice(index, 1)
|
||||
this.$refs.tree2.setCheckedNodes(this.candidateUserList)
|
||||
},
|
||||
orgIcon(data) {
|
||||
if (data.orgkind === 'COMPANY') {
|
||||
return 'iconfont icon-gongsi'
|
||||
} else if (data.orgkind === 'DEPARTMENT') {
|
||||
return 'iconfont icon-bumen'
|
||||
} else if (data.orgkind === 'GROUP') {
|
||||
return 'iconfont icon-a-weibiaoti-1_huaban1fuben19'
|
||||
} else if (data.orgkind === 'POST') {
|
||||
return 'iconfont icon-04geren'
|
||||
} else if (data.orgkind === 'EMPLOYEE') {
|
||||
return 'iconfont icon-04geren'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
filterNode(value, data, node) {
|
||||
if (!value) {
|
||||
return true
|
||||
}
|
||||
const _array = []// 这里使用数组存储 只是为了存储值。
|
||||
this.getReturnNode(node, _array, value)
|
||||
let result = false
|
||||
_array.forEach((item) => {
|
||||
result = result || item
|
||||
})
|
||||
return result
|
||||
},
|
||||
getReturnNode(node, _array, value) {
|
||||
const isPass = node.data && node.data.realName && node.data.realName.indexOf(value) !== -1
|
||||
isPass ? _array.push(isPass) : ''
|
||||
this.index++
|
||||
if (!isPass && node.level !== 1 && node.parent) {
|
||||
this.getReturnNode(node.parent, _array, value)
|
||||
}
|
||||
},
|
||||
addToRight() {
|
||||
const orgs = this.$refs.tree2.getCheckedNodes().filter(function(v) {
|
||||
return v.orgkind === 'EMPLOYEE'
|
||||
})
|
||||
this.candidateUserList = orgs
|
||||
},
|
||||
handleDel: function(index, row) {
|
||||
this.candidateUserList.splice(index, 1)
|
||||
this.$refs.tree2.setCheckedNodes(this.candidateUserList)
|
||||
},
|
||||
handCancelAction() {
|
||||
this.filterText = ''
|
||||
this.$emit('cancelaction')
|
||||
},
|
||||
handOkAction() {
|
||||
if (this.candidateUserList.length === 0) {
|
||||
this.$message.error(this.$t('task.noForwardUser'))
|
||||
return
|
||||
}
|
||||
const checkOrg = []
|
||||
let n = 1
|
||||
this.table_data.forEach(v => {
|
||||
checkOrg.push({
|
||||
orgID: v.id,
|
||||
displayName: v.text,
|
||||
userID: v.userid,
|
||||
sortno: n
|
||||
})
|
||||
n++
|
||||
})
|
||||
const data = {
|
||||
remark: this.optionsText,
|
||||
candidateUserList: this.candidateUserList,
|
||||
type: 1
|
||||
}
|
||||
this.$emit('transmitokaction', data)
|
||||
this.$emit('flowTransmitWindowClose')
|
||||
},
|
||||
checkchange() {
|
||||
this.candidateUserList = this.$refs.tree2.getCheckedNodes().filter((node) => {
|
||||
return node.deptId !== undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.left-box {
|
||||
padding: 0 30px 0 0;
|
||||
border-right: 1px solid $dialogLine;
|
||||
|
||||
}
|
||||
.right-box{
|
||||
padding: 0 0 0 30px;
|
||||
// /deep/.el-input__inner{
|
||||
// background: #fff;
|
||||
// color: #333;
|
||||
// }
|
||||
}
|
||||
// /deep/.el-dialog .el-tree__empty-block {
|
||||
// background: $dialogBg !important;
|
||||
// }
|
||||
// /deep/.el-input__inner{
|
||||
// border-color:$dialogBorder !important;
|
||||
// }
|
||||
/deep/.el-tag.el-tag--info{
|
||||
background-color:#043050 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
// /deep/.el-textarea__inner{
|
||||
// border-color:$dialogBorder !important;
|
||||
// background: #fff;
|
||||
// color: #333;
|
||||
// }
|
||||
// /deep/.el-dialog__footer{
|
||||
// margin: 0 30px;
|
||||
// border-top:1px solid $dialogLine;
|
||||
// padding-top:20px;
|
||||
// }
|
||||
</style>
|
||||
598
src/components/FlowToolBarNew/index.vue
Normal file
@ -0,0 +1,598 @@
|
||||
<template>
|
||||
<section class="flow-toole-bar-container">
|
||||
<div class="btnGroup">
|
||||
<el-button-group>
|
||||
<slot />
|
||||
<el-button v-show="isBtnShow.acceptShow" type="primary" icon="el-icon-printer" :loading="isLoadingacceptBtn" @click="acceptBtn">{{ $t('task.accept') }}</el-button>
|
||||
<el-button v-show="isBtnShow.flowToShow" type="primary" icon="el-icon-sort" :loading="isLoadingflowToBtn" @click="flowToBtn">{{ $t('task.transfer') }}</el-button>
|
||||
<el-button v-show="isBtnShow.abortShow" type="primary" icon="el-icon-close" :loading="isLoadingflowAbortBtn" @click="flowAbortBtn">{{ $t('task.void') }}</el-button>
|
||||
<el-button v-show="isBtnShow.backShow" type="primary" icon="el-icon-back" :loading="isLoadingflowBackBtn" @click="flowBackBtn">{{ $t('task.back') }}</el-button>
|
||||
<el-button v-show="isBtnShow.transmitShow" type="primary" icon="el-icon-share" :loading="isLoadingflowTransmitBtn" @click="flowTransmitBtn">{{ $t('task.tran') }}</el-button>
|
||||
<el-button v-show="isBtnShow.opinionShow" type="primary" icon="el-icon-view" :loading="isLoadingflowOpinionBtn" @click="flowOpinionBtn">{{ $t('task.track') }}</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
<!-- <div class="processState">
|
||||
<el-button type="text">状态:{{ flowData.currentNodeName }}</el-button>
|
||||
</div> -->
|
||||
|
||||
<flowToWindow
|
||||
ref="toWindow"
|
||||
:flowto-visible="flowtoVisible"
|
||||
:flow-win-data="flowWinData"
|
||||
:multiple="false"
|
||||
@flowtookaction="flowtookaction"
|
||||
@cancelaction="flowToWindowClose"
|
||||
/>
|
||||
<flowAbortWindow ref="abortWindow" :flow-abort-visible="flowAbortVisible" :multiple="false" @cancelaction="flowAbortWindowClose" @flowabortokaction="flowAbortOkAction" />
|
||||
<flowCompleteWindow
|
||||
ref="completeWindow"
|
||||
:flow-complete-visible="flowCompleteVisible"
|
||||
:multiple="false"
|
||||
@cancelaction="flowCompleteWindowClose"
|
||||
@flowCompleteAction="flowCompleteAction"
|
||||
/>
|
||||
<flowBackWindow
|
||||
v-if="flowBackVisible"
|
||||
ref="backWindow"
|
||||
:flow-data="backData"
|
||||
:flow-back-visible="flowBackVisible"
|
||||
:multiple="false"
|
||||
@cancelaction="flowBackWindowClose"
|
||||
@flowBackOkAction="flowBackOkAction"
|
||||
/>
|
||||
<flowTransmitWindow
|
||||
ref="toTranSmit"
|
||||
:flow-data="transmitData"
|
||||
:flow-transmit-visible="flowTransmitVisible"
|
||||
:multiple="false"
|
||||
@cancelaction="flowTransmitWindowClose"
|
||||
@transmitokaction="flowTransmitOkAction"
|
||||
/>
|
||||
<flowOpinionWindow
|
||||
:opinion-data="opinionData"
|
||||
:instance-i-d="excutionID"
|
||||
:flow-opinion-visible="flowOpinionVisible"
|
||||
:multiple="false"
|
||||
@cancelaction="flowOpinionWindowClose"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import flowToWindow from './flowToWindow'
|
||||
import flowAbortWindow from './flowAbortWindow'
|
||||
import flowBackWindow from './flowBackWindow'
|
||||
import flowTransmitWindow from './flowTransmitWindow'
|
||||
import flowOpinionWindow from './flowOpinionWindow'
|
||||
import flowCompleteWindow from './flowCompleteWindow'
|
||||
import request from '@/utils/request'
|
||||
export default {
|
||||
components: {
|
||||
flowToWindow,
|
||||
flowTransmitWindow,
|
||||
flowBackWindow,
|
||||
flowOpinionWindow,
|
||||
flowCompleteWindow,
|
||||
flowAbortWindow
|
||||
},
|
||||
props: {
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}, // 流程数据,
|
||||
processUrl: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 流转按钮名
|
||||
circulationName: {
|
||||
type: String,
|
||||
default: '流转'
|
||||
},
|
||||
// 流程地址,
|
||||
// isBtnDisabled: {
|
||||
// //按钮禁用
|
||||
// acceptDisabled: Boolean,
|
||||
// flowToDisabled: Boolean,
|
||||
// abortDisabled: Boolean,
|
||||
// backDisabled: Boolean,
|
||||
// transmitDisabled: Boolean,
|
||||
// opinionDisabled: Boolean
|
||||
// },
|
||||
|
||||
// 按钮显示
|
||||
isBtnShow: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
acceptShow: Boolean,
|
||||
flowToShow: Boolean,
|
||||
abortShow: Boolean,
|
||||
backShow: Boolean,
|
||||
transmitShow: Boolean,
|
||||
opinionShow: Boolean,
|
||||
userShow: Boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flowWinData: {}, // 流程下一环节数据,
|
||||
opinionData: [], // 审批意见数据
|
||||
backData: {}, // 回退获取下一环节数据
|
||||
transmitData: {}, // 转发下一环节数据
|
||||
// 弹出框显示隐藏
|
||||
flowtoVisible: false,
|
||||
flowAbortVisible: false,
|
||||
flowBackVisible: false,
|
||||
flowTransmitVisible: false,
|
||||
flowOpinionVisible: false,
|
||||
flowCompleteVisible: false,
|
||||
isLoadingacceptBtn: false,
|
||||
isLoadingflowToBtn: false,
|
||||
isLoadingflowAbortBtn: false,
|
||||
isLoadingflowBackBtn: false,
|
||||
isLoadingflowTransmitBtn: false,
|
||||
isLoadingflowOpinionBtn: false,
|
||||
excutionID: '',
|
||||
userShow: true
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
flowData: {
|
||||
handler: function(val, oldVal) {
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
isBtnShow: {
|
||||
handler(val) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.toWindow.treeShow = val.userShow
|
||||
})
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 接收方法
|
||||
acceptBtn() {
|
||||
this.acceptBefore()
|
||||
this.isLoadingacceptBtn = true
|
||||
|
||||
this.$confirm('确认接收吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
showClose: false,
|
||||
center: true,
|
||||
closeOnClickModal: false
|
||||
}).then(() => {
|
||||
const para = {
|
||||
processInstId: this.flowData.bizData.processId
|
||||
}
|
||||
request.post(this.processUrl.acceptUrl, para).then(res => {
|
||||
this.isLoadingacceptBtn = false
|
||||
if (res.code === 200) {
|
||||
this.acceptComplete(res)
|
||||
this.$message({
|
||||
message: '接收成功',
|
||||
type: 'success'
|
||||
})
|
||||
this.isBtnShow.acceptShow = false
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isLoadingacceptBtn = false
|
||||
// this.load_data_org = false
|
||||
})
|
||||
}).catch(() => {
|
||||
this.isLoadingacceptBtn = false
|
||||
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消接收'
|
||||
})
|
||||
})
|
||||
},
|
||||
// 接收前
|
||||
acceptBefore() {
|
||||
this.$emit('accept')
|
||||
},
|
||||
// 接收后
|
||||
acceptComplete(data) {
|
||||
this.$emit('acceptcomplete', data)
|
||||
},
|
||||
// 打开流转框
|
||||
showFlowWindow(data) {
|
||||
if (this.flowData.userShow === false) {
|
||||
this.flowCompleteVisible = true
|
||||
} else {
|
||||
this.flowWinData = {
|
||||
title: this.flowData.title,
|
||||
treeData: data,
|
||||
currentStep: this.flowData.bizData.currentStep
|
||||
}
|
||||
this.flowtoVisible = true
|
||||
}
|
||||
},
|
||||
// 流转方法
|
||||
flowToBtn() {
|
||||
this.flowToBefore()
|
||||
},
|
||||
flowtookaction(data) {
|
||||
const self = this
|
||||
const idList = []
|
||||
data.candidateUserList.forEach(item => {
|
||||
idList.push(item.id)
|
||||
})
|
||||
const para = {
|
||||
candidateUserList: idList,
|
||||
suggestion: data.remark,
|
||||
type: data.type,
|
||||
processInstId: this.flowData.bizData.processId,
|
||||
orderForm: this.flowData.bizData
|
||||
}
|
||||
this.$refs.toWindow.loading = true
|
||||
request.post(this.processUrl.flowtoUrl, para).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success(res.msg)
|
||||
// this.flowWinData = res.data;
|
||||
this.flowToComplete(res)
|
||||
} else {
|
||||
// const msg = res.msg || '流转异常'
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
}).finally(() => {
|
||||
self.$refs.toWindow.loading = false
|
||||
})
|
||||
},
|
||||
flowCompleteAction(data) {
|
||||
const self = this
|
||||
const para = {
|
||||
candidateUserList: [],
|
||||
suggestion: data.remark,
|
||||
type: data.type,
|
||||
processInstId: this.flowData.bizData.processId,
|
||||
orderForm: this.flowData.bizData
|
||||
}
|
||||
this.$refs.completeWindow.loading = true
|
||||
request.post(this.processUrl.flowtoUrl, para).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message({
|
||||
message: '流转成功',
|
||||
type: 'success'
|
||||
})
|
||||
this.flowToComplete(res)
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
self.$refs.completeWindow.loading = false
|
||||
})
|
||||
},
|
||||
flowToBefore() {
|
||||
this.isLoadingflowToBtn = true
|
||||
const para = {
|
||||
processInstId: this.flowData.bizData.processId
|
||||
}
|
||||
request.post(this.processUrl.nextInfoUrl, para).then(res => {
|
||||
this.isLoadingflowToBtn = false
|
||||
if (res.code === 200) {
|
||||
this.showFlowWindow(res.data)
|
||||
this.$emit('flowto')
|
||||
} else {
|
||||
const msg = res.msg || '流转异常'
|
||||
this.$message({
|
||||
message: msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
flowToComplete(res) {
|
||||
this.$emit('flowtocomplete', res)
|
||||
},
|
||||
// 关闭流转完成框
|
||||
flowCompleteWindowClose() {
|
||||
this.flowCompleteVisible = false
|
||||
},
|
||||
// 关闭流转框
|
||||
flowToWindowClose() {
|
||||
this.flowtoVisible = false
|
||||
},
|
||||
|
||||
// 作废点击事件
|
||||
flowAbortBtn() {
|
||||
this.flowabortBefore()
|
||||
},
|
||||
// 关闭作废框
|
||||
flowAbortWindowClose() {
|
||||
this.flowAbortVisible = false
|
||||
},
|
||||
// 打开作废框
|
||||
showAbortWindow() {
|
||||
this.flowAbortVisible = true
|
||||
},
|
||||
// 作废前
|
||||
flowabortBefore() {
|
||||
this.isLoadingflowAbortBtn = true
|
||||
this.$confirm('确认作废吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
showClose: false,
|
||||
center: true,
|
||||
closeOnClickModal: false
|
||||
}).then(() => {
|
||||
this.isLoadingflowAbortBtn = false
|
||||
this.$emit('flowabort')
|
||||
this.showAbortWindow()
|
||||
}).catch(() => {
|
||||
this.isLoadingflowAbortBtn = false
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消作废'
|
||||
})
|
||||
})
|
||||
},
|
||||
// 作废完成
|
||||
flowabortComplete(res) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success'
|
||||
})
|
||||
this.flowAbortWindowClose()
|
||||
this.$emit('flowabortcomplete', res)
|
||||
},
|
||||
flowAbortOkAction(data) {
|
||||
const self = this
|
||||
const pram = {
|
||||
suggestion: data,
|
||||
processInstId: this.flowData.bizData.processId,
|
||||
orderForm: this.flowData.bizData
|
||||
}
|
||||
this.$refs.abortWindow.loading = true
|
||||
request.post(this.processUrl.flowAbortUrl, pram).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.flowabortComplete(res)
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
self.$refs.abortWindow.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
flowBackBtn() {
|
||||
this.flowBackBefore()
|
||||
},
|
||||
// 关闭回退框
|
||||
flowBackWindowClose() {
|
||||
this.flowBackVisible = false
|
||||
},
|
||||
// 打开回退框
|
||||
showBackWindow() {
|
||||
this.flowBackVisible = true
|
||||
},
|
||||
flowBackBefore() {
|
||||
this.isLoadingflowBackBtn = true
|
||||
const para = {
|
||||
processInstId: this.flowData.bizData.processId
|
||||
}
|
||||
request.post(this.processUrl.backInfoUrl, para).then(res => {
|
||||
this.isLoadingflowBackBtn = false
|
||||
if (res.code === 200) {
|
||||
this.backData = {
|
||||
nextNodeList: res.data,
|
||||
...this.flowData
|
||||
}
|
||||
this.$emit('flowback')
|
||||
this.showBackWindow()
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isLoadingflowBackBtn = false
|
||||
})
|
||||
},
|
||||
flowBackOkAction(data) {
|
||||
const self = this
|
||||
const para = {
|
||||
taskDefinitionKey: data.taskDefinitionKey,
|
||||
suggestion: data.suggestion,
|
||||
processInstId: data.processInstId,
|
||||
taskInstId: data.taskInstIds,
|
||||
orderForm: this.flowData.bizData
|
||||
}
|
||||
this.$refs.backWindow.loading = true
|
||||
request.post(this.processUrl.flowBackUrl, para).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.flowBackComplete(res)
|
||||
this.$message({
|
||||
message: '回退成功',
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
|
||||
}).finally(() => {
|
||||
self.$refs.backWindow.loading = false
|
||||
})
|
||||
},
|
||||
flowBackComplete(res) {
|
||||
this.$emit('flowbackcomplete', res)
|
||||
},
|
||||
|
||||
// 关闭转发框
|
||||
flowTransmitWindowClose() {
|
||||
this.flowTransmitVisible = false
|
||||
},
|
||||
// 打开转发框
|
||||
showTransmitWindow(data) {
|
||||
this.transmitData = {
|
||||
title: this.flowData.title,
|
||||
treeData: data,
|
||||
currentStep: this.flowData.bizData.currentStep
|
||||
}
|
||||
this.flowTransmitVisible = true
|
||||
},
|
||||
flowTransmitBtn() {
|
||||
this.flowTransmitBefore()
|
||||
},
|
||||
flowTransmitBefore() {
|
||||
const para = {
|
||||
processInstId: this.flowData.bizData.processId
|
||||
}
|
||||
request.post(this.processUrl.transmitInfoUrl, para).then(res => {
|
||||
this.isLoadingflowToBtn = false
|
||||
if (res.code === 200) {
|
||||
this.showTransmitWindow(res.data)
|
||||
// this.showFlowWindow(res.data)
|
||||
this.$emit('flowto')
|
||||
} else {
|
||||
const msg = res.msg || '流转异常'
|
||||
this.$message({
|
||||
message: msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
// this.isLoadingflowTransmitBtn = true
|
||||
// const para = {
|
||||
// taskId: this.flowData.bizData.id
|
||||
// }
|
||||
// request.post(this.processUrl.transmitInfoUrl, para).then(res => {
|
||||
// if (res.code === 200) {
|
||||
// this.isLoadingflowTransmitBtn = false
|
||||
// this.transmitData = res.data
|
||||
// this.$emit('flowtransmit')
|
||||
// this.showTransmitWindow()
|
||||
// } else {
|
||||
// this.$message({
|
||||
// message: res.msg,
|
||||
// type: 'error'
|
||||
// })
|
||||
// }
|
||||
// }).catch(() => {
|
||||
// this.isLoadingflowTransmitBtn = false
|
||||
// })
|
||||
},
|
||||
flowTransmitOkAction(data) {
|
||||
const self = this
|
||||
const idList = []
|
||||
data.candidateUserList.forEach(item => {
|
||||
idList.push(item.id)
|
||||
})
|
||||
const para = {
|
||||
candidateUserList: idList,
|
||||
suggestion: data.remark,
|
||||
processInstanceId: this.flowData.bizData.processId
|
||||
}
|
||||
this.$refs.toTranSmit.loading = true
|
||||
request.post(this.processUrl.flowTransmitUrl, para).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success(res.msg)
|
||||
this.flowTransmitComplete(res)
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.flowTransmitVisible = false
|
||||
}).finally(() => {
|
||||
self.$refs.toTranSmit.loading = false
|
||||
})
|
||||
},
|
||||
flowTransmitComplete(res) {
|
||||
this.flowTransmitVisible = false
|
||||
|
||||
this.$emit('flowtransmitcomplete', res)
|
||||
},
|
||||
|
||||
// 流程意见框关闭
|
||||
flowOpinionWindowClose() {
|
||||
this.flowOpinionVisible = false
|
||||
},
|
||||
// 打开意见框
|
||||
showOpinionWindow() {
|
||||
this.flowOpinionVisible = true
|
||||
},
|
||||
flowOpinionBtn() {
|
||||
let para = {}
|
||||
this.isLoadingflowOpinionBtn = true
|
||||
if (this.flowData) {
|
||||
console.log(this.flowData)
|
||||
para = {
|
||||
processInstId: this.flowData.bizData.processId,
|
||||
orderFormId: this.flowData.bizData.id
|
||||
}
|
||||
request.post(this.processUrl.flowOpinionUrl, para).then(res => {
|
||||
this.isLoadingflowOpinionBtn = false
|
||||
if (res.code === 200) {
|
||||
this.opinionData = res.data
|
||||
this.showOpinionWindow()
|
||||
} else {
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style type="text/css" scoped>
|
||||
.flow-toole-bar-container{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.btnGroup {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.processState {
|
||||
min-width: 200px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
</style>
|
||||
52
src/components/InfiniteTableTemplate/index.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table v-el-table-infinite-scroll="load" :data="data" border :infinite-scroll-disabled="disabled" height="412px">
|
||||
<el-table-column
|
||||
prop="tagName"
|
||||
label="名称"
|
||||
/>
|
||||
</el-table>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ElTableInfiniteScroll from 'el-table-infinite-scroll'
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
'el-table-infinite-scroll': ElTableInfiniteScroll
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
scrollLoading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scrollLoading(val) {
|
||||
this.scrollLoading = val
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
if (this.scrollLoading) return
|
||||
this.$emit('update:scrollLoading', true)
|
||||
this.$emit('loadmore')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
45
src/components/LangSelect/index.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<el-dropdown trigger="click" class="international" @command="handleSetLanguage">
|
||||
<div>
|
||||
<svg-icon class-name="international-icon" icon-class="language" :color="color" style="font-size: 20px;" />
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item :disabled="language==='zh'" command="zh">
|
||||
中文
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="language==='en'" command="en">
|
||||
English
|
||||
</el-dropdown-item>
|
||||
<!-- <el-dropdown-item :disabled="language==='es'" command="es">
|
||||
Español
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="language==='ja'" command="ja">
|
||||
日本語
|
||||
</el-dropdown-item> -->
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
language() {
|
||||
return this.$store.getters.language
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSetLanguage(lang) {
|
||||
this.$i18n.locale = lang
|
||||
document.title = this.$t('login.title')
|
||||
localStorage.removeItem('activeMenuName')
|
||||
this.$store.dispatch('app/setLanguage', lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
424
src/components/MapPoint/index.vue
Normal file
@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
title="地图选点"
|
||||
top="5vh"
|
||||
:visible.sync="visibleInChild"
|
||||
width="60%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div class="coord-picker">
|
||||
<div class="map-container">
|
||||
<amap
|
||||
cache-key="coord-picker-map"
|
||||
mmap-style="amap://styles/whitesmoke"
|
||||
async
|
||||
:center.sync="center"
|
||||
:zoom.sync="zoom"
|
||||
is-hotspot
|
||||
@click="onMapClick"
|
||||
>
|
||||
<amap-satellite-layer :visible="satellite" />
|
||||
|
||||
<amap-marker v-if="position" :position.sync="position" draggable />
|
||||
|
||||
<el-card class="result-panel">
|
||||
<template>
|
||||
<template v-if="mode === 'search'">
|
||||
<div style="display: flex">
|
||||
<el-select
|
||||
v-model="query"
|
||||
class="search-select"
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
placeholder="请输入关键词"
|
||||
:remote-method="autoComplete"
|
||||
:loading="loading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in tips"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
:disabled="!query"
|
||||
type="primary"
|
||||
style="margin-left: 6px"
|
||||
@click="search(true)"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="mode === 'result'">
|
||||
<div class="search-bar">
|
||||
<el-button
|
||||
icon="el-icon-arrow-left"
|
||||
style="margin-right: 6px"
|
||||
@click="reset"
|
||||
/>
|
||||
<span
|
||||
class="text"
|
||||
>搜索 {{ query }} 共
|
||||
{{ searching ? "..." : total }} 条结果</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<ul
|
||||
v-if="mode === 'result'"
|
||||
class="result-list"
|
||||
style="overflow: auto"
|
||||
>
|
||||
<el-pagination
|
||||
v-if="total > 0"
|
||||
:current-page="pageIndex"
|
||||
:page-size="pageSize"
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
<li v-for="(item, index) in results" :key="index">
|
||||
<div class="title" @click="focus(item)">{{ item.address }}</div>
|
||||
<span class="sub-title" @click="focus(item)">{{
|
||||
item.name
|
||||
}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-card>
|
||||
<el-card class="info">
|
||||
<el-form class="form-control">
|
||||
<el-form-item v-if="position" label="坐标">
|
||||
<el-input
|
||||
read-only
|
||||
:value="positionText"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="卫星图">
|
||||
<el-switch v-model="satellite" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</amap>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleToSelected"
|
||||
>确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loadAmap, loadPlugins } from '@amap/amap-vue'
|
||||
window._AMapSecurityConfig = {
|
||||
securityJsCode: '2e16af43283c658cba14be1731649afc'
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
mapCenter: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mode: 'search',
|
||||
zoom: 10,
|
||||
center: null,
|
||||
query: '',
|
||||
address: '',
|
||||
searching: false,
|
||||
tips: [],
|
||||
results: [],
|
||||
position: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
satellite: false,
|
||||
loading: false,
|
||||
// 当前页码
|
||||
currentPage: 1,
|
||||
// 数据总条目
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleInChild: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
},
|
||||
wrapper() {
|
||||
return this.$refs.wrapper
|
||||
},
|
||||
positionText() {
|
||||
if (!this.position) return ''
|
||||
return `${this.position[0]}, ${this.position[1]}`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pageIndex(value) {
|
||||
this.$ready.then(() => {
|
||||
this.ps.setPageIndex(value)
|
||||
this.search(false)
|
||||
})
|
||||
}
|
||||
// mapCenter(value) {
|
||||
// if (value) {
|
||||
// this.center = value
|
||||
// }
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
this.$ready = new Promise((resolve) => {
|
||||
this.loadAmap()
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async loadAmap() {
|
||||
const AMap = await loadAmap()
|
||||
loadPlugins(['AMap.PlaceSearch', 'AMap.AutoComplete'])
|
||||
this.ps = new AMap.PlaceSearch({
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
this.ac = new AMap.AutoComplete()
|
||||
},
|
||||
// 页码选择
|
||||
handleCurrentChange(val) {
|
||||
const self = this
|
||||
this.pageIndex = val
|
||||
this.$ready.then(() => {
|
||||
self.ps.setPageIndex(val)
|
||||
self.search(false)
|
||||
})
|
||||
},
|
||||
onMapClick(e) {
|
||||
const self = this
|
||||
if (e.lnglat) {
|
||||
this.position = [e.lnglat.lng, e.lnglat.lat]
|
||||
// 这里通过高德 SDK 完成。
|
||||
const geocoder = new AMap.Geocoder()
|
||||
geocoder.getAddress(this.position, function(status, result) {
|
||||
if (status === 'complete' && result.info === 'OK') {
|
||||
if (result && result.regeocode) {
|
||||
self.address = result.regeocode.formattedAddress
|
||||
self.$nextTick()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.position = null
|
||||
}
|
||||
},
|
||||
async search(clear = false) {
|
||||
this.mode = 'result'
|
||||
await this._ready
|
||||
|
||||
if (clear) {
|
||||
this.results = []
|
||||
this.total = 0
|
||||
this.pageIndex = 1
|
||||
this.ps.setPageIndex(1)
|
||||
}
|
||||
|
||||
this.searching = true
|
||||
const { query } = this
|
||||
this.ps.search(query, (status, result) => {
|
||||
this.searching = false
|
||||
if (query !== this.query) return
|
||||
|
||||
if (status === 'complete' && result.poiList) {
|
||||
this.results = result.poiList.pois
|
||||
this.total = result.poiList.count
|
||||
} else {
|
||||
this.results = []
|
||||
this.total = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
async autoComplete(kw) {
|
||||
const self = this
|
||||
self.query = kw
|
||||
if (!kw) {
|
||||
this.tips = []
|
||||
} else {
|
||||
this.ac.search(kw, (status, result) => {
|
||||
if (status === 'complete' && result.tips) {
|
||||
this.tips = result.tips
|
||||
} else {
|
||||
this.tips = []
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
focus(poi) {
|
||||
const self = this
|
||||
const pos = [poi.location.lng, poi.location.lat]
|
||||
this.position = [...pos]
|
||||
this.center = [...pos]
|
||||
const geocoder = new AMap.Geocoder()
|
||||
geocoder.getAddress(this.position, function(status, result) {
|
||||
if (status === 'complete' && result.info === 'OK') {
|
||||
if (result && result.regeocode) {
|
||||
self.address = result.regeocode.formattedAddress
|
||||
self.$nextTick()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
reset() {
|
||||
this.ps.setPageIndex(1)
|
||||
this.results = []
|
||||
this.tips = []
|
||||
this.total = 0
|
||||
this.mode = 'search'
|
||||
},
|
||||
handleToSelected() {
|
||||
const parsms = {
|
||||
address: this.address,
|
||||
position: this.position
|
||||
}
|
||||
this.$emit('mapPoint', parsms)
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('mapClose')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 540px;
|
||||
.search-select {
|
||||
flex: 1;
|
||||
::v-deep .el-input__inner {
|
||||
background: #fff !important;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-panel {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
width: 380px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 450px;
|
||||
overflow-y: auto;
|
||||
padding-top: 0;
|
||||
.result-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
li {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.sub-title {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.text {
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.result-list.ant-list-loading {
|
||||
min-height: 100px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
padding-left: 10px;
|
||||
background: #fff;
|
||||
color: #606266;
|
||||
::v-deep .el-card__body {
|
||||
padding: 5px;
|
||||
}
|
||||
.form-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
::v-deep .el-form-item__label {
|
||||
color: #606266 !important;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
background-color: #fff;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .el-card__body .el-pagination {
|
||||
color: #606266;
|
||||
.el-pagination__total {
|
||||
color: #606266;
|
||||
}
|
||||
button:disabled {
|
||||
color: #606266;
|
||||
background-color: #fff;
|
||||
}
|
||||
li {
|
||||
color: #606266;
|
||||
background-color: #fff;
|
||||
}
|
||||
.el-pager li.active {
|
||||
color: #21a6df !important;
|
||||
cursor: default;
|
||||
}
|
||||
.el-pagination__jump {
|
||||
color: #606266;
|
||||
}
|
||||
.btn-next,
|
||||
.btn-prev {
|
||||
color: #606266;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
src/components/ModelKuang/index.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div v-show="isModelShow" id="commitModal" class="modal" aria-hidden="true">
|
||||
|
||||
<div class="modal-dialog">
|
||||
<!-- <div class="modal-header">
|
||||
<span id="close" class="btn-close" aria-hidden="true">×</span>
|
||||
</div> -->
|
||||
<div class="modal-body">
|
||||
<el-progress type="circle" :percentage="percentage" :color="colors" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
isModelShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
percentage: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
colors: [
|
||||
{ color: '#f56c6c', percentage: 20 },
|
||||
{ color: '#e6a23c', percentage: 40 },
|
||||
{ color: '#6f7ad3', percentage: 60 },
|
||||
{ color: '#1989fa', percentage: 80 },
|
||||
{ color: '#5cb87a', percentage: 100 }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
display: block;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
width:100%;
|
||||
height:100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.btn-close {
|
||||
color: #aaa;
|
||||
font-size: 30px;
|
||||
text-decoration: none;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
}
|
||||
.btn-close:hover {
|
||||
color: #919191;
|
||||
}
|
||||
.modal-dialog {
|
||||
width:calc(100% - 210px);
|
||||
height:fit-content;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
.modal-body {
|
||||
padding: 10px 20px;
|
||||
height: calc(100% - 105px);
|
||||
overflow: auto;
|
||||
}
|
||||
.modal-header h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.modal-footer {
|
||||
border-top: #eee solid 1px;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #428bca;
|
||||
border: #357ebd solid 1px;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding: 2px 5px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
position: relative;
|
||||
transition: color .1s ease;
|
||||
}
|
||||
.btn-new{
|
||||
background: #fff;
|
||||
border: #357ebd solid 1px;
|
||||
border-radius: 3px;
|
||||
color: #428bca;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding: 2px 5px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
position: relative;
|
||||
transition: color .1s ease;
|
||||
}
|
||||
.modal-header,
|
||||
.modal-footer {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.modal-header {
|
||||
border-bottom: #eee solid 1px;
|
||||
height:20px;
|
||||
}
|
||||
</style>
|
||||
14
src/components/Pagingbar/index.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="bottom-toolbar ofh">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<div class="fl">
|
||||
<slot name="handler" />
|
||||
</div>
|
||||
<div class="fr">
|
||||
<slot name="page" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
126
src/components/RightMenu/index.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<ul class="table-right-menu">
|
||||
<!-- 循环菜单项,事件带参数抛出 -->
|
||||
<li
|
||||
v-for="item in rightclickInfo.menulists"
|
||||
:key="item.btnName"
|
||||
class="table-right-menu-item"
|
||||
@click.stop="fnHandler(item)"
|
||||
>
|
||||
<div class="table-right-menu-item-btn">
|
||||
<!-- 图标和按钮名 -->
|
||||
<i :class="item.icoName" class="iii" />
|
||||
<span>{{ item.btnName }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MyRightMenu',
|
||||
props: {
|
||||
// 接收右键点击的信息
|
||||
rightclickInfo: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
position: {
|
||||
// 右键点击的位置
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnName: '', // 点击菜单项的事件名
|
||||
params: {}, // 点击的参数
|
||||
icoName: '', // 图标名
|
||||
btnName: '' // 按钮名
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
// 重要参数,用于标识是哪个右键菜单dom元素
|
||||
classIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听右键点击时点击位置的变化,只要变化了,就弹出右键菜单供用户点击操作
|
||||
'rightclickInfo.position'(val) {
|
||||
const x = val.x // 获取x轴坐标
|
||||
const y = val.y // 获取y轴坐标
|
||||
const innerWidth = window.innerWidth // 获取页面可是区域宽度,即页面的宽度
|
||||
const innerHeight = window.innerHeight // 获取可视区域高度,即页面的高度
|
||||
/**
|
||||
* 注意,这里要使用getElementsByClassName去选中对应dom,因为右键菜单组件可能被多处使用
|
||||
* classIndex标识就是去找到对应的那个右键菜单组件的,需要加的
|
||||
* */
|
||||
const menu =
|
||||
document.getElementsByClassName('table-right-menu')[this.classIndex]
|
||||
menu.style.display = 'block'
|
||||
const menuHeight = this.rightclickInfo.menulists.length * 30 // 菜单容器高
|
||||
const menuWidth = 180 // 菜单容器宽
|
||||
// 菜单的位置计算
|
||||
menu.style.top =
|
||||
(y + menuHeight > innerHeight ? innerHeight - menuHeight : y) + 'px'
|
||||
menu.style.left =
|
||||
(x + menuWidth > innerWidth ? innerWidth - menuWidth : x) + 'px'
|
||||
// 因为菜单还要关闭,就绑定一个鼠标点击事件,通过e.button判断点击的是否是左键,左键关闭菜单
|
||||
document.addEventListener('mouseup', this.hide, false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hide(e) {
|
||||
if (e.button === 0) {
|
||||
// 0是左键、1是滚轮按钮或中间按钮(若有)、2鼠标右键
|
||||
const menu =
|
||||
document.getElementsByClassName('table-right-menu')[this.classIndex] // 同样的精确查找
|
||||
menu.style.display = 'none' // 菜单关闭
|
||||
document.removeEventListener('mouseup', this.hide) // 及时解绑监听事件
|
||||
}
|
||||
},
|
||||
fnHandler(item) {
|
||||
this.$emit(item.fnName, item.params)
|
||||
// 事件再传出去,即为:
|
||||
// this.$emit('事件名',事件参数)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.table-right-menu {
|
||||
color: #333;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
list-style-type: none;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 0;
|
||||
// 固定定位,抬高层级,初始隐藏,右击时置为display:block显示
|
||||
position: fixed;
|
||||
z-index: 3000;
|
||||
display: none;
|
||||
.table-right-menu-item {
|
||||
box-sizing: border-box;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.36s;
|
||||
cursor: pointer;
|
||||
.table-right-menu-item-btn {
|
||||
.iii {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.table-right-menu-item:hover {
|
||||
background-color: #ebf5ff;
|
||||
color: #6bacf2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
145
src/components/RightPanel/index.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
|
||||
<div class="rightPanel-background" />
|
||||
<div class="rightPanel">
|
||||
<div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
|
||||
<i :class="show?'el-icon-close':'el-icon-setting'" />
|
||||
</div>
|
||||
<div class="rightPanel-items">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addClass, removeClass } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'RightPanel',
|
||||
props: {
|
||||
clickNotClose: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
buttonTop: {
|
||||
default: 250,
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
theme() {
|
||||
return this.$store.state.settings.theme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(value) {
|
||||
if (value && !this.clickNotClose) {
|
||||
this.addEventClick()
|
||||
}
|
||||
if (value) {
|
||||
addClass(document.body, 'showRightPanel')
|
||||
} else {
|
||||
removeClass(document.body, 'showRightPanel')
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.insertToBody()
|
||||
},
|
||||
beforeDestroy() {
|
||||
const elx = this.$refs.rightPanel
|
||||
elx.remove()
|
||||
},
|
||||
methods: {
|
||||
addEventClick() {
|
||||
window.addEventListener('click', this.closeSidebar)
|
||||
},
|
||||
closeSidebar(evt) {
|
||||
const parent = evt.target.closest('.rightPanel')
|
||||
if (!parent) {
|
||||
this.show = false
|
||||
window.removeEventListener('click', this.closeSidebar)
|
||||
}
|
||||
},
|
||||
insertToBody() {
|
||||
const elx = this.$refs.rightPanel
|
||||
const body = document.querySelector('body')
|
||||
body.insertBefore(elx, body.firstChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.showRightPanel {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: calc(100% - 15px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rightPanel-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
|
||||
background: rgba(0, 0, 0, .2);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.rightPanel {
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
||||
transition: all .25s cubic-bezier(.7, .3, .1, 1);
|
||||
transform: translate(100%);
|
||||
background: #fff;
|
||||
z-index: 40000;
|
||||
}
|
||||
|
||||
.show {
|
||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||
|
||||
.rightPanel-background {
|
||||
z-index: 20000;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.rightPanel {
|
||||
transform: translate(0);
|
||||
}
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
z-index: 0;
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
i {
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
265
src/components/SchemeModel/index.vue
Normal file
@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
title="方案指标配置"
|
||||
:visible.sync="visiable"
|
||||
width="60%"
|
||||
:close-on-click-modal="false"
|
||||
center
|
||||
@close="close"
|
||||
>
|
||||
<el-row style="margin-bottom: 10px;">
|
||||
<el-col :span="24" class="top">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
<el-form
|
||||
ref="formModel"
|
||||
:model="model"
|
||||
>
|
||||
<el-table
|
||||
:data="model.schemeArr"
|
||||
border
|
||||
max-height="400"
|
||||
highlight-current-row
|
||||
style="width: 100%"
|
||||
>
|
||||
|
||||
<el-table-column prop="curveName" align="center" label="曲线名称">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="'schemeArr.' + scope.$index +'.curveName'" :rules="rules.curveName" style="margin-left: 0;">
|
||||
<el-input v-model.trim="scope.row.curveName" maxlength="50" placeholder="请填写曲线名称" />
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="colType" align="center" label="类型">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="'schemeArr.' + scope.$index +'.colType'" :rules="rules.colType" style="margin-left: 0;">
|
||||
<el-select v-model="scope.row.colType" placeholder="请选择类型" @change="selectType(scope.$index,scope.row.colType)">
|
||||
<el-option
|
||||
v-for="item in colTypeOption"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="col" align="center" label="指标1">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="'schemeArr.' + scope.$index +'.col'" :rules="rules.col" style="margin-left: 0;">
|
||||
<el-input v-model.trim="scope.row.col" maxlength="50" placeholder="请填写指标1" />
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="anotherCol" align="center" label="指标2">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="'schemeArr.' + scope.$index +'.anotherCol'" style="margin-left: 0;">
|
||||
<el-input v-model.trim="scope.row.anotherCol" maxlength="50" :readonly="scope.row.disabled" placeholder="请填写指标2" />
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column prop="deviceType" align="center" label="设备类型">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="'schemeArr.' + scope.$index +'.deviceType'" :rules="rules.deviceType" style="margin-left: 0;">
|
||||
<el-select v-model="scope.row.deviceType" placeholder="请选择设备类型">
|
||||
<el-option
|
||||
v-for="item in planTestDeviceType"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
class="btn-delete-table-text"
|
||||
@click="handleDelete(scope.$index)"
|
||||
>删除</el-button>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="close">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="saveLoading" @click="save">
|
||||
确定
|
||||
</el-button>
|
||||
</span>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { AddPlanPoint } from '@/api/test-management'
|
||||
export default {
|
||||
props: {
|
||||
visiable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
shemeData: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
planId: {
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
stationId: null,
|
||||
formModel: [],
|
||||
model: { schemeArr: [{ curveName: null, colType: null, col: null, anotherCol: null, deviceType: null }] },
|
||||
secondDisable: false,
|
||||
saveLoading: false,
|
||||
rules: {
|
||||
col: [
|
||||
{ required: true, message: '请填写指标1', trigger: 'blur' }
|
||||
],
|
||||
curveName: [
|
||||
{ required: true, message: '请填写曲线名称', trigger: 'blur' }
|
||||
],
|
||||
colType: [
|
||||
{ required: true, message: '请选择类型', trigger: 'change' }
|
||||
],
|
||||
anotherCol: [
|
||||
{ required: true, message: '请填写指标2', trigger: 'blur' }
|
||||
],
|
||||
deviceType: [
|
||||
{ required: true, message: '请选择设备类型', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
colTypeOption() {
|
||||
return this.$store.getters.dicts['colType'] || []
|
||||
},
|
||||
planTestDeviceType() {
|
||||
return this.$store.getters.dicts['planTestDeviceType'] || []
|
||||
},
|
||||
currentStation() {
|
||||
return this.$store.getters.currentStation || undefined
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
visiable: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formModel.clearValidate()
|
||||
})
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
SchemeData: {
|
||||
handler(val) {
|
||||
this.model.schemeArr = val
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
currentStation: {
|
||||
handler(val) {
|
||||
if (val && val.id) {
|
||||
this.stationId = val.id
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
// this.visiable = false
|
||||
this.$emit('close')
|
||||
this.model.schemeArr = [{ curveName: null, colType: null, col: null, anotherCol: null, deviceType: null }]
|
||||
this.$refs.formModel.clearValidate()
|
||||
},
|
||||
async save() {
|
||||
this.$refs.formModel.validate(async(valid) => {
|
||||
if (valid) {
|
||||
this.saveLoading = true
|
||||
// console.log(this.model.schemeArr)
|
||||
try {
|
||||
this.model.schemeArr.forEach((item) => {
|
||||
item.planId = this.planId
|
||||
item.stationId = this.stationId
|
||||
})
|
||||
|
||||
await AddPlanPoint(this.model.schemeArr)
|
||||
this.$message.success('保存成功')
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
} finally {
|
||||
this.saveLoading = false
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.model.schemeArr.push({ curveName: null, colType: null, col: null, anotherCol: null, deviceType: null })
|
||||
},
|
||||
selectType(index, value) {
|
||||
if (value === '1') {
|
||||
this.model.schemeArr[index].disabled = true
|
||||
this.model.schemeArr[index].anotherCol = null
|
||||
} else {
|
||||
this.model.schemeArr[index].disabled = false
|
||||
}
|
||||
},
|
||||
handleDelete(index) {
|
||||
this.model.schemeArr.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.top{
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
256
src/components/StackChartDialog/components/chart.vue
Normal file
@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div class="charts">
|
||||
<Chart v-if="chartShow" :options="powerChart_options" :class-name="'chart'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
powerChart_options: {
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
}
|
||||
},
|
||||
name: [],
|
||||
seriesList: [],
|
||||
Arr: [
|
||||
|
||||
],
|
||||
unit: '',
|
||||
chartShow: false,
|
||||
unitArr: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler(value) {
|
||||
this.seriesList = []
|
||||
this.Arr = value
|
||||
if (value.length === 0) {
|
||||
this.powerChart_options = {
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.seriesList = []
|
||||
this.handler()
|
||||
// value.forEach((el) => {
|
||||
// if (el.staticCurveList.length === 0) {
|
||||
// this.handler()
|
||||
// // this.powerChart_options = {
|
||||
// // title: {
|
||||
// // text: '暂无数据',
|
||||
// // x: 'center',
|
||||
// // y: 'center',
|
||||
// // textStyle: {
|
||||
// // fontSize: 14,
|
||||
// // fontWeight: 'normal'
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// } else {
|
||||
// this.seriesList = []
|
||||
// this.handler()
|
||||
// }
|
||||
// })
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
isShow: {
|
||||
handler(value) {
|
||||
this.chartShow = value
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.handler()
|
||||
},
|
||||
|
||||
methods: {
|
||||
handler() {
|
||||
const self = this
|
||||
const dateArr = []
|
||||
const colNameArr = []
|
||||
const digitalArr = []
|
||||
this.unitArr = []
|
||||
for (let i = 0; i < this.Arr.length; i++) {
|
||||
this.unitArr.push(this.Arr[i].unit)
|
||||
if (this.Arr[i].deviceName) {
|
||||
colNameArr.push(this.Arr[i].deviceName + '——' + this.Arr[i].colName + '?' + this.Arr[i].srcId)
|
||||
} else {
|
||||
colNameArr.push(this.Arr[i].deviceName + this.Arr[i].colName + '?' + this.Arr[i].srcId)
|
||||
}
|
||||
dateArr[i] = []
|
||||
digitalArr[i] = []
|
||||
for (let j = 0; j < this.Arr[i].staticCurveList.length; j++) {
|
||||
dateArr[i][j] = this.Arr[i].staticCurveList[j].date
|
||||
digitalArr[i][j] = this.Arr[i].staticCurveList[j].digital
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 1; i <= this.Arr.length; i++) {
|
||||
this.seriesList.push({
|
||||
name: colNameArr[i - 1],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2
|
||||
},
|
||||
itemStyle: { normal: { label: { show: false }}},
|
||||
showSymbol: false,
|
||||
data: digitalArr[i - 1]
|
||||
}
|
||||
)
|
||||
}
|
||||
this.powerChart_options = {
|
||||
title: {
|
||||
top: 20,
|
||||
textStyle: {
|
||||
fontWeight: 'normal',
|
||||
fontSize: 16,
|
||||
color: '#F1F1F3'
|
||||
},
|
||||
left: '1%'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(0,0,0,0,)',
|
||||
borderColor: 'rgba(0,0,0,0,);',
|
||||
borderWidth: 0,
|
||||
textStyle: {
|
||||
width: 160,
|
||||
height: 250,
|
||||
lineHeight: 24,
|
||||
color: '#ffffff',
|
||||
fontSize: '14',
|
||||
fontFamily: 'SourceHanSansCN-Normal'
|
||||
},
|
||||
formatter: params => {
|
||||
// 获取xAxis data中的数据
|
||||
let dataStr = `<div><p style="font-weight:bold;margin:0 8px 15px;">${params[0].name}</p></div>`
|
||||
params.forEach((item, index) => {
|
||||
const seriesName = (item.seriesName.split('?')[0])
|
||||
const relVal = item.marker + seriesName + ' : '
|
||||
dataStr += `<div>
|
||||
<div style="margin: 0 8px;">
|
||||
<span>${relVal}</span>
|
||||
<span style="float:right;color:#00C8FF;margin-left:20px;">${item.data === null ? '' : `${item.data}` + (self.unitArr[item.componentIndex] ? self.unitArr[item.componentIndex] : '')}</span>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
const div = `<div style='border: 1px solid ;
|
||||
border-image: linear-gradient(130deg, #FFFFFF 0%, rgba(201,255,243,0.00) 22%, rgba(201,255,243,0.00) 75%, rgba(201,255,243,0.00) 80%, #FFFFFF 99%, #FFFFFF 99%) 1;
|
||||
box-shadow: inset 0px 2px 16px 0px rgba(0, 148, 255, 0.4);' >${dataStr}</div>`
|
||||
return div
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: colNameArr,
|
||||
top: 20,
|
||||
icon: 'rect',
|
||||
itemWidth: 14,
|
||||
itemHeight: 5,
|
||||
itemGap: 13,
|
||||
right: '4%',
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: '#F1F1F3'
|
||||
},
|
||||
formatter: function(params) {
|
||||
params = (params.split('?'))
|
||||
return params[0]
|
||||
}
|
||||
|
||||
},
|
||||
grid: {
|
||||
top: 100,
|
||||
left: '8%',
|
||||
right: '5%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLabel: {
|
||||
// interval: dateArr.length > 0 ? parseInt(dateArr[0].length / 10) : 0,
|
||||
// showMaxLabel: true,
|
||||
// showMinLabel: true,
|
||||
// formatter: (value, index) => {
|
||||
// const r = value.split(':')
|
||||
// r[1] = '00'
|
||||
// return r[0] + ':' + r[1]
|
||||
// }
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: { // lineStyle里面写y轴那一条线的样式
|
||||
color: '#123f63',
|
||||
width: 2 // 轴线的粗细 我写的是2 最小为0,值为0的时候线隐藏
|
||||
}
|
||||
},
|
||||
data: dateArr[0]
|
||||
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: ``,
|
||||
nameTextStyle: { // y轴上方单位的颜色
|
||||
color: '#fff'
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: { // lineStyle里面写y轴那一条线的样式
|
||||
color: '#123f63',
|
||||
width: 2 // 轴线的粗细 我写的是2 最小为0,值为0的时候线隐藏
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
series: this.seriesList,
|
||||
color: ['#FF0000', '#00FF00', '#0000FF', '#FFA500', '#FFFF00', '#FFC0CB', '#800080', '#008000', '#000000', '#FFFFFF']
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.charts {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// border: 1px solid #123f63;
|
||||
}
|
||||
</style>
|
||||
295
src/components/StackChartDialog/index.vue
Normal file
@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<div class="base-dialog">
|
||||
<el-dialog
|
||||
:append-to-body="false"
|
||||
center
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="visible"
|
||||
custom-class="saveAsDialog"
|
||||
>
|
||||
<div slot="title">
|
||||
<div class="new-dialog-header">{{ title }}</div>
|
||||
<el-row class="top-search">
|
||||
<el-col :span="24" class="serach-item" style="text-align: left;margin-top: 80px;">
|
||||
<!-- 时间区间
|
||||
<el-select v-model="timeInterval" style="margin-left: 10px;" placeholder="请选择时间区间" @change="changeTimeInterval">
|
||||
<el-option
|
||||
v-for="item in timeIntervalOption"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select> -->
|
||||
<el-date-picker
|
||||
v-model="dataTime"
|
||||
class="input-box"
|
||||
type="datetimerange"
|
||||
:picker-options="pickerOptionsStart"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="changeDate"
|
||||
/>
|
||||
<el-button
|
||||
style="margin-left: 10px;"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="on_refresh"
|
||||
>查询</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div>
|
||||
<!-- <img src="../../assets/images/dialog-left.png" alt="">
|
||||
<img src="../../assets/images/dialog-right.png" alt=""> -->
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 500px;">
|
||||
<Chart :is-show="activeName" :options="powerChart_options" :title="colName" />
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Chart from './components/chart.vue'
|
||||
import { GetStackHisData } from '@/api/surveillance/stack'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Chart
|
||||
},
|
||||
props: {
|
||||
title: { // 标题
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isShow: { // 弹窗是否展示
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: { // 弹窗宽度
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
cancelName: { // 取消按钮名称
|
||||
type: String,
|
||||
default: '取 消'
|
||||
},
|
||||
confirmName: { // 确定按钮名称
|
||||
type: String,
|
||||
default: '确 定'
|
||||
},
|
||||
isShowFooter: { // 是否自定底部
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
appendToBody: { // 是否将自身插入至 body 元素,有嵌套的弹窗时一定要设置
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
// 设备id
|
||||
srcId: {
|
||||
type: [Number, String],
|
||||
default: 0 || ''
|
||||
},
|
||||
// 设备字段
|
||||
col: {
|
||||
type: Array,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: []
|
||||
}
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: false,
|
||||
timeInterval: '',
|
||||
table_data: [],
|
||||
dataTime: null,
|
||||
powerChart_options: [],
|
||||
filters: {
|
||||
stationId: null,
|
||||
endTime: null,
|
||||
beginTime: null,
|
||||
mark: null
|
||||
},
|
||||
result1: null,
|
||||
result: null,
|
||||
// 当前页码
|
||||
pickerOptionsStart: {
|
||||
// 时间不能大于当前时间
|
||||
disabledDate: (time) => {
|
||||
return time.getTime() > Date.now()
|
||||
}
|
||||
},
|
||||
colName: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get() {
|
||||
return this.isShow
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:isShow', false)
|
||||
}
|
||||
},
|
||||
currentStation() {
|
||||
return this.$store.getters.currentStation || undefined
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible(val) { // 在此做显示与隐藏的交互
|
||||
if (val === false) {
|
||||
this.activeName = false
|
||||
// this.table_data = []
|
||||
// // this.dataTime = null
|
||||
// this.powerChart_options = []
|
||||
// this.filters.beginTime = this.result
|
||||
// this.filters.endTime = this.result1
|
||||
// this.dataTime = [this.result, this.result1]
|
||||
// // this.filters.endTime = null
|
||||
// // this.filters.beginTime = null
|
||||
// // 重置操作
|
||||
} else {
|
||||
const now = Date.now()
|
||||
const twentyFourHoursAgo = now - 24 * 60 * 60 * 1000
|
||||
const twentyFourHoursAgoDate = new Date(twentyFourHoursAgo)
|
||||
const year = twentyFourHoursAgoDate.getFullYear().toString().padStart(4, '0')
|
||||
const month = (twentyFourHoursAgoDate.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = twentyFourHoursAgoDate.getDate().toString().padStart(2, '0')
|
||||
const hour = twentyFourHoursAgoDate.getHours().toString().padStart(2, '0')
|
||||
const minute = twentyFourHoursAgoDate.getMinutes().toString().padStart(2, '0')
|
||||
const second = twentyFourHoursAgoDate.getSeconds().toString().padStart(2, '0')
|
||||
this.result = `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
||||
|
||||
const now1 = new Date()
|
||||
const year1 = now1.getFullYear()
|
||||
const month1 = (now1.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day1 = now1.getDate().toString().padStart(2, '0')
|
||||
const hour1 = now1.getHours().toString().padStart(2, '0')
|
||||
const minute1 = now1.getMinutes().toString().padStart(2, '0')
|
||||
const second1 = now1.getSeconds().toString().padStart(2, '0')
|
||||
this.result1 = `${year1}-${month1}-${day1} ${hour1}:${minute1}:${second1}`
|
||||
this.filters.beginTime = this.result
|
||||
this.filters.endTime = this.result1
|
||||
this.dataTime = [this.result, this.result1]
|
||||
const params = {
|
||||
beginTime: this.result,
|
||||
colName: this.col,
|
||||
srcId: this.srcId,
|
||||
endTime: this.result1,
|
||||
stationId: this.filters.stationId
|
||||
}
|
||||
// this.$forceUpdate()
|
||||
// this.getColHistoricalDetailsForTable()
|
||||
this.GetPointCurve(params)
|
||||
// // 展示时操作
|
||||
}
|
||||
},
|
||||
currentStation: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.filters.stationId = val.id
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
changeDate(val) {
|
||||
this.filters.beginTime = val[0]
|
||||
this.filters.endTime = val[1]
|
||||
},
|
||||
on_refresh() {
|
||||
const params = {
|
||||
beginTime: this.filters.beginTime,
|
||||
colName: this.col,
|
||||
srcId: this.srcId,
|
||||
endTime: this.filters.endTime,
|
||||
stationId: this.filters.stationId
|
||||
}
|
||||
this.GetPointCurve(params)
|
||||
},
|
||||
async GetPointCurve(params) {
|
||||
try {
|
||||
const res = await GetStackHisData(params)
|
||||
this.powerChart_options = res.data
|
||||
this.activeName = true
|
||||
if (res.data.length) {
|
||||
this.colName = res.data[0].deviceName + '————' + res.data[0].colName
|
||||
}
|
||||
} catch (error) {
|
||||
this.powerChart_options = []
|
||||
this.activeName = true
|
||||
this.$notify({
|
||||
title: '失败',
|
||||
message: '查询失败',
|
||||
type: 'warning',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.base-dialog{
|
||||
min-width: 300px;
|
||||
.top-search{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
// background: $card-background;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
|
||||
.serach-item {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #0094FF;
|
||||
color: $text-color;
|
||||
.input-box {
|
||||
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.charts {
|
||||
width: 100%;
|
||||
min-height: 450px;
|
||||
// // border: 1px solid #123f63;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .el-dialog__header{
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
|
||||
}
|
||||
.new-dialog-header{
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
162
src/components/StationTopology/index.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
require('echarts/theme/macarons') // echarts theme
|
||||
// import resize from './mixins/resize'
|
||||
|
||||
// const animationDuration = 6000
|
||||
import chunengdanyuan from '@/assets/images/chunengdanyuan.png'
|
||||
import dianchicu from '@/assets/images/dianchicu.png'
|
||||
import dianchidui from '@/assets/images/dianchidui.png'
|
||||
import pcs from '@/assets/images/wxjd/pcs-energy.png'
|
||||
import wenduyi from '@/assets/images/wenduyi.png'
|
||||
import xiaofang from '@/assets/images/xiaofang.png'
|
||||
import kongtiao from '@/assets/images/kongtiao.png'
|
||||
import dianbiao from '@/assets/images/wxjd/ammeter.png'
|
||||
export default {
|
||||
// mixins: [resize],
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
default: 'chart'
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '500px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chunengdanyuan,
|
||||
dianchicu,
|
||||
dianchidui,
|
||||
pcs,
|
||||
wenduyi,
|
||||
xiaofang,
|
||||
kongtiao,
|
||||
dianbiao,
|
||||
myChart: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.myChart) {
|
||||
return
|
||||
}
|
||||
this.myChart.dispose()
|
||||
this.myChart = null
|
||||
},
|
||||
methods: {
|
||||
initChart(chartData) {
|
||||
const self = this
|
||||
this.myChart = echarts.init(this.$el, 'macarons')
|
||||
this.setOptions(chartData)
|
||||
this.myChart.on('click', function(params, params1) {
|
||||
if (params.data && params.data.deviceType !== 'storage') {
|
||||
self.$router.push({
|
||||
name: 'standard-215-device-list',
|
||||
params: {
|
||||
node: params.data,
|
||||
from: 'energy-storage'
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
setOptions(chartData) {
|
||||
this.myChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove'
|
||||
},
|
||||
label: {
|
||||
// 每个节点的label
|
||||
|
||||
show: true
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'tree',
|
||||
orient: 'vertical',
|
||||
top: '12%',
|
||||
left: '5%',
|
||||
bottom: '10%',
|
||||
right: '5%',
|
||||
nodePadding: 100,
|
||||
edgeShape: 'curve',
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: '#1989fa'
|
||||
// type: "solid", // 'curve'|'broken'|'solid'|'dotted'|'dashed'
|
||||
},
|
||||
symbol: function(params, params1, params2) {
|
||||
let img = ''
|
||||
|
||||
if (params1.data.deviceType) {
|
||||
if (params1.data.deviceType === 'storage') {
|
||||
img = 'image://' + require('@/assets/images/chunengdanyuan.png')
|
||||
} else if (params1.data.deviceType.includes('bms')) {
|
||||
img = 'image://' + require('@/assets/images/dianchicu.png')
|
||||
} else if (params1.data.deviceType.includes('stack')) {
|
||||
img = 'image://' + require('@/assets/images/dianchicu.png')
|
||||
} else if (params1.data.deviceType.includes('pcs')) {
|
||||
img = 'image://' + require('@/assets/images/pcs.png')
|
||||
} else if (params1.data.deviceType.includes('transmitter')) {
|
||||
img = 'image://' + require('@/assets/images/wenduyi.png')
|
||||
} else if (params1.data.deviceType.includes('air_condition')) {
|
||||
img = 'image://' + require('@/assets/images/kongtiao.png')
|
||||
} else if (params1.data.deviceType.includes('storage_fire')) {
|
||||
img = 'image://' + require('@/assets/images/xiaofang.png')
|
||||
} else if (params1.data.deviceType.includes('ele_meter')) {
|
||||
img = 'image://' + require('@/assets/images/dianbiao.png')
|
||||
}
|
||||
}
|
||||
return img
|
||||
},
|
||||
symbolSize: function(params, params1, params2) {
|
||||
let imgSize = [60, 60]
|
||||
if (params1.data.deviceType) {
|
||||
if (params1.data.deviceType === 'storage') {
|
||||
imgSize = [60, 60]
|
||||
} else if (params1.data.deviceType.includes('bms')) {
|
||||
imgSize = [60, 60]
|
||||
} else if (params1.data.deviceType.includes('stack')) {
|
||||
imgSize = [60, 60]
|
||||
} else if (params1.data.deviceType.includes('pcs')) {
|
||||
imgSize = [60, 60]
|
||||
} else if (params1.data.deviceType.includes('transmitter')) {
|
||||
imgSize = [35, 35]
|
||||
} else if (params1.data.deviceType.includes('air_condition')) {
|
||||
imgSize = [40, 40]
|
||||
} else if (params1.data.deviceType.includes('storage_fire')) {
|
||||
imgSize = [35, 35]
|
||||
} else if (params1.data.deviceType.includes('ele_meter')) {
|
||||
imgSize = [40, 40]
|
||||
}
|
||||
}
|
||||
return imgSize
|
||||
}, // 图片大小
|
||||
label: {
|
||||
// 每个节点的label
|
||||
show: true,
|
||||
color: '#fff',
|
||||
rotate: -45,
|
||||
position: [10, 0]
|
||||
},
|
||||
data: chartData
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
62
src/components/SvgIcon/index.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover!important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
581
src/components/SwiperTable/index.vue
Normal file
@ -0,0 +1,581 @@
|
||||
<template>
|
||||
<div
|
||||
class="table-wrapper"
|
||||
:style="{
|
||||
width: 'calc(' + widths.reduce((i, j) => `${i} + ${j}`) + ` + ${(widths.length - 1) * 6}px)`,
|
||||
height: `calc(${contentHeight}px + 48px)`
|
||||
}"
|
||||
>
|
||||
<div v-if="showHeader" class="table-header">
|
||||
<span v-show="isSort" :style="{ width: '100px' }">{{ $t('monitoring.index') }}</span>
|
||||
<span v-for="(it, i) in titles" :key="i" :style="{ width: widths[i] === 'auto' ? 'auto' : widths[i] + 'px' }" :class="{'span-auto': widths[i] === 'auto'}">{{ titles[i] }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="table-content"
|
||||
:style="{height:contentHeight+'px'}"
|
||||
>
|
||||
<swiper v-if="data.length > 0" ref="myBotSwiper" class="swiper" :options="swiperOption">
|
||||
<swiper-slide v-for="(row, rowIndex) in data" :key="rowIndex">
|
||||
<div
|
||||
class="table-row"
|
||||
:class="{ stripe: rowIndex % 2 === 1, active: rowIndex === currentActiveRow }"
|
||||
:style="{ height: tabelHeight }"
|
||||
@click="handleRowClick(row, rowIndex)"
|
||||
>
|
||||
<span
|
||||
v-show="isSort"
|
||||
:style="{ width: '60px', height: tabelHeight }"
|
||||
>{{ rowIndex+1 }}</span>
|
||||
<span
|
||||
v-for="(column, columnIndex) in columns"
|
||||
:key="columnIndex"
|
||||
:title="row[columnIndex]"
|
||||
:style="{ width: widths[columnIndex] === 'auto' ? 'auto' : widths[columnIndex] + 'px', height: tabelHeight }"
|
||||
:class="{'span-auto': widths[columnIndex] === 'auto'}"
|
||||
>{{ row[column] }}</span>
|
||||
</div>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
<div v-if="data.length === 0" style="height:100%;text-align:center; margin-top:40px;font-size:14px;color:#999">
|
||||
{{ $t('dashboard.noData') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import 'swiper/dist/css/swiper.css'
|
||||
import { swiper, swiperSlide } from 'vue-awesome-swiper'
|
||||
export default {
|
||||
name: 'SwiperTable',
|
||||
components: {
|
||||
swiper,
|
||||
swiperSlide
|
||||
},
|
||||
props: {
|
||||
// 传入的表格数据
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
],
|
||||
[
|
||||
'杂草乱扔',
|
||||
'2020.08.23 12:26:15',
|
||||
'全要素网格化',
|
||||
'公安交警',
|
||||
'环境保护',
|
||||
'待受理',
|
||||
'李念省'
|
||||
]
|
||||
]
|
||||
},
|
||||
// 传入的表格头
|
||||
titles: {
|
||||
type: Array,
|
||||
default: () => ['事件标题', '创建时间', '信息来源', '分类', '状态', '上报人']
|
||||
},
|
||||
// 表格的列宽
|
||||
widths: {
|
||||
type: Array,
|
||||
default: () => ['246px', '348px', '224px', '214px', '214px', '214px']
|
||||
},
|
||||
// 表格的高度
|
||||
contentHeight: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
// 是否展示表格头
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isSort: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 表格的行高
|
||||
tabelHeight: {
|
||||
type: String,
|
||||
default: '32px'
|
||||
},
|
||||
// 字段
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => ['title', 'createTime', 'info', 'type', 'status', 'upper']
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentActiveRow: 0,
|
||||
swiperOption: {
|
||||
autoHeight: true,
|
||||
direction: 'vertical',
|
||||
spaceBetween: 0,
|
||||
autoplay: {
|
||||
delay: 2500,
|
||||
disableOnInteraction: false,
|
||||
autoplayDisableOnInteraction: false
|
||||
},
|
||||
slidesPerView: 'auto',
|
||||
grabCursor: true,
|
||||
autoplayDisableOnInteraction: false,
|
||||
mousewheelControl: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
myBotSwiper() {
|
||||
return this.$refs.myBotSwiper.$swiper
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler(val) {
|
||||
this.currentActiveRow = 0
|
||||
// if (val && val.length > 0) {
|
||||
// this.columns = []
|
||||
// for (const key in val[0]) {
|
||||
// this.columns.push(key)
|
||||
// }
|
||||
// // this.swiperStart()
|
||||
// }
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRowClick(it, i) {
|
||||
this.currentActiveRow = i
|
||||
const currentIt = this.data[i]
|
||||
this.$emit('change', currentIt)
|
||||
},
|
||||
// 控制表格停止滚动
|
||||
swiperStop() {
|
||||
this.myBotSwiper.autoplay.stop()
|
||||
},
|
||||
// 控制表格开始滚动
|
||||
swiperStart() {
|
||||
this.myBotSwiper.autoplay.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
span {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.table-header {
|
||||
$height: 32px;
|
||||
width: 100%;
|
||||
height: $height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: linear-gradient(0deg, #32AAFF -24.83%, rgba(50, 170, 255, 0.00) 100%);
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
// background: rgba(255, 255, 255, 0.12);
|
||||
// background-color: #013558;
|
||||
font-size: 14px;
|
||||
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
line-height: $height;
|
||||
&:nth-child(2) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
.span-auto {
|
||||
flex: 1;
|
||||
}
|
||||
span + span {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
width: 100%;
|
||||
margin-top: 2px;
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.table-row {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&.active {
|
||||
border: 2px solid rgba(0, 148, 255, 0.00);
|
||||
background: linear-gradient(90deg, rgba(0, 51, 81, 0.00) 0%, #003351 51.3%, rgba(0, 51, 81, 0.00) 100%);
|
||||
span {
|
||||
|
||||
color: #32AAFF;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&.stripe span {
|
||||
background: rgba(2, 74, 123, 0.2);
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
font-family: PingFangSC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
line-height: 36px;
|
||||
}
|
||||
.span-auto {
|
||||
flex: 1;
|
||||
}
|
||||
span + span {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 100%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 6px;
|
||||
&:nth-child(1) {
|
||||
width: 246px;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: 348px;
|
||||
padding-left: 13px;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
width: 214px;
|
||||
}
|
||||
&:nth-child(4) {
|
||||
width: 214px;
|
||||
}
|
||||
&:nth-child(5) {
|
||||
width: 214px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- <script>
|
||||
import 'swiper/dist/css/swiper.css'
|
||||
import { swiper, swiperSlide } from 'vue-awesome-swiper'
|
||||
export default {
|
||||
name: 'SwiperTable',
|
||||
components: {
|
||||
swiper,
|
||||
swiperSlide
|
||||
},
|
||||
props: {
|
||||
// 传入的表格数据
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 传入的表格头
|
||||
titles: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 表格的列宽
|
||||
widths: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 表格的高度
|
||||
contentHeight: {
|
||||
type: String,
|
||||
default: 'auto'
|
||||
},
|
||||
// 是否展示表格头
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 表格的行高
|
||||
tabelHeight: {
|
||||
type: String,
|
||||
default: '32px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentActiveRow: 0,
|
||||
columns: [],
|
||||
swiperOption: {
|
||||
autoHeight: true,
|
||||
direction: 'vertical',
|
||||
spaceBetween: 0,
|
||||
autoplay: {
|
||||
delay: 2500,
|
||||
disableOnInteraction: false,
|
||||
autoplayDisableOnInteraction: false
|
||||
},
|
||||
slidesPerView: 'auto',
|
||||
grabCursor: true,
|
||||
autoplayDisableOnInteraction: false,
|
||||
mousewheelControl: true
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler(val) {
|
||||
this.currentActiveRow = 0;
|
||||
if (val && val.length > 0) {
|
||||
this.columns = []
|
||||
for (const key in val[0]) {
|
||||
this.columns.push(key)
|
||||
}
|
||||
this.swiperStart()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleRowClick(it, i) {
|
||||
this.currentActiveRow = i;
|
||||
const currentIt = this.data[i];
|
||||
this.$emit('change', currentIt);
|
||||
},
|
||||
// 控制表格停止滚动
|
||||
swiperStop() {
|
||||
this.$refs.myBotSwiper.$swiper.autoplay.stop();
|
||||
},
|
||||
// 控制表格开始滚动
|
||||
swiperStart() {
|
||||
setTimeout(() => {
|
||||
this.$refs.myBotSwiper.swiper.autoplay.start();
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
span {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.table-header {
|
||||
$height: 31px;
|
||||
width: 100%;
|
||||
height: $height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
color: #83c2ee;
|
||||
// background: rgba(255, 255, 255, 0.12);
|
||||
background-color: #013558;
|
||||
font-size: 19px;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: rgba(131, 194, 238, 1);
|
||||
line-height: $height;
|
||||
&:nth-child(2) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.span-auto {
|
||||
flex: 1;
|
||||
}
|
||||
span + span {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 2px;
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.table-row {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&.active {
|
||||
span {
|
||||
color: rgba(131, 194, 238, 1);
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&.stripe span {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
span {
|
||||
font-size: 17px;
|
||||
font-family: PingFangSC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
line-height: 36px;
|
||||
}
|
||||
.span-auto {
|
||||
flex: 1;
|
||||
}
|
||||
span + span {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 100%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
}
|
||||
</style> -->
|
||||
59
src/components/TextModel/index.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div v-if="isModelShow" class="mark">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<i class="el-icon-loading" style="color: #fff; font-size: 100px" />
|
||||
<span class="title">{{ title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
isModelShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
percentage: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '正在生成中...'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
// const props = defineProps<{ visible: any;progress:any,title:any }>()
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
/* scoped 使用得定义的样式只在本页面内生效 */
|
||||
.mark {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 99;
|
||||
.title {
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
margin-top: 10px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
174
src/components/ThemePicker/index.vue
Normal file
@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<el-color-picker
|
||||
v-model="theme"
|
||||
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
|
||||
class="theme-picker"
|
||||
popper-class="theme-picker-dropdown"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const version = require('element-ui/package.json').version // element-ui version from node_modules
|
||||
const ORIGINAL_THEME = '#409EFF' // default color
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chalk: '', // content of theme-chalk css
|
||||
theme: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
defaultTheme() {
|
||||
return this.$store.state.settings.theme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultTheme: {
|
||||
handler: function(val, oldVal) {
|
||||
this.theme = val
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
async theme(val) {
|
||||
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
|
||||
if (typeof val !== 'string') return
|
||||
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
||||
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
||||
|
||||
const $message = this.$message({
|
||||
message: ' Compiling the theme',
|
||||
customClass: 'theme-message',
|
||||
type: 'success',
|
||||
duration: 0,
|
||||
iconClass: 'el-icon-loading'
|
||||
})
|
||||
|
||||
const getHandler = (variable, id) => {
|
||||
return () => {
|
||||
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
||||
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
|
||||
|
||||
let styleTag = document.getElementById(id)
|
||||
if (!styleTag) {
|
||||
styleTag = document.createElement('style')
|
||||
styleTag.setAttribute('id', id)
|
||||
document.head.appendChild(styleTag)
|
||||
}
|
||||
styleTag.innerText = newStyle
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.chalk) {
|
||||
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
|
||||
await this.getCSSString(url, 'chalk')
|
||||
}
|
||||
|
||||
const chalkHandler = getHandler('chalk', 'chalk-style')
|
||||
|
||||
chalkHandler()
|
||||
|
||||
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||
.filter(style => {
|
||||
const text = style.innerText
|
||||
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
|
||||
})
|
||||
styles.forEach(style => {
|
||||
const { innerText } = style
|
||||
if (typeof innerText !== 'string') return
|
||||
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
||||
})
|
||||
|
||||
this.$emit('change', val)
|
||||
|
||||
$message.close()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateStyle(style, oldCluster, newCluster) {
|
||||
let newStyle = style
|
||||
oldCluster.forEach((color, index) => {
|
||||
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
|
||||
})
|
||||
return newStyle
|
||||
},
|
||||
|
||||
getCSSString(url, variable) {
|
||||
return new Promise(resolve => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
xhr.open('GET', url)
|
||||
xhr.send()
|
||||
})
|
||||
},
|
||||
|
||||
getThemeCluster(theme) {
|
||||
const tintColor = (color, tint) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
if (tint === 0) { // when primary color is in its rgb space
|
||||
return [red, green, blue].join(',')
|
||||
} else {
|
||||
red += Math.round(tint * (255 - red))
|
||||
green += Math.round(tint * (255 - green))
|
||||
blue += Math.round(tint * (255 - blue))
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
}
|
||||
|
||||
const shadeColor = (color, shade) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
red = Math.round((1 - shade) * red)
|
||||
green = Math.round((1 - shade) * green)
|
||||
blue = Math.round((1 - shade) * blue)
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
|
||||
const clusters = [theme]
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
|
||||
}
|
||||
clusters.push(shadeColor(theme, 0.1))
|
||||
return clusters
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme-message,
|
||||
.theme-picker-dropdown {
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
.theme-picker .el-color-picker__trigger {
|
||||
height: 26px !important;
|
||||
width: 26px !important;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
155
src/components/TransferOrg/department/index.vue
Normal file
@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
title="组织列表"
|
||||
:visible.sync="visibleInChild"
|
||||
:height="600"
|
||||
width="400px"
|
||||
@close="departClose"
|
||||
>
|
||||
<div class="tree-container">
|
||||
<div class="tree-filter">
|
||||
<el-input v-model="filterText" placeholder="请输入过滤条件" />
|
||||
</div>
|
||||
<div class="tree-wrapper">
|
||||
<el-tree
|
||||
ref="_selectOrgTree"
|
||||
:data="treeData"
|
||||
node-key="id"
|
||||
:props="defaultProps"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
:default-checked-keys="checkedKeys"
|
||||
:filter-node-method="filterNode"
|
||||
class="selectOrgTree"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<span slot-scope="{ data }" class="custom-tree-node">
|
||||
<span> {{ data.title }}</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="departClose">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getDeptUse } from '@/api/system/org'
|
||||
export default {
|
||||
name: 'SelectOrg',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
treeChangedata: {
|
||||
type: Array,
|
||||
default: function(params) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterText: '',
|
||||
treeData: [],
|
||||
table_data: [],
|
||||
expandedKeys: [],
|
||||
checkedKeys: [],
|
||||
btn_del: false,
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'title',
|
||||
isLeaf: 'isLeaf',
|
||||
data: 'data'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleInChild: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs._selectOrgTree.filter(val)
|
||||
},
|
||||
treeChangedata: {
|
||||
handler(val) {
|
||||
this.treeData = val
|
||||
if (val.length > 0) {
|
||||
this.$nextTick(() => {
|
||||
for (var i = 0; i < this.$refs._selectOrgTree.store._getAllNodes().length; i++) {
|
||||
this.$refs._selectOrgTree.store._getAllNodes()[i].expanded = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTreeData()
|
||||
},
|
||||
methods: {
|
||||
departClose() {
|
||||
this.$emit('departClose')
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.title.indexOf(value) !== -1
|
||||
},
|
||||
async getTreeData() {
|
||||
const res = await getDeptUse()
|
||||
this.treeData = res.data
|
||||
if (this.treeData.length > 0) {
|
||||
this.$nextTick(() => {
|
||||
for (var i = 0; i < this.$refs._selectOrgTree.store._getAllNodes().length; i++) {
|
||||
this.$refs._selectOrgTree.store._getAllNodes()[i].expanded = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
handleNodeClick(data) {
|
||||
this.currentNode = data
|
||||
},
|
||||
confirm() {
|
||||
this.$emit('confirm', this.currentNode)
|
||||
this.departClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tree-container {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
.tree-filter{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tree-wrapper{
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 0 20px;
|
||||
}
|
||||
</style>
|
||||
159
src/components/TransferOrg/manager/index.vue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
title="负责人列表"
|
||||
:visible.sync="visibleInChild"
|
||||
:height="600"
|
||||
width="400px"
|
||||
@close="managerClose"
|
||||
>
|
||||
<div class="tree-container">
|
||||
<div class="tree-filter">
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
placeholder="请输入姓名过滤"
|
||||
/>
|
||||
</div>
|
||||
<div class="tree-wrapper">
|
||||
<el-table
|
||||
ref="_sysUserTable"
|
||||
:data="tableData"
|
||||
border
|
||||
fit
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
highlight-current-row
|
||||
height="360"
|
||||
style="width: 100%;"
|
||||
:cell-style="{padding:'3px'}"
|
||||
@current-change="rowClick"
|
||||
>
|
||||
<!-- <el-table-column label="工号" prop="id" align="center" /> -->
|
||||
<el-table-column label="姓名" prop="username" align="center" />
|
||||
<el-table-column label="所属机构" prop="deptName" align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="managerClose">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SelectOrg',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
managerList: {
|
||||
type: Array,
|
||||
default: function(params) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterText: '',
|
||||
currentRow: undefined,
|
||||
// 输入框搜索出来的值
|
||||
showTable: [],
|
||||
tableData: []
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleInChild: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 监听:如果为空,显示所有数据
|
||||
filterText(item1) {
|
||||
if (item1 === '') {
|
||||
this.tableData = this.showTable
|
||||
} else {
|
||||
this.search()
|
||||
}
|
||||
},
|
||||
managerList: {
|
||||
handler(val) {
|
||||
this.tableData = this.managerList
|
||||
this.showTable = this.managerList
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
// 页面渲染时,显示所有的数据
|
||||
created() {
|
||||
this.tableData = this.managerList
|
||||
this.showTable = this.managerList
|
||||
},
|
||||
methods: {
|
||||
managerClose() {
|
||||
this.filterText = ''
|
||||
this.$emit('managerClose')
|
||||
},
|
||||
rowClick(currentRow) {
|
||||
this.currentRow = currentRow
|
||||
},
|
||||
confirm() {
|
||||
this.filterText = ''
|
||||
this.$emit('confirm', this.currentRow)
|
||||
this.managerClose()
|
||||
},
|
||||
// 搜索内容
|
||||
search() {
|
||||
const Search_List = []
|
||||
const res1 = this.filterText
|
||||
const res = res1.replace(/\s/gi, '')
|
||||
const searchArr = this.showTable
|
||||
searchArr.forEach((e) => {
|
||||
// 绑定的table prop
|
||||
const name = e.username
|
||||
if (name.includes(res)) {
|
||||
if (Search_List.indexOf(e) === -1) {
|
||||
Search_List.push(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.tableData = Search_List
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tree-container {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
.tree-filter{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
.tree-wrapper{
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 0 20px;
|
||||
}
|
||||
</style>
|
||||
330
src/components/TransferOrg/user/index.vue
Normal file
@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
title="选择组织人员列表"
|
||||
:visible.sync="visibleInChild"
|
||||
width="75%"
|
||||
style="max-height:600px"
|
||||
:before-close="close"
|
||||
>
|
||||
<div class="el-dialog-body-custom-height">
|
||||
<div style="width: 100%;overflow: hidden">
|
||||
<el-row :gutter="5">
|
||||
<el-col :span="6">
|
||||
<div class="select_user_container">
|
||||
<div>
|
||||
<el-input v-model="filterText" placeholder="请输入过滤条件" />
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 375px; overflow: auto">
|
||||
<el-tree
|
||||
ref="_selectOrgTree"
|
||||
v-loading="userLoading"
|
||||
style="min-height: 300px"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
:data="treeData"
|
||||
node-key="id"
|
||||
:props="defaultProps"
|
||||
:filter-node-method="filterNode"
|
||||
class="filter-tree"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<span slot-scope="{ data }" class="custom-tree-node">
|
||||
<span>
|
||||
<span> {{ data.name }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div>
|
||||
<div class="select_user_container">
|
||||
<div class="user_title">人员列表</div>
|
||||
<div>
|
||||
<el-input
|
||||
v-model="listQuery.displayname"
|
||||
placeholder="姓名"
|
||||
@keyup.enter.native="btnQuery"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
ref="_sysUserTable"
|
||||
v-loading="userLoading"
|
||||
:data="records"
|
||||
border
|
||||
fit
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
highlight-current-row
|
||||
height="360"
|
||||
style="width: 100%;"
|
||||
:cell-style="{padding:'3px'}"
|
||||
@select="rowClick"
|
||||
@select-all="handelSelectAll"
|
||||
>
|
||||
<el-table-column v-if="multipleSelect" type="selection" align="center" width="50px" />
|
||||
<el-table-column label="工号" prop="workno" align="center" />
|
||||
<el-table-column label="姓名" prop="displayname" align="center" />
|
||||
<el-table-column label="所属机构" prop="departName" align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div>
|
||||
<div class="select_user_container">
|
||||
<div class="user_title">人员选中列表</div>
|
||||
</div>
|
||||
<el-table
|
||||
:data="selectedRecords"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
height="360"
|
||||
style="width: 100%;"
|
||||
:cell-style="{padding:'3px'}"
|
||||
>
|
||||
<el-table-column label="工号" prop="workno" align="center" />
|
||||
<el-table-column label="姓名" prop="displayname" align="center" />
|
||||
<el-table-column v-if="multipleSelect" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<i
|
||||
class="el-icon-delete el-icon--left"
|
||||
style="cursor:pointer"
|
||||
@click="btnRemove(row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="visibleInChild = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SelectUser',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
multipleSelect: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
userList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterText: '',
|
||||
treeData: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'text'
|
||||
},
|
||||
records: [],
|
||||
total: 0,
|
||||
appendToBody: true,
|
||||
userLoading: false,
|
||||
selectedRecords: [],
|
||||
listQuery: {
|
||||
userId: undefined,
|
||||
displayname: undefined,
|
||||
orgId: undefined
|
||||
},
|
||||
currOrgId: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleInChild: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('closeUserDialog', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs._selectOrgTree.filter(val)
|
||||
},
|
||||
userList: {
|
||||
handler: function(val, oldVal) {
|
||||
if (val.length !== 0) {
|
||||
this.selectedRecords = val
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.records = []
|
||||
this.selectedRecords = []
|
||||
this.getTreeData()
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.visibleInChild = false
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.name.indexOf(value) !== -1
|
||||
},
|
||||
getTreeData() {
|
||||
this.$http.get('/admin/org/tree').then(res => {
|
||||
this.treeData = res.data
|
||||
})
|
||||
},
|
||||
handleNodeClick(node) {
|
||||
this.currOrgId = node.id
|
||||
this.listQuery.displayname = ''
|
||||
this.listSysUsers()
|
||||
},
|
||||
listSysUsers() {
|
||||
const _this = this
|
||||
this.userLoading = true
|
||||
this.listQuery.orgId = this.currOrgId
|
||||
const para = {
|
||||
deptId: this.currOrgId,
|
||||
displayname: this.listQuery.displayname
|
||||
}
|
||||
this.$http.get('/admin/user/getListByDeptId', { params: para }).then(res => {
|
||||
this.userLoading = false
|
||||
this.records = res.data
|
||||
const arr = this.selectedRecords
|
||||
this.$nextTick(function() {
|
||||
if (arr) { // 判断有无数据
|
||||
_this.records.forEach(function(row) {
|
||||
const index = arr.findIndex(item => item.userId === row.userId)
|
||||
if (index !== -1) {
|
||||
_this.$refs._sysUserTable.toggleRowSelection(row)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
btnQuery() {
|
||||
this.listSysUsers()
|
||||
},
|
||||
btnReset() {
|
||||
this.currOrgId = ''
|
||||
this.listQuery = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
userId: undefined,
|
||||
userName: undefined,
|
||||
orgId: undefined
|
||||
}
|
||||
this.listSysUsers()
|
||||
},
|
||||
rowClick(selection, row) {
|
||||
if (!this.multipleSelect) {
|
||||
this.selectedRecords = []
|
||||
this.selectedRecords[0] = row
|
||||
} else {
|
||||
const arr = this.selectedRecords
|
||||
const index = arr.findIndex(item => item.userId === row.userId)
|
||||
if (index < 0) {
|
||||
arr.push(row)
|
||||
} else {
|
||||
arr.splice(index, 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
handelSelectAll(selection) {
|
||||
const arr = this.selectedRecords
|
||||
this.records.forEach(function(row) {
|
||||
const index = arr.findIndex(item => item.userId === row.userId)
|
||||
if (index < 0) {
|
||||
arr.push(row)
|
||||
} else {
|
||||
arr.splice(index, 1)
|
||||
}
|
||||
})
|
||||
},
|
||||
btnRemoveAll() {
|
||||
this.selectedRecords = []
|
||||
},
|
||||
btnRemove(row) {
|
||||
const _this = this
|
||||
const arr = this.selectedRecords
|
||||
const rows = []
|
||||
arr.splice(arr.findIndex(item => item.userId === row.userId), 1)
|
||||
this.$nextTick(function() {
|
||||
if (arr.length !== 0) { // 判断有无数据
|
||||
_this.records.forEach(function(row) {
|
||||
arr.forEach(function(item) {
|
||||
if (item.userId === row.userId) {
|
||||
rows.push(row)
|
||||
}
|
||||
})
|
||||
})
|
||||
if (rows.length > 0) {
|
||||
_this.$refs._sysUserTable.clearSelection()
|
||||
rows.forEach(function(v) {
|
||||
_this.$refs._sysUserTable.toggleRowSelection(v, true)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
_this.$refs._sysUserTable.clearSelection()
|
||||
}
|
||||
})
|
||||
},
|
||||
confirm() {
|
||||
if (!this.selectedRecords || this.selectedRecords.length === 0) {
|
||||
this.$message.error('请先选择用户')
|
||||
return
|
||||
}
|
||||
if (this.multipleSelect) {
|
||||
this.$emit('selectUserFinished', this.selectedRecords)
|
||||
} else {
|
||||
this.$emit('selectUserFinished', this.selectedRecords[0])
|
||||
}
|
||||
this.selectedRecords = []
|
||||
this.records = []
|
||||
this.visibleInChild = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.select_user_container {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.select_user_container div:nth-child(1) {
|
||||
flex: 1;
|
||||
justify-items: left;
|
||||
}
|
||||
|
||||
.select_user_container div:nth-child(2) {
|
||||
flex: 1;
|
||||
justify-items: right;
|
||||
}
|
||||
|
||||
.user_title {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
259
src/components/Tree/index.vue
Normal file
@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<div class="tree-container">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
:indent="0"
|
||||
:data="treeData"
|
||||
default-expand-all
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
:check-on-click-node="true"
|
||||
:check-strictly="true"
|
||||
:current-node-key="currentNode"
|
||||
@node-click="handleTreeCheck"
|
||||
>
|
||||
<span slot-scope="{ node }" class="custom-tree-node">
|
||||
<span>
|
||||
<i class="el-icon-s-platform" style="color: #02e9ae" />{{ node.label }}
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
defaultProps: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
}
|
||||
}
|
||||
},
|
||||
treeData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentNode: undefined
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
treeData: {
|
||||
handler(val) {
|
||||
if (val.length > 0) {
|
||||
this.$nextTick(() => {
|
||||
if (this.type === 'pvinverter') {
|
||||
this.currentNode = val[0].children !== undefined && val[0].children.length > 0 ? val[0].children[0].id : val[0].id
|
||||
this.$emit('handleTreeCheck', val[0].children !== undefined && val[0].children.length > 0 ? val[0].children[0] : val[0])
|
||||
this.$refs.tree.setCurrentKey(this.currentNode)
|
||||
} else {
|
||||
this.currentNode = val[0].id
|
||||
this.$emit('handleTreeCheck', val[0])
|
||||
this.$refs.tree.setCurrentKey(this.currentNode)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
filterNode(val) {
|
||||
this.currentNode = val.id
|
||||
this.$emit('filterNode', val)
|
||||
},
|
||||
handleTreeCheck(val) {
|
||||
this.$emit('handleTreeCheck', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tree-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.tree-container /deep/ .el-tree-node__expand-icon.expanded {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
margin-top: 10px;
|
||||
padding-bottom: 40px;
|
||||
|
||||
.tree-box {
|
||||
width: 100%;
|
||||
height: calc(100% - 40px);
|
||||
overflow: auto;
|
||||
}
|
||||
.iconfont {
|
||||
color: aquamarine;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.tree-container /deep/ .el-icon-caret-right:before {
|
||||
content: "\e791";
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node__expand-icon {
|
||||
margin-left: 15px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node__expand-icon.is-leaf {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node {
|
||||
position: relative;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node__children {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree > .el-tree-node:before {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree > .el-tree-node:after {
|
||||
border-top: none;
|
||||
}
|
||||
.tree-container /deep/ .el-tree > .el-tree-node:before {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree > .el-tree-node:after {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node:before {
|
||||
content: "";
|
||||
left: 7px;
|
||||
position: absolute;
|
||||
right: auto;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node:after {
|
||||
content: "";
|
||||
left: 10px;
|
||||
position: absolute;
|
||||
right: auto;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node:before {
|
||||
border-left: 1px dashed rgba(126, 147, 166, 0.5);
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node:after {
|
||||
border-top: 1px dashed rgba(126, 147, 166, 0.5);
|
||||
height: 25px;
|
||||
top: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.el-tree-node :last-child:before {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree .el-tree-node {
|
||||
position: relative;
|
||||
}
|
||||
.tree-container /deep/ .el-tree-node .el-tree-node__content {
|
||||
height: 40px;
|
||||
padding-left: 18px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.tree-container /deep/ .el-tree-node .el-tree-node__content::before {
|
||||
border-left: 1px dashed rgba(126, 147, 166, 0.5);
|
||||
height: 100%;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
margin-left: 1px;
|
||||
margin-top: 0px;
|
||||
z-index: 8;
|
||||
}
|
||||
.tree-container
|
||||
/deep/
|
||||
.el-tree-node
|
||||
.el-tree-node__children
|
||||
.el-tree-node__content::before {
|
||||
border-left: 0px solid #e6e6e6;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
margin-left: 1px;
|
||||
margin-top: 0px;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.tree-container /deep/ .el-tree-node .el-tree-node__content::after {
|
||||
border-top: 1px dashed rgba(126, 147, 166, 0.5);
|
||||
height: 1px;
|
||||
top: 18px;
|
||||
width: 13px;
|
||||
margin-left: 1px;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.tree-container
|
||||
/deep/
|
||||
.el-tree-node
|
||||
.el-tree-node__children
|
||||
.el-tree-node__content::after {
|
||||
border-top: 0px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.tree-container .el-tree-node .el-tree-node__content::before,
|
||||
.tree-container .el-tree-node .el-tree-node__content::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: auto;
|
||||
}
|
||||
.tree-container {
|
||||
/deep/ .el-tree-node.is-current > .el-tree-node__content {
|
||||
background:#0b435f;
|
||||
color:#fff;
|
||||
/deep/ .el-tree-node__expand-icon {
|
||||
color: #fff;
|
||||
}
|
||||
/deep/ .is-leaf {
|
||||
color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
/deep/ .el-tree .is-current{
|
||||
background: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
246
src/components/TreeDialog/index.vue
Normal file
@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="title"
|
||||
:visible.sync="visibleInChild"
|
||||
:height="600"
|
||||
|
||||
width="400px"
|
||||
@close="departClose"
|
||||
>
|
||||
<div class="tree-container">
|
||||
<div class="tree-filter">
|
||||
<el-input v-model="filterText" :placeholder="$t('alarm.filterWord')" />
|
||||
</div>
|
||||
<div v-if="multiple" class="check-box">
|
||||
<el-checkbox v-model="allSelectStatus" @change="handleSelectAll">{{ $t('alarm.selectAllNone') }}</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="tree-wrapper">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
:data="treeData"
|
||||
:node-key="treeProps.id"
|
||||
:props="treeProps"
|
||||
default-expand-all
|
||||
:check-strictly="checkStrictly"
|
||||
:show-checkbox="multiple"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
:default-checked-keys="checkedKeys"
|
||||
:filter-node-method="filterNode"
|
||||
:expand-on-click-node="true"
|
||||
class="selectOrgTree"
|
||||
@node-click="handleNodeClick"
|
||||
@check-change="checkNodeClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="departClose">{{ $t('alarm.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ $t('alarm.sure') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SelectOrg',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
treeChangedata: {
|
||||
type: Array,
|
||||
default: function(params) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
treeProps: {
|
||||
type: Object,
|
||||
default: function(params) {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
checkStrictly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterText: '',
|
||||
treeData: [],
|
||||
table_data: [],
|
||||
expandedKeys: [],
|
||||
checkedKeys: [],
|
||||
btn_del: false,
|
||||
currentNode: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
},
|
||||
oldValue: [],
|
||||
allSelectStatus: false,
|
||||
levelData: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleInChild: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val)
|
||||
},
|
||||
treeChangedata: {
|
||||
handler(val) {
|
||||
this.treeData = val
|
||||
this.getLevelData()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
visibleInChild: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.oldValue = this.currentNode
|
||||
if (this.multiple) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCheckedKeys(this.oldValue)
|
||||
})
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(this.oldValue)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.getTreeData()
|
||||
},
|
||||
methods: {
|
||||
departClose() {
|
||||
this.filterText = ''
|
||||
this.$emit('close')
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) {
|
||||
return true
|
||||
} else {
|
||||
return `${data[this.defaultProps.label]}`.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
||||
}
|
||||
},
|
||||
|
||||
handleNodeClick(data) {
|
||||
|
||||
},
|
||||
checkNodeClick(data) {
|
||||
// 获取勾选的数据
|
||||
const checkNode = this.$refs.tree.getCheckedKeys()
|
||||
|
||||
if (checkNode.length === this.levelData.length) {
|
||||
this.allSelectStatus = true
|
||||
} else {
|
||||
this.allSelectStatus = false
|
||||
}
|
||||
},
|
||||
confirm() {
|
||||
if (this.multiple) {
|
||||
let newCurrentNode = []
|
||||
newCurrentNode = this.$refs.tree.getCheckedKeys()
|
||||
this.currentNode = newCurrentNode
|
||||
const Arr = this.$refs.tree.getCheckedNodes()
|
||||
let name = ''
|
||||
|
||||
Arr.forEach((el, index) => {
|
||||
if (index !== Arr.length - 1) {
|
||||
name += el.name + ','
|
||||
} else {
|
||||
name += el.name
|
||||
}
|
||||
})
|
||||
this.$emit('confirm', this.currentNode, name)
|
||||
this.departClose()
|
||||
} else {
|
||||
let newCurrentNode2 = []
|
||||
newCurrentNode2 = this.$refs.tree.getCurrentKey()
|
||||
this.currentNode = newCurrentNode2
|
||||
const name = this.$refs.tree.getCurrentNode().name
|
||||
this.$emit('confirm', this.currentNode, name)
|
||||
this.departClose()
|
||||
}
|
||||
},
|
||||
handleSelectAll() { // 全选
|
||||
if (this.allSelectStatus) { // 全选
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCheckedNodes(this.levelData)
|
||||
})
|
||||
} else { // 不全选
|
||||
this.$refs.tree.setCheckedKeys([])
|
||||
}
|
||||
},
|
||||
// 获取拉平后的数据
|
||||
getLevelData() {
|
||||
const cloneData = JSON.parse(JSON.stringify(this.treeData))
|
||||
this.levelData = this.recursion(cloneData).filter(item => item.category !== 1 && item.category !== 2)
|
||||
},
|
||||
// 递归调用
|
||||
recursion(arr) {
|
||||
return [].concat(
|
||||
...arr.map((item) => {
|
||||
if (item.children) {
|
||||
const arr = [].concat(item, ...this.recursion(item.children))
|
||||
delete item.children
|
||||
return arr
|
||||
}
|
||||
return [].concat(item)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tree-container {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
.tree-filter{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tree-wrapper{
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 0 20px;
|
||||
}
|
||||
.check-box{
|
||||
width:100%;
|
||||
}
|
||||
</style>
|
||||
111
src/components/WebtopoEditor/assets/css/svgAnimation/index.css
Normal file
@ -0,0 +1,111 @@
|
||||
/* 正向流动效果 */
|
||||
.svg_ani_flow {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
animation: ani_flow 10s linear infinite;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation: ani_flow 10s linear infinite;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes ani_flow {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 13, 5;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ani_flow {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 13, 5;
|
||||
}
|
||||
}
|
||||
|
||||
/* 停止流动效果 */
|
||||
.svg_ani_flow_stop {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
animation: ani_flow_stop 10s linear infinite;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation: ani_flow_stop 10s linear infinite;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes ani_flow_stop {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ani_flow_stop {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
}
|
||||
/* 反向流动效果 */
|
||||
.svg_ani_flow_back {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
animation: ani_flow_back 10s linear infinite;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation: ani_flow_back 10s linear infinite;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes ani_flow_back {
|
||||
from {
|
||||
stroke-dasharray: 13, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ani_flow_stop {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
}
|
||||
/* 以最大40高度填充 */
|
||||
.svg_ani_fill_h40 {
|
||||
animation: ani_fill_h40 5s linear infinite;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation: ani_fill_h40 5s linear infinite;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes ani_fill_h40 {
|
||||
from {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
to {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ani_flow_stop {
|
||||
from {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
|
||||
to {
|
||||
stroke-dasharray: 10, 5;
|
||||
}
|
||||
}
|
||||
BIN
src/components/WebtopoEditor/assets/svg/AlternatorSvg.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ArrowDownSvg.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ArrowUpSvg.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ChemicalFeederSvg.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/components/WebtopoEditor/assets/svg/CircuitBreakerSvg.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
BIN
src/components/WebtopoEditor/assets/svg/CoolingTowerSvg.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/components/WebtopoEditor/assets/svg/DoubleWindingSvg.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/components/WebtopoEditor/assets/svg/DoubleWindingSvgB.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ECharts_BasicBar.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ECharts_PieSvg.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
src/components/WebtopoEditor/assets/svg/GGJSvg.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
src/components/WebtopoEditor/assets/svg/GroundGraySvg.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/components/WebtopoEditor/assets/svg/IsolatingSwitchSvg.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/LightningArresterSvg.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/components/WebtopoEditor/assets/svg/Pipeline_H_Svg.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/Pipeline_V_Svg.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/PolylineSvg.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
src/components/WebtopoEditor/assets/svg/RectSvg.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/components/WebtopoEditor/assets/svg/RectangleSvg.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/ReservoirSvg.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/components/WebtopoEditor/assets/svg/RightAnglePipeSvg.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/SignalLampSvg.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
src/components/WebtopoEditor/assets/svg/StandardCapacitorSvg.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/components/WebtopoEditor/assets/svg/StandardReactanceSvg.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
src/components/WebtopoEditor/assets/svg/TextSvg.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
BIN
src/components/WebtopoEditor/assets/svg/TransformerYSvg.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/components/WebtopoEditor/assets/svg/TwoCircleSvg.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
src/components/WebtopoEditor/assets/svg/VerticalLineSvg.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
src/components/WebtopoEditor/assets/svg/WaterPipeValveSvg.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/components/WebtopoEditor/assets/svg/WireBreakSvg.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/components/WebtopoEditor/assets/svg/test.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
998
src/components/WebtopoEditor/assets/temp/InterfaceReturn.json
Normal file
@ -0,0 +1,998 @@
|
||||
[
|
||||
{
|
||||
"type": "AlternatorSvg",
|
||||
"title": "发电机",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"50\" cy=\"50\" rx=\"35\" ry=\"35\" fill=\"none\" :stroke=\"prop_data.extend_attr.stroke_color_a.val\" :stroke-width=\"prop_data.extend_attr.stroke_width_a.val\" :transform=\"prop_data.extend_attr.transform_a.val\"></ellipse><path d=\"M30,50 C30,44 34,40 40,40 46,40 50,44 50,50 M50,50 C50,56 54,60 60,60 66,60 70,56 70,50 \" fill=\"none\" :stroke=\"prop_data.extend_attr.stroke_color_b.val\" :stroke-width=\"prop_data.extend_attr.stroke_width_b.val\" :transform=\"prop_data.extend_attr.transform_b.val\"></path></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"stroke_color_a": {
|
||||
"title": "外轮廓颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"stroke_color_b": {
|
||||
"title": "内轮廓颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"stroke_width_a": {
|
||||
"title": "外轮廓厚度",
|
||||
"val": 2,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"stroke_width_b": {
|
||||
"title": "内轮廓厚度",
|
||||
"val": 2,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"transform_a": {
|
||||
"title": "外中心点坐标",
|
||||
"val": "translate(-50,-50)",
|
||||
"type": "textinputbox"
|
||||
},
|
||||
"transform_b": {
|
||||
"title": "内中心点坐标",
|
||||
"val": "translate(-50,-50)",
|
||||
"type": "textinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/AlternatorSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ArrowDownSvg",
|
||||
"title": "箭头向下",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><polygon points=\"0,-8 5,0 10,-8\" :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-5,0)\"></polygon></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/ArrowDownSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ArrowUpSvg",
|
||||
"title": "箭头向上",
|
||||
"panel_class": "common",
|
||||
"template": "<polygon points=\"0,8 5,0 10,8\" :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-5,0)\"></polygon>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/ArrowUpSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "CircuitBreakerSvg",
|
||||
"title": "断路器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><rect x=\"0\" y=\"0\" width=\"20\" height=\"40\" :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" stroke-width=\"2\" transform=\"translate(-10,-20)\"></rect></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"switch": {
|
||||
"title": "类型",
|
||||
"val": {
|
||||
"selectval": "{\"fill\":\"#FF0000\"}",
|
||||
"ridiogroup": [
|
||||
{
|
||||
"value": "{\"fill\":\"#FF0000\"}",
|
||||
"label": "断开"
|
||||
},
|
||||
{
|
||||
"value": "{\"fill\":\"#00FF00\"}",
|
||||
"label": "连接"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "radiogroup"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/CircuitBreakerSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "DoubleWindingSvg",
|
||||
"title": "双绕组变压器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"0\" cy=\"-20\" rx=\"25\" ry=\"25\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></ellipse> <ellipse cx=\"0\" cy=\"20\" rx=\"25\" ry=\"25\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></ellipse> <polygon points=\"10,-30 0,-10 -10,-30\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></polygon> <line x1=\"0\" y1=\"20\" x2=\"0\" y2=\"35\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"20\" x2=\"-10\" y2=\"10\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"20\" x2=\"10\" y2=\"10\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/DoubleWindingSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "GGJSvg",
|
||||
"title": "电容柜",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><line x1=\"0.5\" y1=\"-25\" x2=\"-9.5\" y2=\"-13\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <line x1=\"0.5\" y1=\"-26\" x2=\"9.5\" y2=\"-13\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <line x1=\"-12\" y1=\"-17\" x2=\"-6\" y2=\"-8\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-15\" y1=\"-12\" x2=\"-9\" y2=\"-3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <polyline points=\"-13,-8 -22,3 -22,5\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></polyline> <line x1=\"-21\" y1=\"4\" x2=\"-4\" y2=\"4\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <line x1=\"-5\" y1=\"-2\" x2=\"-5\" y2=\"11\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <line x1=\"3\" y1=\"-2\" x2=\"3\" y2=\"11\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <line x1=\"4\" y1=\"4\" x2=\"21\" y2=\"4\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></line> <polyline points=\"13,-8 22,3 22,5\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" ></polyline> <line x1=\"14\" y1=\"-12\" x2=\"8\" y2=\"-3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"12\" y1=\"-17\" x2=\"6\" y2=\"-8\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/GGJSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "GroundGraySvg",
|
||||
"title": "接地灰白",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-9,-6)\"></line> <line x1=\"0\" y1=\"9\" x2=\"18\" y2=\"9\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-9,-6)\"></line> <line x1=\"3\" y1=\"15\" x2=\"15\" y2=\"15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-9,-6)\"></line> <line x1=\"6\" y1=\"21\" x2=\"12\" y2=\"21\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-9,-6)\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#CCCCCC",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/GroundGraySvg.png"
|
||||
},
|
||||
{
|
||||
"type": "IsolatingSwitchSvg",
|
||||
"title": "隔离开关",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><line x1=\"0\" y1=\"-20\" x2=\"0\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-10\" y1=\"0\" x2=\"6\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"20\" x2=\"-10\" y2=\"5\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"40\" x2=\"0\" y2=\"20\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment> ",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/IsolatingSwitchSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "LightningArresterSvg",
|
||||
"title": "避雷器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><rect x=\"-7\" y=\"-14\" width=\"15\" height=\"35\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></rect> <line x1=\"0\" y1=\"-21\" x2=\"0\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"21\" x2=\"0\" y2=\"28\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <polyline points=\"-1,-7 0,0 1,-7\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></polyline></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/LightningArresterSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "PolylineSvg",
|
||||
"title": "多段折线",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><polyline points=\"0,7 13,-7 26,7\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-13,0)\"></polyline> <polyline points=\"0,7 13,-7 26,7\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-13,8)\"></polyline></fragment> ",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/PolylineSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "RectSvg",
|
||||
"title": "长方形",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><rect x=\"-5\" y=\"-15\" width=\"10\" height=\"30\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" stroke-linecap=\"round\"></rect></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/RectSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "SignalLampSvg",
|
||||
"title": "信号灯",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"7\" cy=\"22\" rx=\"12\" ry=\"12\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-7,-22)\"></ellipse> <line x1=\"0\" y1=\"30\" x2=\"15\" y2=\"15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-7,-22)\"></line> <line x1=\"15\" y1=\"30\" x2=\"0\" y2=\"15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-7,-22)\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/SignalLampSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "StandardCapacitorSvg",
|
||||
"title": "标准电容器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><line x1=\"0\" y1=\"-12\" x2=\"0\" y2=\"-3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-9\" y1=\"-3\" x2=\"9\" y2=\"-3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-9\" y1=\"3\" x2=\"9\" y2=\"3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"12\" x2=\"0\" y2=\"3\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/StandardCapacitorSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "StandardReactanceSvg",
|
||||
"title": "标准电抗",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><path d=\"M18,63 V36 H33 C33,42 27,51 18,51 9,51 3,42 3,36 3,27 9,21 18,21 V6 V21\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" transform=\"translate(-18,-36)\"></path></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/StandardReactanceSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "TextSvg",
|
||||
"title": "文字",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><text x=\"0\" y=\"0\" :font-family=\"prop_data.extend_attr.font_family.val.selectval\" :font-size=\"prop_data.extend_attr.font_size.val\" :fill=\"prop_data.extend_attr.color.val\">{{prop_data.extend_attr.text.val}}</text></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "文字颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"font_size": {
|
||||
"title": "字体大小",
|
||||
"val": 15,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"font_family": {
|
||||
"title": "字体样式",
|
||||
"val": {
|
||||
"selectval": "Microsoft YaHei",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "Microsoft YaHei",
|
||||
"label": "微软雅黑"
|
||||
},
|
||||
{
|
||||
"value": "NSimSun",
|
||||
"label": "新宋体"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
},
|
||||
"text": {
|
||||
"title": "文字内容",
|
||||
"val": "文字",
|
||||
"type": "textinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/TextSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "TransformerTriphaseOpenSvg",
|
||||
"title": "三相互感器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"0\" cy=\"0\" rx=\"10\" ry=\"10\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></ellipse> <line x1=\"-2\" y1=\"-6\" x2=\"-2\" y2=\"6\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-2\" y1=\"-6\" x2=\"4\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"4\" y1=\"2\" x2=\"-2\" y2=\"6\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/TransformerTriphaseOpenSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "TransformerYSvg",
|
||||
"title": "电流互感器Y",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"0\" cy=\"0\" rx=\"10\" ry=\"10\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></ellipse> <line x1=\"5\" y1=\"-5\" x2=\"0\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"-5\" y1=\"-5\" x2=\"0\" y2=\"0\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"5\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/TransformerYSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "TwoCircleSvg",
|
||||
"title": "双圆",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"0\" cy=\"-4.5\" rx=\"6\" ry=\"6\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></ellipse> <ellipse cx=\"0\" cy=\"4.5\" rx=\"6\" ry=\"6\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></ellipse></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/TwoCircleSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "WireBreakSvg",
|
||||
"title": "电线开关",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><line x1=\"0\" y1=\"-40\" x2=\"0\" y2=\"-15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"15\" :x2=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).x2\" y2=\"-15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line> <line x1=\"0\" y1=\"45\" x2=\"0\" y2=\"15\" fill=\"none\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"switch": {
|
||||
"title": "类型",
|
||||
"val": {
|
||||
"selectval": "{\"x2\":-10}",
|
||||
"ridiogroup": [
|
||||
{
|
||||
"value": "{\"x2\":-10}",
|
||||
"label": "断开"
|
||||
},
|
||||
{
|
||||
"value": "{\"x2\":0}",
|
||||
"label": "连接"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "radiogroup"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/WireBreakSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ConnLineSvg",
|
||||
"title": "连接线",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line :x1=\"prop_data.extend_attr.startpoint_x.val\" :y1=\"prop_data.extend_attr.startpoint_y.val\" :x2=\"prop_data.extend_attr.endpoint_x.val\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_x": {
|
||||
"title": "起点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"startpoint_y": {
|
||||
"title": "起点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_x": {
|
||||
"title": "终点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_y": {
|
||||
"title": "终点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "电流效果",
|
||||
"val": {
|
||||
"selectval": "",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "draw",
|
||||
"priview_img": "/VerticalLineSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ConnHorizontalLineSvg",
|
||||
"title": "连接线-横线",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line :x1=\"prop_data.extend_attr.startpoint_x.val\" y1=\"0\" :x2=\"prop_data.extend_attr.endpoint_x.val\" y2=\"0\" :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_x": {
|
||||
"title": "起点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_x": {
|
||||
"title": "终点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "电流效果",
|
||||
"val": {
|
||||
"selectval": "",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "click",
|
||||
"priview_img": "/ConnHorizontalLineSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ConnVerticalLineSvg",
|
||||
"title": "连接线-竖线",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line x1=\"0\" :y1=\"prop_data.extend_attr.startpoint_y.val\" x2=\"0\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"2\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_y": {
|
||||
"title": "起点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_y": {
|
||||
"title": "终点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "电流效果",
|
||||
"val": {
|
||||
"selectval": "",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "click",
|
||||
"priview_img": "/VerticalLineSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "TestAddSvg",
|
||||
"title": "测试新增心形",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><path :fill=\"prop_data.extend_attr.color.val\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"5\" style=\"pointer-events:inherit\" d=\"m143.72081869586242,163.35565803158485 c14.617751633754164,-41.93617271978648 71.89058180534832,0 0,53.91793635401125 c-71.89058180534832,-53.91793635401125 -14.617751633754164,-95.85410907379776 0,-53.91793635401125 z\" fill-opacity=\"1\" stroke-opacity=\"1\" transform=\"translate(-145,-180)\"></path></fragment> ",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "心形颜色",
|
||||
"val": "#FF0000",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "http://svg.yaolm.top/test.png"
|
||||
},
|
||||
{
|
||||
"type": "PipelineSvg",
|
||||
"title": "管道",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line :x1=\"prop_data.extend_attr.startpoint_x.val\" :y1=\"prop_data.extend_attr.startpoint_y.val\" :x2=\"prop_data.extend_attr.endpoint_x.val\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :stroke=\"prop_data.extend_attr.o_color.val\" :stroke-width=\"prop_data.extend_attr.o_width.val\"></line><line :x1=\"prop_data.extend_attr.startpoint_x.val\" :y1=\"prop_data.extend_attr.startpoint_y.val\" :x2=\"prop_data.extend_attr.endpoint_x.val\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :stroke=\"prop_data.extend_attr.i_color.val\" :stroke-width=\"prop_data.extend_attr.i_width.val\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"o_color": {
|
||||
"title": "管道颜色",
|
||||
"val": "#0a7ae2",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"i_color": {
|
||||
"title": "水流颜色",
|
||||
"val": "#119bfa",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_x": {
|
||||
"title": "起点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"startpoint_y": {
|
||||
"title": "起点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_x": {
|
||||
"title": "终点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_y": {
|
||||
"title": "终点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"o_width": {
|
||||
"title": "管道宽度",
|
||||
"val": 10,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"i_width": {
|
||||
"title": "水流宽度",
|
||||
"val": 5,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "水流效果",
|
||||
"val": {
|
||||
"selectval": "svg_ani_flow",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "draw",
|
||||
"priview_img": "/Pipeline_V_Svg.png"
|
||||
},
|
||||
{
|
||||
"type": "Pipeline_H_Svg",
|
||||
"title": "管道-横向",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line :x1=\"prop_data.extend_attr.startpoint_x.val\" :y1=\"0\" :x2=\"prop_data.extend_attr.endpoint_x.val\" :y2=\"0\" :stroke=\"prop_data.extend_attr.o_color.val\" :stroke-width=\"prop_data.extend_attr.o_width.val\"></line><line :x1=\"prop_data.extend_attr.startpoint_x.val\" :y1=\"0\" :x2=\"prop_data.extend_attr.endpoint_x.val\" :y2=\"0\" :stroke=\"prop_data.extend_attr.i_color.val\" :stroke-width=\"prop_data.extend_attr.i_width.val\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"o_color": {
|
||||
"title": "管道颜色",
|
||||
"val": "#0a7ae2",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"i_color": {
|
||||
"title": "水流颜色",
|
||||
"val": "#119bfa",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_x": {
|
||||
"title": "起点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_x": {
|
||||
"title": "终点x相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"o_width": {
|
||||
"title": "管道宽度",
|
||||
"val": 10,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"i_width": {
|
||||
"title": "水流宽度",
|
||||
"val": 5,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "水流效果",
|
||||
"val": {
|
||||
"selectval": "svg_ani_flow",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "draw",
|
||||
"priview_img": "/Pipeline_H_Svg.png"
|
||||
},
|
||||
{
|
||||
"type": "Pipeline_V_Svg",
|
||||
"title": "管道-纵向",
|
||||
"panel_class": "draw",
|
||||
"template": "<fragment><line :x1=\"0\" :y1=\"prop_data.extend_attr.startpoint_y.val\" :x2=\"0\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :stroke=\"prop_data.extend_attr.o_color.val\" :stroke-width=\"prop_data.extend_attr.o_width.val\"></line><line :x1=\"0\" :y1=\"prop_data.extend_attr.startpoint_y.val\" :x2=\"0\" :y2=\"prop_data.extend_attr.endpoint_y.val\" :stroke=\"prop_data.extend_attr.i_color.val\" :stroke-width=\"prop_data.extend_attr.i_width.val\" :class=\"prop_data.extend_attr.svg_line_ani.val.selectval\"></line></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"o_color": {
|
||||
"title": "管道颜色",
|
||||
"val": "#0a7ae2",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"i_color": {
|
||||
"title": "水流颜色",
|
||||
"val": "#119bfa",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"startpoint_y": {
|
||||
"title": "起点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"endpoint_y": {
|
||||
"title": "终点y相对坐标",
|
||||
"val": 0,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"o_width": {
|
||||
"title": "管道宽度",
|
||||
"val": 10,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"i_width": {
|
||||
"title": "水流宽度",
|
||||
"val": 5,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_line_ani": {
|
||||
"title": "水流效果",
|
||||
"val": {
|
||||
"selectval": "svg_ani_flow",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow",
|
||||
"label": "正向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_back",
|
||||
"label": "反向"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_flow_stop",
|
||||
"label": "停止"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "draw",
|
||||
"priview_img": "/Pipeline_V_Svg.png"
|
||||
},
|
||||
{
|
||||
"type": "ReservoirSvg",
|
||||
"title": "蓄水池",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><g transform=\"translate(50,100)rotate(180)scale(1)\"><rect x=\"0\" y=\"65\" :width=\"prop_data.extend_attr.width.val\" :height=\"prop_data.extend_attr.height.val\" fill=\"#000000\" :stroke=\"prop_data.extend_attr.color.val\" stroke-width=\"4\"></rect><line x1=\"8\" :y1=\"(prop_data.extend_attr.height.val+65)\" :x2=\"(prop_data.extend_attr.width.val-8)\" :y2=\"(prop_data.extend_attr.height.val+65)\" stroke=\"#000000\" stroke-width=\"5\"></line><rect x=\"2\" y=\"65\" :width=\"(prop_data.extend_attr.width.val-4)\" :height=\"(prop_data.extend_attr.height.val-20)\" :fill=\"prop_data.extend_attr.f_color.val\" :class=\"prop_data.extend_attr.svg_fill_ani.val.selectval\"></rect></g></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "边框颜色",
|
||||
"val": "#FFFFFF",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"f_color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#37cfe7",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"width": {
|
||||
"title": "宽度",
|
||||
"val": 100,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"height": {
|
||||
"title": "高度",
|
||||
"val": 60,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"svg_fill_ani": {
|
||||
"title": "填充效果",
|
||||
"val": {
|
||||
"selectval": "svg_ani_fill_h40",
|
||||
"selectgroup": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "无"
|
||||
},
|
||||
{
|
||||
"value": "svg_ani_fill_h40",
|
||||
"label": "正向"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "select"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/ReservoirSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "WaterPipeValveSvg",
|
||||
"title": "水管阀",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><ellipse cx=\"0\" cy=\"-12\" :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" rx=\"20\" ry=\"2\"/><rect :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" height=\"9\" width=\"6\" x=\"-2\" y=\"-12\"/><rect :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" height=\"5\" width=\"19\" x=\"-8\" y=\"-6\"/><rect :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" height=\"12\" width=\"39\" x=\"-19\" y=\"-1\"/><rect :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" height=\"20\" width=\"11\" x=\"-30\" y=\"-6\"/><rect :fill=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" :stroke=\"JSON.parse(prop_data.extend_attr.switch.val.selectval).fill\" height=\"20\" width=\"11\" x=\"20\" y=\"-6\"/></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"switch": {
|
||||
"title": "类型",
|
||||
"val": {
|
||||
"selectval": "{\"fill\":\"#FF0000\"}",
|
||||
"ridiogroup": [
|
||||
{
|
||||
"value": "{\"fill\":\"#FF0000\"}",
|
||||
"label": "关阀"
|
||||
},
|
||||
{
|
||||
"value": "{\"fill\":\"#00FF00\"}",
|
||||
"label": "开阀"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "radiogroup"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/WaterPipeValveSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "RightAnglePipeSvg",
|
||||
"title": "直角管道",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><path :fill=\"prop_data.extend_attr.color.val\" d=\"m-2.84801,-8.56044l7.8889,0l0,0c4.35692,0 7.8889,3.75583 7.8889,8.38889c0,4.63306 -3.53198,8.38889 -7.8889,8.38889l-7.8889,0l0,-16.77778z\"/><rect :fill=\"prop_data.extend_attr.color.val\" x=\"-16.07021\" y=\"-8.56044\" width=\"15.84921\" height=\"16\" /><rect :fill=\"prop_data.extend_attr.color.val\" x=\"-3.07021\" y=\"1.6548\" width=\"16\" height=\"16\"/></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "管道颜色",
|
||||
"val": "#0a7ae2",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/RightAnglePipeSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "CoolingTowerSvg",
|
||||
"title": "冷却塔",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><rect transform=\"translate(-375 -210)\" height=\"6.35115\" width=\"30\" y=\"182.99916\" x=\"362.03168\" :fill=\"prop_data.extend_attr.color.val\"/><path transform=\"translate(-375 -210)\" d=\"m351.12388,196.27079l0,-3.62923l0,0c0,-2.00437 11.75252,-3.62923 26.24999,-3.62923c14.49747,0 26.24999,1.62486 26.24999,3.62923l0,3.62923l-52.49998,0z\" :fill=\"prop_data.extend_attr.color.val\"/><rect transform=\"translate(-375 -210)\" height=\"18.14613\" width=\"45.46875\" y=\"196.60876\" x=\"354.06293\" :fill=\"prop_data.extend_attr.color.val\"/><path transform=\"translate(-375 -210)\" d=\"m339.11917,231.98921l14.0625,-16.7852l46.875,0l14.06249,16.7852l-74.99999,0z\" :fill=\"prop_data.extend_attr.color.val\"/></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "冷却塔颜色",
|
||||
"val": "#E6EEFAFF",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/CoolingTowerSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "ChemicalFeederSvg",
|
||||
"title": "化学加料器",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><path transform=\"translate(-460,-171)\" d=\"m490.83794,134.8702c0,3.4359 -13.80016,6.22125 -30.82353,6.22125m30.82353,-6.22125l0,0c0,3.4359 -13.80016,6.22125 -30.82353,6.22125c-17.02336,0 -30.82351,-2.78534 -30.82351,-6.22125m0,0l0,0c0,-3.4359 13.80016,-6.22125 30.82351,-6.22125c17.02336,0 30.82353,2.78535 30.82353,6.22125l0,24.885c0,3.4359 -13.80016,6.22124 -30.82353,6.22124c-17.02336,0 -30.82351,-2.78534 -30.82351,-6.22124l0,-24.885z\" :fill=\"prop_data.extend_attr.color.val\"/><path transform=\"translate(-460,-171)\" d=\"m473.3227,122.35395c0,1.53294 -5.47793,2.77564 -12.23531,2.77564m12.23531,-2.77564l0,0c0,1.53294 -5.47793,2.77564 -12.23531,2.77564c-6.75737,0 -12.2353,-1.24269 -12.2353,-2.77564m0,0l0,0c0,-1.53294 5.47793,-2.77564 12.2353,-2.77564c6.75737,0 12.23531,1.2427 12.23531,2.77564l0,11.10255c0,1.53294 -5.47793,2.77563 -12.23531,2.77563c-6.75737,0 -12.2353,-1.24269 -12.2353,-2.77563l0,-11.10255z\" :fill=\"prop_data.extend_attr.color.val\"/><rect transform=\"translate(-460,-171)\" height=\"4.59415\" width=\"30.58823\" y=\"164.03918\" x=\"444.22147\" :fill=\"prop_data.extend_attr.color.val\"/><rect transform=\"translate(-460,-171)\" height=\"49.9614\" width=\"94.11762\" y=\"167.63333\" x=\"412.69207\" :fill=\"prop_data.extend_attr.color.val\"/><path transform=\"translate(-460,-171)\" d=\"m500.73203,173.02074l13.76468,0l4.58824,18.6637l-4.58824,18.66378l-13.76468,0l4.58823,-18.66378l-4.58823,-18.6637z\" :fill=\"prop_data.extend_attr.color.val\"/><path transform=\"translate(-460,-171)\" d=\"m417.43793,210.92252l-13.76468,0l-4.58823,-18.6637l4.58823,-18.66379l13.76468,0l-4.58823,18.66379l4.58823,18.6637z\" :fill=\"prop_data.extend_attr.color.val\"/></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"color": {
|
||||
"title": "化学加料器",
|
||||
"val": "#E6EEFAFF",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/ChemicalFeederSvg.png"
|
||||
},
|
||||
{
|
||||
"type": "RectangleSvg",
|
||||
"title": "矩形",
|
||||
"panel_class": "common",
|
||||
"template": "<fragment><rect :width=\"prop_data.extend_attr.width.val\" :height=\"prop_data.extend_attr.height.val\" :fill=\"prop_data.extend_attr.fill_color.val\" :stroke-width=\"prop_data.extend_attr.stroke_width.val\" :stroke=\"prop_data.extend_attr.stroke_color.val\" /></fragment>",
|
||||
"props": [
|
||||
"prop_data"
|
||||
],
|
||||
"extend_attr": {
|
||||
"width": {
|
||||
"title": "矩形宽度",
|
||||
"val": 80,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"height": {
|
||||
"title": "矩形高度",
|
||||
"val": 30,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"fill_color": {
|
||||
"title": "填充颜色",
|
||||
"val": "#000000",
|
||||
"type": "colorinputbox"
|
||||
},
|
||||
"stroke_width": {
|
||||
"title": "边框宽度",
|
||||
"val": 2,
|
||||
"type": "numberinputbox"
|
||||
},
|
||||
"stroke_color": {
|
||||
"title": "边框颜色",
|
||||
"val": "#FFFFFF",
|
||||
"type": "colorinputbox"
|
||||
}
|
||||
},
|
||||
"create_type": "draggable",
|
||||
"priview_img": "/RectangleSvg.png"
|
||||
}
|
||||
]
|
||||
3138
src/components/WebtopoEditor/assets/temp/example.json
Normal file
1
src/components/WebtopoEditor/assets/temp/example2.json
Normal file
28
src/components/WebtopoEditor/components/BottomBar.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
title="操作说明"
|
||||
trigger="click"
|
||||
>
|
||||
<i slot="reference" class="el-icon-question question" />
|
||||
<ul>
|
||||
<li>常规组件和图表组件用鼠标左键选中并按住可拖动至画布</li>
|
||||
<li>绘制组件需先选中 再将鼠标移至画布中按住左键开始绘制 松开左键结束绘制</li>
|
||||
<li>在画布上单击左键并按住可以拖动组件改变位置</li>
|
||||
<li>当组件选中时会有选中效果 此时右侧面板弹出 可使用快捷键和编辑右侧面板属性更改组件</li>
|
||||
<li>鼠标右键点击组件可以进行一些快捷操作</li>
|
||||
<li>键盘↑↓←→可移动选中组件 ctrl+c复制当前选中组件 deleted删除当前选中组件</li>
|
||||
<li>ctrl+键盘↑↓←→可移动组件图层</li>
|
||||
<li>点击画布空白处可以取消选中组件 并关闭属性面板</li>
|
||||
<li>点击《 符号可以显示或隐藏左侧面板</li>
|
||||
<li>请先保存绘制再切换到预览界面</li>
|
||||
</ul>
|
||||
</el-popover>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.question{
|
||||
font-size: 24px;
|
||||
color: #f5f5f5;
|
||||
padding-left: 20px;
|
||||
}
|
||||
</style>
|
||||
153
src/components/WebtopoEditor/components/LeftToolBar.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<div :class="leftnav.navclass">
|
||||
<div v-show="leftnav.navopen" class="svgimg">
|
||||
<el-collapse v-model="activeNames" accordion style="width:100%">
|
||||
<el-collapse-item title="常规组件" name="1" style="margin-top: 15px;">
|
||||
<ul class="leftImgUl">
|
||||
<li v-for="(leftImgItem,index) in left_imglists.commonComponentList" :key="index">
|
||||
<img
|
||||
:title="leftImgItem.title"
|
||||
:src="leftImgItem.priview_img"
|
||||
draggable="true"
|
||||
@dragstart="dragStartEvent(leftImgItem, $event)"
|
||||
@dragend="dragEndEvent(leftImgItem, $event)"
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="绘制组件" name="2">
|
||||
<ul class="leftImgUl">
|
||||
<li v-for="(leftImgItem,index) in left_imglists.drawComponentList" :key="index">
|
||||
<img
|
||||
:class="select_toolbar == leftImgItem.type ? 'svg-selected' : ''"
|
||||
:title="leftImgItem.title"
|
||||
:src="leftImgItem.priview_img"
|
||||
@click="() => { $emit('setCreatSvgInfo', leftImgItem) }"
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { ILeftImgLists, IComponentInfo } from '../func/Model'
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
left_imglists: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 选中的左侧工具图标
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
select_toolbar: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeNames: '1',
|
||||
leftnav: {
|
||||
navclass: 'leftnavDisplay',
|
||||
navopen: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
clickHandleIcon() {
|
||||
this.leftnav.navopen = !this.leftnav.navopen
|
||||
this.leftnav.navclass = this.leftnav.navclass === 'leftnavDisplay' ? 'leftnavNone' : 'leftnavDisplay'
|
||||
},
|
||||
dragStartEvent(leftImgItem, e) {
|
||||
// 设置要创建的svg组件信息
|
||||
this.$emit('setCreatSvgInfo', leftImgItem)
|
||||
},
|
||||
dragEndEvent(leftImgItem, e) {
|
||||
// 拖动时记录拖动的svg信息
|
||||
if (e.dataTransfer?.dropEffect !== 'copy') {
|
||||
this.$message.error('请将组件拖到画布中!')
|
||||
// 清空已选择的信息
|
||||
this.$emit('setCreatSvgInfo', {})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.leftnavDisplay,
|
||||
.leftnavNone {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
.leftnavDisplay {
|
||||
width: 210px;
|
||||
}
|
||||
.leftnavNone {
|
||||
width: 10px;
|
||||
}
|
||||
.svgimg {
|
||||
/* background-color: green; */
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: overlay;
|
||||
}
|
||||
.svgimg::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.handlehidden {
|
||||
height: 100%;
|
||||
width: 10px;
|
||||
background-color: grey;
|
||||
}
|
||||
.handleicon {
|
||||
top: 50%;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.leftImgUl {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
padding: 0;
|
||||
}
|
||||
.leftImgUl li {
|
||||
width: calc(33.33% - 30px);
|
||||
margin: 0 15px 15px 15px;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
box-shadow: 1px 1px 5px #ddd;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
.leftImgUl li :hover {
|
||||
box-shadow: 1px 1px 10px #ccc;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.leftImgUl img {
|
||||
width: 100%;
|
||||
}
|
||||
.svg-selected {
|
||||
outline: 1px solid #0cf;
|
||||
}
|
||||
</style>
|
||||
104
src/components/WebtopoEditor/components/RightToolBar.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="rightnav">
|
||||
<div class="form-wrap">
|
||||
<el-form size="small" label-placement="left">
|
||||
<el-form-item label="标识">
|
||||
<span class="form-label">{{ set_svg_info.id }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<span class="form-label">{{ set_svg_info.type }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="set_svg_info.title" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="x轴坐标">
|
||||
<el-input-number v-model="set_svg_info.svgPositionX" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="y轴坐标">
|
||||
<el-input-number v-model="set_svg_info.svgPositionY" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大小">
|
||||
<el-input-number v-model="set_svg_info.size" :min="1" :step="0.1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="旋转">
|
||||
<el-input-number v-model="set_svg_info.angle" />
|
||||
</el-form-item>
|
||||
<el-form-item v-for="(item,index) in set_svg_info.extend_attr" :key="index" :label="item.title">
|
||||
<el-input-number v-if="item.type == 'numberinputbox'" v-model="item.val" />
|
||||
<el-color-picker
|
||||
v-else-if="item.type == 'colorinputbox'"
|
||||
v-model="item.val"
|
||||
:modes="['hex']"
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="item.type == 'textinputbox'"
|
||||
v-model="item.val"
|
||||
:placeholder="`请输入${item.title}`"
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="item.type == 'textareainputbox'"
|
||||
v-model="item.val"
|
||||
:placeholder="`请输入${item.title}`"
|
||||
type="textarea"
|
||||
/>
|
||||
<el-radio-group v-else-if="item.type == 'radiogroup'" v-model="item.val.selectval">
|
||||
<el-radio
|
||||
v-for="ridioitem in item.val.ridiogroup"
|
||||
:key="ridioitem.value"
|
||||
:value="ridioitem.value"
|
||||
>{{ ridioitem.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-select v-else-if="item.type == 'select'" v-model="item.val.selectval">
|
||||
<el-option
|
||||
v-for="group in item.val.selectgroup"
|
||||
:key="group.value"
|
||||
:label="group.label"
|
||||
:value="group.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
set_svg_info: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.rightnav{
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.form-wrap{
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
.form-label{
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
49
src/components/WebtopoEditor/components/SvgDynamic.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<component :is="component_info" :prop_data="component_attr" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_template: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_props: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_attr: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
component_info: {
|
||||
template: this.component_template,
|
||||
props: ['prop_data']
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
613
src/components/WebtopoEditor/components/SvgEditor.vue
Normal file
@ -0,0 +1,613 @@
|
||||
<template>
|
||||
<section>
|
||||
<div class="ancestors" @mousedown="documentClickEvent">
|
||||
<div class="navleft">
|
||||
<left-tool-bar
|
||||
:left_imglists="leftimg_lists"
|
||||
:select_toolbar="select_toolbar"
|
||||
@setCreatSvgInfo="setCreatSvgInfo"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="warp"
|
||||
@drop="dropEvent"
|
||||
@dragenter="dragEnterEvent"
|
||||
@dragover="dragOverEvent"
|
||||
@mousemove="mouseMoveEvent"
|
||||
@mouseup="mouseUpEvent"
|
||||
@mousedown="mouseDownCanvasEvent"
|
||||
>
|
||||
<svg
|
||||
ref="svg_dom_ref"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style="background-color:#000;"
|
||||
:width="svgCanvas.width"
|
||||
:height="svgCanvas.height"
|
||||
:viewBox="`0 0 ${svgCanvas.width} ${svgCanvas.height}`"
|
||||
>
|
||||
<defs />
|
||||
<filter id="solid" x="0" y="0" width="1" height="1">
|
||||
<feFlood flood-color="rgb(255,255,255)" />
|
||||
<feComposite in="SourceGraphic" />
|
||||
</filter>
|
||||
<g
|
||||
v-for="(item,index) in svgLists"
|
||||
:id="item.id"
|
||||
:key="item.id"
|
||||
style="cursor:pointer"
|
||||
:class="item.id == select_svg.id ? 'svg-selected' : ''"
|
||||
:transform="'translate(' + (item.svgPositionX) + ',' + (item.svgPositionY) + ')' + 'rotate(' + item.angle + ')' + 'scale(' + item.size + ')'"
|
||||
@mousedown="mouseDownEvent(item, index, $event)"
|
||||
@contextmenu.stop="contextmenuEvent"
|
||||
>
|
||||
<SvgDynamic
|
||||
:component_type="item.type"
|
||||
:component_template="component_infos.filter(f => f.type === item.type)[0].template"
|
||||
:component_props="component_infos.filter(f => f.type == item.type)[0].props"
|
||||
:component_attr="item"
|
||||
/>
|
||||
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div v-show="rightnav_open" class="navright">
|
||||
<right-tool-bar :set_svg_info="set_svg_info" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右键菜单 -->
|
||||
<ul v-show="display_contextmenu" ref="contextMenuRef" class="contextMenu">
|
||||
<li v-for="(item,index) in contextmenu_data" :key="index" @click="item.fun()">
|
||||
<p :class="item.enable ? '' : 'disabled'">
|
||||
{{ item.name }}
|
||||
<span class="shortcut">{{ item.hotkey }}</span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LeftToolBar from './LeftToolBar.vue'
|
||||
import RightToolBar from './RightToolBar.vue'
|
||||
|
||||
import SvgDynamic from './SvgDynamic.vue'
|
||||
import {
|
||||
moveUp,
|
||||
moveDown,
|
||||
moveLeft,
|
||||
moveRight,
|
||||
hotkeyCopy,
|
||||
hotkeyDel,
|
||||
hotkeyPutOnTop,
|
||||
hotkeyPutOnButtom,
|
||||
hotkeyPutOnUp,
|
||||
hotkeyPutOnDown
|
||||
} from '@/components/WebtopoEditor/func/HotkeyFunc'
|
||||
export default {
|
||||
components: {
|
||||
LeftToolBar,
|
||||
RightToolBar,
|
||||
SvgDynamic
|
||||
},
|
||||
props: {
|
||||
// 组件的json格式
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_infos: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
svgCanvas: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return { width: 1520, height: 720 }
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const self = this
|
||||
return {
|
||||
svgLists: [],
|
||||
leftimg_lists: {},
|
||||
select_lefttool: {},
|
||||
display_contextmenu: false, // 显示右键菜单
|
||||
set_svg_info: {
|
||||
id: '',
|
||||
title: '',
|
||||
svgPositionX: 0,
|
||||
svgPositionY: 0
|
||||
},
|
||||
select_svg: {
|
||||
id: '',
|
||||
index: 0,
|
||||
sPositionX: 0,
|
||||
sPositionY: 0,
|
||||
create_type: ''
|
||||
},
|
||||
select_toolbar: '', // 选中的左侧工具栏
|
||||
mouseInfo: {
|
||||
status: 0,
|
||||
mPositionX: 0,
|
||||
mPositionY: 0
|
||||
}, // 记录鼠标信息
|
||||
rightnav_open: false,
|
||||
contextmenu_data: [
|
||||
{
|
||||
name: '复制',
|
||||
hotkey: 'Ctrl+C',
|
||||
enable: true,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyCopy(self.svgLists, self.select_svg)
|
||||
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '删除',
|
||||
hotkey: 'Delete',
|
||||
enable: false,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyDel(self.svgLists, self.select_svg)
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '置于顶层',
|
||||
hotkey: 'Ctrl+→',
|
||||
enable: true,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyPutOnTop(self.svgLists, self.select_svg)
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '置于底层',
|
||||
hotkey: 'Ctrl+←',
|
||||
enable: true,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyPutOnButtom(this.svgLists, this.select_svg)
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '置于上一层',
|
||||
hotkey: 'Ctrl+↑',
|
||||
enable: true,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyPutOnUp(self.svgLists, self.select_svg)
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '置于下一层',
|
||||
hotkey: 'Ctrl+↓',
|
||||
enable: true,
|
||||
fun: function() {
|
||||
if (!this.enable) {
|
||||
return
|
||||
}
|
||||
hotkeyPutOnDown(self.svgLists, self.select_svg)
|
||||
self.display_contextmenu = false
|
||||
}
|
||||
}
|
||||
] // 右键菜单数据
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
component_infos: {
|
||||
handler: function(newval) {
|
||||
this.leftimg_lists = {
|
||||
commonComponentList: newval.filter((f) => f.panel_class === 'common'),
|
||||
drawComponentList: newval.filter((f) => f.panel_class === 'draw'),
|
||||
chartComponentList: newval.filter((f) => f.panel_class === 'chart')
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
// 监听键盘
|
||||
const self = this
|
||||
document.onkeydown = function(e) {
|
||||
// 如果没选中组件
|
||||
if (!self.select_svg.id) {
|
||||
return
|
||||
}
|
||||
if (!e.ctrlKey && e.key === 'ArrowUp') {
|
||||
e.preventDefault()
|
||||
moveUp(self.svgLists, self.select_svg)
|
||||
} else if (!e.ctrlKey && e.key === 'ArrowDown') {
|
||||
e.preventDefault()
|
||||
moveDown(self.svgLists, self.select_svg)
|
||||
} else if (!e.ctrlKey && e.key === 'ArrowLeft') {
|
||||
e.preventDefault()
|
||||
moveLeft(self.svgLists, self.select_svg)
|
||||
} else if (!e.ctrlKey && e.key === 'ArrowRight') {
|
||||
e.preventDefault()
|
||||
moveRight(self.svgLists, self.select_svg)
|
||||
} else if (e.ctrlKey && e.key.toLowerCase() === 'c') {
|
||||
// ctrl c
|
||||
e.preventDefault()
|
||||
hotkeyCopy(self.svgLists, self.select_svg)
|
||||
} else if (e.key === 'Delete') {
|
||||
// deleted
|
||||
|
||||
e.preventDefault()
|
||||
hotkeyDel(self.svgLists, self.select_svg)
|
||||
self.rightnav_open = false
|
||||
} else if (e.ctrlKey && e.key === 'ArrowUp') {
|
||||
// 上移一层
|
||||
|
||||
e.preventDefault()
|
||||
hotkeyPutOnUp(self.svgLists, self.select_svg)
|
||||
} else if (e.ctrlKey && e.key === 'ArrowDown') {
|
||||
// 下移一层
|
||||
e.preventDefault()
|
||||
hotkeyPutOnDown(self.svgLists, self.select_svg)
|
||||
} else if (e.ctrlKey && e.key === 'ArrowLeft') {
|
||||
// 置于底层
|
||||
e.preventDefault()
|
||||
hotkeyPutOnButtom(self.svgLists, self.select_svg)
|
||||
} else if (e.ctrlKey && e.key === 'ArrowRight') {
|
||||
// 置于顶层
|
||||
e.preventDefault()
|
||||
hotkeyPutOnTop(self.svgLists, self.select_svg)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @description: 从左侧工具栏拖动组件到画布触发的事件
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
dropEvent(e) {
|
||||
// 当左侧工具栏拖动到此处时在画布上创建该组件
|
||||
if (Object.keys(this.select_lefttool).length < 1) {
|
||||
// 未选择任何组件
|
||||
return
|
||||
}
|
||||
// 在鼠标位置创建当前组件
|
||||
const create_svg = {
|
||||
id: `${new Date().getTime()}`,
|
||||
type: this.select_lefttool.type,
|
||||
title: this.select_lefttool.title,
|
||||
svgPositionX: e.offsetX,
|
||||
svgPositionY: e.offsetY,
|
||||
angle: 0,
|
||||
size: 1,
|
||||
extend_attr: JSON.parse(
|
||||
JSON.stringify(this.select_lefttool.extend_attr)
|
||||
)
|
||||
}
|
||||
this.svgLists.push(create_svg)
|
||||
// 清空左侧工具选中
|
||||
this.select_lefttool = {}
|
||||
},
|
||||
dragEnterEvent(e) {
|
||||
// dragenter和dragover一定要阻止浏览器默认行为 不然不会触发drop
|
||||
this.rightnav_open = false
|
||||
e.preventDefault()
|
||||
},
|
||||
dragOverEvent(e) {
|
||||
// dragenter和dragover一定要阻止浏览器默认行为 不然不会触发drop
|
||||
e.preventDefault()
|
||||
},
|
||||
setCreatSvgInfo(createsvg_info) {
|
||||
this.select_lefttool = createsvg_info
|
||||
this.select_toolbar = createsvg_info.type
|
||||
},
|
||||
/**
|
||||
* @description: 保存svg结果 父组件调用用
|
||||
* @param {*}type 0失败 1成功 2警告
|
||||
* @return {*}
|
||||
*/
|
||||
saveSvgInfoRes(type) {
|
||||
if (type?.code === 0) {
|
||||
this.$message.error(type?.msg)
|
||||
} else if (type?.code === 1) {
|
||||
this.$message.success(type?.msg)
|
||||
} else if (type?.code === 2) {
|
||||
this.$message.warning(type?.msg)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description: 保存绘制组件后的数据和svgdom
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
saveSvgInfo(e) {
|
||||
if (this.svgLists.length === 0) {
|
||||
this.saveSvgInfoRes({
|
||||
code: 2,
|
||||
msg: '请先绘制图像!'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.saveSvgInfoRes(
|
||||
this.svgLists.length > 0
|
||||
? { code: 1, msg: '保存成功!' }
|
||||
: { code: 0, msg: '保存失败!' }
|
||||
)
|
||||
this.$emit('saveSvgInfo', this.svgLists, this.$refs.svg_dom_ref)
|
||||
},
|
||||
/**
|
||||
* @description: 鼠标点击画布上svg触发事件
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
mouseDownEvent(selectsvg, index, e) {
|
||||
e.preventDefault()
|
||||
e.cancelBubble = true
|
||||
// 清空左侧工具选中
|
||||
this.select_lefttool = {};
|
||||
// 鼠标在画布上的组件按下记录选中的组件信息和鼠标位置信息等
|
||||
({
|
||||
id: this.select_svg.id,
|
||||
svgPositionX: this.select_svg.sPositionX,
|
||||
svgPositionY: this.select_svg.sPositionY
|
||||
} = selectsvg)
|
||||
this.rightnav_open = false
|
||||
this.select_svg.index = index
|
||||
this.select_svg.create_type = 'draggable'
|
||||
this.mouseInfo.status = 1
|
||||
this.mouseInfo.mPositionX = e.clientX
|
||||
this.mouseInfo.mPositionY = e.clientY
|
||||
// debugger
|
||||
},
|
||||
mouseMoveEvent(e) {
|
||||
// 如果鼠标不是按下状态或者没有选择组件
|
||||
if (this.mouseInfo.status !== 1 || !this.select_svg.id) {
|
||||
return
|
||||
}
|
||||
const { clientX, clientY } = e
|
||||
if (this.select_svg.create_type === 'draggable') {
|
||||
const new_select_svg = { ...this.select_svg }
|
||||
new_select_svg.sPositionX += clientX - this.mouseInfo.mPositionX
|
||||
new_select_svg.sPositionY += clientY - this.mouseInfo.mPositionY;
|
||||
// 更新视图
|
||||
({
|
||||
sPositionX: this.svgLists[this.select_svg.index].svgPositionX,
|
||||
sPositionY: this.svgLists[this.select_svg.index].svgPositionY
|
||||
} = new_select_svg)
|
||||
} else if (this.select_svg.create_type === 'draw') {
|
||||
// 拓展属性里未配置的属性不进行赋值
|
||||
if (
|
||||
this.svgLists[this.select_svg.index].extend_attr?.startpoint_x
|
||||
?.val !== null
|
||||
) {
|
||||
this.svgLists[this.select_svg.index].extend_attr.startpoint_x.val = 0
|
||||
}
|
||||
if (
|
||||
this.svgLists[this.select_svg.index].extend_attr?.startpoint_y?.val !=
|
||||
null
|
||||
) {
|
||||
this.svgLists[this.select_svg.index].extend_attr.startpoint_y.val = 0
|
||||
}
|
||||
if (
|
||||
this.svgLists[this.select_svg.index].extend_attr?.endpoint_x?.val !=
|
||||
null
|
||||
) {
|
||||
this.svgLists[this.select_svg.index].extend_attr.endpoint_x.val =
|
||||
clientX - this.mouseInfo.mPositionX
|
||||
}
|
||||
if (
|
||||
this.svgLists[this.select_svg.index].extend_attr?.endpoint_y?.val !=
|
||||
null
|
||||
) {
|
||||
this.svgLists[this.select_svg.index].extend_attr.endpoint_y.val =
|
||||
clientY - this.mouseInfo.mPositionY
|
||||
}
|
||||
}
|
||||
},
|
||||
mouseUpEvent(e) {
|
||||
// 如果鼠标不是按下状态或者没有选择组件
|
||||
if (this.mouseInfo.status !== 1 || !this.select_svg.id) {
|
||||
return
|
||||
}
|
||||
this.mouseInfo.status = 0
|
||||
this.rightnav_open = true
|
||||
this.set_svg_info = this.svgLists[this.select_svg.index]
|
||||
|
||||
// 清空左侧工具选中
|
||||
this.select_lefttool = {}
|
||||
this.select_toolbar = ''
|
||||
},
|
||||
/**
|
||||
* @description: 鼠标点击画布
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
mouseDownCanvasEvent(e) {
|
||||
// 判断当前是否有选中的工具栏
|
||||
if (Object.keys(this.select_lefttool).length < 1) {
|
||||
this.rightnav_open = false
|
||||
this.select_svg.id = ''
|
||||
return
|
||||
}
|
||||
// 在当前位置创建要绘制的组件
|
||||
const create_svg = {
|
||||
id: `${new Date().getTime()}`,
|
||||
type: this.select_lefttool.type,
|
||||
title: this.select_lefttool.title,
|
||||
svgPositionX: e.offsetX,
|
||||
svgPositionY: e.offsetY,
|
||||
angle: 0,
|
||||
size: 1,
|
||||
extend_attr: JSON.parse(
|
||||
JSON.stringify(this.select_lefttool.extend_attr)
|
||||
) // 这个响应式对象我治不了了 所以只能写两次转换
|
||||
}
|
||||
this.svgLists.push(create_svg);
|
||||
// 设置全局选中的组件信息
|
||||
({
|
||||
id: this.select_svg.id,
|
||||
svgPositionX: this.select_svg.sPositionX,
|
||||
svgPositionY: this.select_svg.sPositionY
|
||||
} = create_svg)
|
||||
this.rightnav_open = false
|
||||
this.select_svg.index = this.svgLists.length - 1
|
||||
this.select_svg.create_type = 'draw'
|
||||
this.mouseInfo.status = 1
|
||||
this.mouseInfo.mPositionX = e.clientX
|
||||
this.mouseInfo.mPositionY = e.clientY
|
||||
},
|
||||
/**
|
||||
* @description: 鼠标右键
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
contextmenuEvent(e) {
|
||||
e.preventDefault()
|
||||
this.display_contextmenu = true
|
||||
this.$refs.contextMenuRef.style.left = e.pageX - 170 + 'px'
|
||||
this.$refs.contextMenuRef.style.top = e.pageY - 80 + 'px'
|
||||
// eslint-disable-next-line no-return-assign
|
||||
this.contextmenu_data.map((m) => (m.enable = true))
|
||||
// 判断当前选中组件的index
|
||||
if (this.svgLists.length === 1) {
|
||||
// 禁用下移
|
||||
this.contextmenu_data[3].enable = false
|
||||
this.contextmenu_data[5].enable = false
|
||||
// 禁用上移
|
||||
this.contextmenu_data[2].enable = false
|
||||
this.contextmenu_data[4].enable = false
|
||||
} else if (this.select_svg.index === 0) {
|
||||
// 禁用下移
|
||||
this.contextmenu_data[3].enable = false
|
||||
this.contextmenu_data[5].enable = false
|
||||
} else if (this.select_svg.index === this.svgLists.length - 1) {
|
||||
// 禁用上移
|
||||
this.contextmenu_data[2].enable = false
|
||||
this.contextmenu_data[4].enable = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 点击页面其他位置隐藏右键菜单
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
documentClickEvent(e) {
|
||||
if (e.button !== 2) {
|
||||
this.display_contextmenu = false
|
||||
}
|
||||
},
|
||||
setSvgLists(new_val) {
|
||||
this.svgLists.length = 0
|
||||
this.svgLists.push(...new_val)
|
||||
this.$emit('saveSvgInfo', this.svgLists, this.$refs.svg_dom_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.contextMenu {
|
||||
position: absolute;
|
||||
z-index: 99999;
|
||||
background: #ffffff;
|
||||
padding: 5px 0;
|
||||
margin: 0px;
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
box-shadow: 2px 5px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.contextMenu li {
|
||||
list-style: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.contextMenu .shortcut {
|
||||
width: 115px;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.contextMenu p {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
padding: 0px 15px 1px 20px;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.contextMenu p:hover {
|
||||
background-color: #0cf;
|
||||
color: #ffffff;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.contextMenu .disabled {
|
||||
color: #999;
|
||||
}
|
||||
.contextMenu .disabled:hover {
|
||||
color: #999;
|
||||
background-color: transparent;
|
||||
}
|
||||
.contextMenu li.separator {
|
||||
border-top: solid 1px #e3e3e3;
|
||||
padding-top: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.ancestors {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ancestors .navleft {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
/* border-left: solid 1px rgb(239, 239, 245); */
|
||||
}
|
||||
.ancestors .warp {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ancestors .navright {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
/*background-color: aqua;*/
|
||||
}
|
||||
.navtop {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
border-bottom: solid 1px rgb(239, 239, 245);
|
||||
}
|
||||
.navbuttom {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
.svg-selected {
|
||||
outline: 1px solid #0cf;
|
||||
}
|
||||
.warp::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
@import '../assets/css/svgAnimation/index.css'
|
||||
|
||||
</style>
|
||||
74
src/components/WebtopoEditor/components/SvgPrview.vue
Normal file
@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style="background-color:#000000;"
|
||||
width="100%"
|
||||
height="100%"
|
||||
:viewBox="`0 0 ${svgCanvas.width} ${svgCanvas.height}`"
|
||||
>
|
||||
<g
|
||||
v-for="(item) in svg_data"
|
||||
:id="item.id"
|
||||
:key="item.id"
|
||||
:transform="'translate(' + (item.svgPositionX) + ',' + (item.svgPositionY) + ')' + 'rotate(' + item.angle + ')' + 'scale(' + item.size + ')'"
|
||||
>
|
||||
<svg-dynamic
|
||||
:component_type="item.type"
|
||||
:component_template="component_infos.filter(f => f.type == item.type)[0].template"
|
||||
:component_props="component_infos.filter(f => f.type == item.type)[0].props"
|
||||
:component_attr="item"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SvgDynamic from './SvgDynamic.vue'
|
||||
export default {
|
||||
components: { SvgDynamic },
|
||||
props: {
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
component_infos: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 要渲染的数据
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
svg_data: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
svgCanvas: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return { width: 1520, height: 720 }
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
svg_data: {
|
||||
handler: function(val) {
|
||||
// debugger
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/css/svgAnimation/index.css"
|
||||
</style>
|
||||
47
src/components/WebtopoEditor/components/TopBar.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div style="padding: 10px;display: flex;">
|
||||
<div style="display: flex;width: 100%;flex-direction: row-reverse;">
|
||||
<el-button type="primary" class="button-class" @click="() => { $emit('saveSvgInfo') }">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.logoimg {
|
||||
height: 2rem;
|
||||
min-width: 2rem;
|
||||
margin-right: 0.1rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
.logotext {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
margin-top: 0.7rem;
|
||||
width: 30%;
|
||||
}
|
||||
.a-link {
|
||||
text-decoration: none;
|
||||
margin-right: 1.5rem;
|
||||
align-self: center;
|
||||
}
|
||||
.button-class {
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
105
src/components/WebtopoEditor/func/HotkeyFunc.js
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
/**
|
||||
* 组件上移
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function moveUp(svgLists, select_svg) {
|
||||
svgLists[select_svg.index].svgPositionY -= 1
|
||||
}
|
||||
/**
|
||||
* 组件下移
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function moveDown(svgLists, select_svg) {
|
||||
svgLists[select_svg.index].svgPositionY += 1
|
||||
}
|
||||
/**
|
||||
* 组件左移
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function moveLeft(svgLists, select_svg) {
|
||||
svgLists[select_svg.index].svgPositionX -= 1
|
||||
}
|
||||
/**
|
||||
* 组件右移
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function moveRight(svgLists, select_svg) {
|
||||
svgLists[select_svg.index].svgPositionX += 1
|
||||
}
|
||||
/**
|
||||
* 组件复制
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyCopy(svgLists, select_svg) {
|
||||
svgLists.push({
|
||||
...(JSON.parse(JSON.stringify(svgLists[select_svg.index]))),
|
||||
id: `${new Date().getTime()}`,
|
||||
svgPositionX: svgLists[select_svg.index].svgPositionX + 10,
|
||||
svgPositionY: svgLists[select_svg.index].svgPositionY + 10,
|
||||
title: svgLists[select_svg.index].title + `-copy`
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 组件删除
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyDel(svgLists, select_svg) {
|
||||
svgLists.splice(select_svg.index, 1)
|
||||
}
|
||||
/**
|
||||
* 组件置于顶层
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyPutOnTop(svgLists, select_svg) {
|
||||
const temp = svgLists[select_svg.index]
|
||||
svgLists.splice(select_svg.index, 1)
|
||||
svgLists.push(temp)
|
||||
select_svg.index = svgLists.length - 1
|
||||
}
|
||||
/**
|
||||
* 组件置于底层
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyPutOnButtom(svgLists, select_svg) {
|
||||
const temp = svgLists[select_svg.index]
|
||||
svgLists.splice(select_svg.index, 1)
|
||||
svgLists.unshift(temp)
|
||||
select_svg.index = 0
|
||||
}
|
||||
/**
|
||||
* 组件上移一层
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyPutOnUp(svgLists, select_svg) {
|
||||
if (svgLists.length === 1 || select_svg.index === svgLists.length - 1) {
|
||||
return
|
||||
}
|
||||
const temp = svgLists[select_svg.index]
|
||||
svgLists[select_svg.index] = svgLists[select_svg.index + 1]
|
||||
svgLists[select_svg.index + 1] = temp
|
||||
select_svg.index += 1
|
||||
}
|
||||
/**
|
||||
* 组件下移一层
|
||||
* @param svgLists
|
||||
* @param select_svg
|
||||
*/
|
||||
export function hotkeyPutOnDown(svgLists, select_svg) {
|
||||
if (svgLists.length === 1 || select_svg.index === 0) {
|
||||
return
|
||||
}
|
||||
const temp = svgLists[select_svg.index]
|
||||
svgLists[select_svg.index] = svgLists[select_svg.index - 1]
|
||||
svgLists[select_svg.index - 1] = temp
|
||||
select_svg.index -= 1
|
||||
}
|
||||
77
src/components/WebtopoEditor/func/Model.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @description: 数据结构
|
||||
* @param {*} commonComponentList 常规组件列表
|
||||
* @param {*} drawComponentList 绘制组件列表
|
||||
* @param {*} chartComponentList 图表组件列表
|
||||
* @return {*}
|
||||
*/
|
||||
export interface ILeftImgLists {
|
||||
commonComponentList?: Array<IComponentInfo>,
|
||||
drawComponentList?: Array<IComponentInfo>,
|
||||
chartComponentList?: Array<IComponentInfo>
|
||||
}
|
||||
/**
|
||||
* @description: 画好的组件数据列表
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
export interface ISvgDataLists {
|
||||
id: string,
|
||||
type?: string,
|
||||
title?: string,
|
||||
svgPositionX: number,
|
||||
svgPositionY: number,
|
||||
angle?: number,
|
||||
size?: number,
|
||||
extend_attr?: any
|
||||
}
|
||||
export interface ISvgCanvas {
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
/**
|
||||
* @description: 组件信息格式
|
||||
* @param {*} type 组件类型
|
||||
* @param {*} title 组件显示标题
|
||||
* @param {*} panel_class 面板显示类型 拖放 绘制
|
||||
* @param {*} template 组件渲染模板
|
||||
* @param {*} props 组件传值
|
||||
* @param {*} extend_attr 组件拓展属性
|
||||
* @param {*} create_type 组件创建类型
|
||||
* @param {*} priview_img 组件预览图片
|
||||
* @return {*}
|
||||
*/
|
||||
export interface IComponentInfo {
|
||||
type?: string,
|
||||
title?: string,
|
||||
panel_class?: string,
|
||||
template?: string,
|
||||
props?: Array<string>,
|
||||
extend_attr?: any,
|
||||
create_type?: string,
|
||||
priview_img?: string
|
||||
}
|
||||
/**
|
||||
* @description: 鼠标信息
|
||||
* @param {*} status 1按下 0弹起
|
||||
* @param {*} mPositionX 鼠标x轴坐标
|
||||
* @param {*} mPositionY 鼠标y轴坐标
|
||||
* @return {*}
|
||||
*/
|
||||
export interface IMouseInfo {
|
||||
status: number,
|
||||
mPositionX: number,
|
||||
mPositionY: number
|
||||
}
|
||||
/**
|
||||
* @description: 选中的svg属性
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
export interface ISelectSvg {
|
||||
id: string,
|
||||
index: number,
|
||||
sPositionX: number,
|
||||
sPositionY: number,
|
||||
create_type: string,
|
||||
}
|
||||
227
src/components/WebtopoEditor/index.vue
Normal file
@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<section class="SvgEditor-wrap">
|
||||
<div class="btn-wrap">
|
||||
<el-button v-if="displaymode == 0" type="primary" @click="loadExample('example')">电力系统模板</el-button>
|
||||
<el-button v-if="displaymode == 0" type="primary" @click="loadExample('example2')">水务系统模板</el-button>
|
||||
<el-button type="primary" @click="switchMode">切换到{{ displaymode == 0 ? '预览' : '绘制' }}模式</el-button>
|
||||
<el-button v-if="displaymode == 0" type="primary" @click="downloadSvgData">下载保存数据</el-button>
|
||||
<el-button v-if="displaymode == 0" type="primary" @click="downloadSvgDomData">下载svg数据</el-button>
|
||||
<el-button v-if="displaymode == 1" type="primary" @click="loadExampleData">加载电力模板并模拟硬件工作</el-button>
|
||||
<el-button v-if="displaymode == 0" type="primary" @click="saveBtn">保存</el-button>
|
||||
<bottom-bar v-if="displaymode == 0" />
|
||||
</div>
|
||||
<div ref="ref_svgedit_content" class="SvgEditor-content">
|
||||
<div v-show="displaymode == 0">
|
||||
<SvgEditor
|
||||
ref="ref_svgedit"
|
||||
:component_infos="component_infos"
|
||||
:svg-canvas="{ width: canvasWidth, height: canvasHeight }"
|
||||
@saveSvgInfo="saveSvgInfo"
|
||||
/>
|
||||
</div>
|
||||
<div v-show="displaymode != 0">
|
||||
<SvgPrview
|
||||
:component_infos="component_infos"
|
||||
:svg_data="prview_data"
|
||||
:svg-canvas="{ width: canvasWidth, height: canvasHeight }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
import SvgEditor from './components/SvgEditor.vue'
|
||||
import SvgPrview from './components/SvgPrview.vue'
|
||||
import InterfaceReturn from './assets/temp/InterfaceReturn.json'
|
||||
import example from './assets/temp/example.json'
|
||||
import example2 from './assets/temp/example2.json'
|
||||
import BottomBar from './components/BottomBar.vue'
|
||||
|
||||
export default {
|
||||
components: { SvgEditor, SvgPrview, BottomBar },
|
||||
data() {
|
||||
return {
|
||||
InterfaceReturn,
|
||||
example,
|
||||
example2,
|
||||
interval: null,
|
||||
canvasWidth: 1920,
|
||||
canvasHeight: 900,
|
||||
component_infos: [], // 组件列表
|
||||
prview_data: [], // 要预览的数据
|
||||
displaymode: 0, // 定义一个变量用来控制演示模式 0为绘制模式 1为预览模式
|
||||
savesvg_data: [], // 定义一个变量用来接收保存的svg数据
|
||||
savesvg_dom_data: null // 定义一个变量用来接收保存的svgdom数据
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getComponentInfos()
|
||||
},
|
||||
methods: {
|
||||
// 保存
|
||||
saveBtn() {
|
||||
this.$refs.ref_svgedit.saveSvgInfo()
|
||||
},
|
||||
// 获取组件列表
|
||||
getComponentInfos() {
|
||||
// axios.get('InterfaceReturn.json').then(res => {
|
||||
// component_infos.value = res.data
|
||||
// })
|
||||
this.component_infos = InterfaceReturn
|
||||
},
|
||||
// 定义一个方法 接收组件保存传过来的数据
|
||||
saveSvgInfo(svg_data, svg_dom) {
|
||||
this.savesvg_data = svg_data
|
||||
this.savesvg_dom_data = svg_dom
|
||||
},
|
||||
downloadSvgData() {
|
||||
if (this.savesvg_data == null) {
|
||||
alert('请先保存绘制数据')
|
||||
return
|
||||
}
|
||||
const datastr =
|
||||
'data:text/json;charset=utf-8,' +
|
||||
encodeURIComponent(JSON.stringify(this.savesvg_data))
|
||||
const download = document.createElement('a')
|
||||
download.setAttribute('href', datastr)
|
||||
download.setAttribute('download', `${new Date().getTime()}.json`)
|
||||
download.click()
|
||||
download.remove()
|
||||
},
|
||||
downloadSvgDomData() {
|
||||
if (this.savesvg_dom_data == null) {
|
||||
alert('请先保存绘制数据')
|
||||
return
|
||||
}
|
||||
const datastr =
|
||||
'data:text;charset=utf-8,' +
|
||||
encodeURIComponent(this.savesvg_dom_data.outerHTML)
|
||||
const download = document.createElement('a')
|
||||
download.setAttribute('href', datastr)
|
||||
download.setAttribute('download', `${new Date().getTime()}.html`)
|
||||
download.click()
|
||||
download.remove()
|
||||
},
|
||||
switchMode() {
|
||||
this.displaymode = this.displaymode === 0 ? 1 : 0
|
||||
if (this.displaymode === 1) {
|
||||
this.prview_data = []
|
||||
setTimeout(() => {
|
||||
this.prview_data = this.savesvg_data
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
loadExampleData() {
|
||||
clearInterval(this.interval)
|
||||
const res = {
|
||||
data: example
|
||||
}
|
||||
this.prview_data = res.data
|
||||
const temp = [...res.data]
|
||||
// 模拟硬件工作
|
||||
// 找出所有断路器
|
||||
const anyCircuitBreakerList = temp.filter(
|
||||
(f) => f.type === 'CircuitBreakerSvg'
|
||||
)
|
||||
// 找出所有的电线开关
|
||||
const anyWireBreakList = temp.filter((f) => f.type === 'WireBreakSvg')
|
||||
// // 找到所有饼图
|
||||
// const anyEchartsPieList = temp.filter(
|
||||
// (f) => f.type === 'EchartsPieSvg'
|
||||
// )
|
||||
// 找到所有柱状图
|
||||
// const anyEchartsBasicBarSvgList = temp.filter(
|
||||
// (f) => f.type === 'EchartsBasicBarSvg'
|
||||
// )
|
||||
this.interval = setInterval(function() {
|
||||
anyCircuitBreakerList.forEach((anyCircuitBreaker) => {
|
||||
// 生成一个随机数
|
||||
const random = Math.round(Math.random() * 10)
|
||||
if (random < 5) {
|
||||
anyCircuitBreaker.extend_attr.switch.val.selectval =
|
||||
'{"fill":"#FF0000"}'
|
||||
} else {
|
||||
anyCircuitBreaker.extend_attr.switch.val.selectval =
|
||||
'{"fill":"#00FF00"}'
|
||||
}
|
||||
})
|
||||
anyWireBreakList.forEach((anyWireBreak) => {
|
||||
// 生成一个随机数
|
||||
const random = Math.round(Math.random() * 10)
|
||||
if (random < 5) {
|
||||
anyWireBreak.extend_attr.switch.val.selectval = '{"x2":-10}'
|
||||
} else {
|
||||
anyWireBreak.extend_attr.switch.val.selectval = '{"x2":0}'
|
||||
}
|
||||
})
|
||||
// anyEchartsPieList.forEach((anyEchartsPie) => {
|
||||
// const temp_val = JSON.parse(
|
||||
// anyEchartsPie.extend_attr.echarts_option.val
|
||||
// )
|
||||
// temp_val.series[0].data.forEach((f) => {
|
||||
// // 生成一个随机数
|
||||
// const random = Math.round(Math.random() * 100)
|
||||
// f.value = random
|
||||
// })
|
||||
// anyEchartsPie.extend_attr.echarts_option.val =
|
||||
// JSON.stringify(temp_val)
|
||||
// })
|
||||
// anyEchartsBasicBarSvgList.forEach((anyEchartsBasicBar) => {
|
||||
// const data_arr = [
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300),
|
||||
// Math.round(Math.random() * 300)
|
||||
// ]
|
||||
// const temp_val = JSON.parse(
|
||||
// anyEchartsBasicBar.extend_attr.echarts_option.val
|
||||
// )
|
||||
// temp_val.series[0].data = data_arr
|
||||
// anyEchartsBasicBar.extend_attr.echarts_option.val =
|
||||
// JSON.stringify(temp_val)
|
||||
// })
|
||||
const tempa = JSON.stringify(temp)
|
||||
this.prview_data = JSON.parse(tempa)
|
||||
}, 2000)
|
||||
},
|
||||
loadExample(file_name) {
|
||||
if (file_name === 'example2') {
|
||||
this.$refs.ref_svgedit.setSvgLists(example2)
|
||||
} else {
|
||||
this.$refs.ref_svgedit.setSvgLists(example)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.SvgEditor-wrap{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.btn-wrap{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 30px;
|
||||
.question{
|
||||
font-size: 24px;
|
||||
color: #f5f5f5;
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
.SvgEditor-content{
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
533
src/components/WorderOrderUploadPanel/index.vue
Normal file
@ -0,0 +1,533 @@
|
||||
<template>
|
||||
<div class="photoWall_wrapper">
|
||||
<el-row>
|
||||
|
||||
<el-col :span="24" class="up-col" style="margin-left: 0px">
|
||||
<el-upload
|
||||
ref="upload1"
|
||||
class="upload-demo"
|
||||
|
||||
:before-remove="handleRemove"
|
||||
:limit="10"
|
||||
:show-file-list="showFileList"
|
||||
:multiple="isMultiple"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
:disabled="readonly"
|
||||
:data="para"
|
||||
:action="uploadUrl"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadError"
|
||||
:headers="myHeaders"
|
||||
:accept="documentType"
|
||||
list-type="picture-card"
|
||||
:file-list="upoladFileList"
|
||||
:on-change="handleAddChange"
|
||||
:on-exceed="handleEditChange"
|
||||
>
|
||||
<!-- <el-progress
|
||||
v-if="progressFlag"
|
||||
type="circle"
|
||||
:percentage="loadProgress"
|
||||
class="progress"
|
||||
/> -->
|
||||
|
||||
<i v-if="!readonly" slot="default" class="el-icon-plus" />
|
||||
<div slot="file" slot-scope="{file}">
|
||||
<div v-if="getFileExtName(file)==='.jpg'||getFileExtName(file)==='.png'">
|
||||
<img :src="file.url" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.doc'||getFileExtName(file)==='.docx'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="word" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.pdf'||getFileExtName(file)==='.PDF'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="pdfimg" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.xlsx'||getFileExtName(file)==='.xls'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="excel" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.zip'||getFileExtName(file)==='.rar'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="zip" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<img class="el-upload-list__item-thumbnail" :src="all" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<el-tooltip :content="file.name" placement="top" effect="light">
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
v-if="getFileExtName(file)==='.jpg'||getFileExtName(file)==='.PDF'||getFileExtName(file)==='.pdf'||getFileExtName(file)==='.png'"
|
||||
class="el-upload-list__item-preview"
|
||||
@click="handlePreview(file)"
|
||||
>
|
||||
<i class="el-icon-zoom-in" />
|
||||
</span>
|
||||
<span class="el-upload-list__item-delete" @click="handleDownload(file)">
|
||||
<i class="el-icon-download" />
|
||||
</span>
|
||||
<span
|
||||
v-if="directionControl&&searchControl&&!readonly"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file)"
|
||||
>
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-upload>
|
||||
<span class="main_title_type">{{ $t('task.uploadTip') }}({{ documentType }})</span>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="formTitle"
|
||||
:visible.sync="dialogVisible"
|
||||
top="15%"
|
||||
width="40%"
|
||||
>
|
||||
<img v-if="!isPdf" width="100%" :src="dialogImageUrl" alt style="pointer-events:none;">
|
||||
<div
|
||||
v-else
|
||||
v-loading="pageTotalNum === undefined"
|
||||
element-loading-text="loading"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
>
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<el-row
|
||||
class="page-row"
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-button-group>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-arrow-left"
|
||||
size="mini"
|
||||
@click="prePage"
|
||||
>{{ $t('task.perPage') }}
|
||||
</el-button>
|
||||
<el-button type="primary" size="mini" @click="nextPage">
|
||||
{{ $t('task.nextPage') }}
|
||||
<i class="el-icon-arrow-right el-icon--right" />
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="pagenum">{{ pageNum }} / {{ pageTotalNum }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<pdf
|
||||
class="pdf"
|
||||
:page="pageNum"
|
||||
:src="dialogImageUrl"
|
||||
@progress="loadedRatio = $event"
|
||||
@num-pages="pageTotalNum = $event"
|
||||
@loaded="handleToPdfLoad"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<img :src="url" alt="">
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request'
|
||||
import pdf from 'vue-pdf'
|
||||
import all from '@/assets/images/all.png'
|
||||
import word from '@/assets/images/word.png'
|
||||
import zip from '@/assets/images/zip.png'
|
||||
import pdfimg from '@/assets/images/pdf.png'
|
||||
import excel from '@/assets/images/excel.png'
|
||||
import { getMyHeaders } from '@/utils'
|
||||
|
||||
export default {
|
||||
components: { pdf },
|
||||
props: {
|
||||
uploadType: { // 哪一个模块上传 workOrder 代表工单
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 只读
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
photoSource: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文件限制:票据图片只能是JPG、PNG格式!
|
||||
fileLimit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
directionControl: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
searchControl: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
bizType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
bizCode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/upload'
|
||||
},
|
||||
downloadUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/download'
|
||||
},
|
||||
selectFilesUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/preview'
|
||||
},
|
||||
uploadParam: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
documentType: {
|
||||
type: String,
|
||||
default: '.jpg,.png,.doc,.docx,xlsx,.xls,.pdf'
|
||||
},
|
||||
deleteUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/delete'
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
all,
|
||||
word,
|
||||
excel,
|
||||
zip,
|
||||
pdfimg,
|
||||
showFileList: true,
|
||||
para: { type: this.uploadType },
|
||||
fatherInfo: [],
|
||||
againStatus: false,
|
||||
isMultiple: false,
|
||||
isPdf: false,
|
||||
title: this.$t('task.fjlist'),
|
||||
myHeaders: getMyHeaders(),
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
upoladFileList: [],
|
||||
loadProgress: 0, // 动态显示进度条
|
||||
progressFlag: false, // 关闭进度条 <!-- :http-request="httpRequestUpload" -->
|
||||
isPdfLoaded: false,
|
||||
isPdfLoading: false,
|
||||
formTitle: '',
|
||||
pageNum: 1,
|
||||
pageTotalNum: 0, // 总页数
|
||||
loadedRatio: 0, // 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了
|
||||
showBtnDealImg: true,
|
||||
noneBtnImg: false,
|
||||
limit: '',
|
||||
url: ''
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.uploadType) {
|
||||
this.para.type = this.uploadType
|
||||
} else {
|
||||
this.para = {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
beforeRemove(e) {
|
||||
this.handleRemove(e)
|
||||
},
|
||||
getid(e) {
|
||||
// console.log(e)
|
||||
},
|
||||
// 限制文件大小
|
||||
handleAddChange(file, fileList) {
|
||||
// this.upoladFileList.push(file)
|
||||
// console.log(file)
|
||||
// console.log(this.upoladFileList)
|
||||
// this.limit = this.upoladFileList.length
|
||||
},
|
||||
// 图片个数提示
|
||||
handleEditChange(file, fileList) {
|
||||
this.$message({
|
||||
message: this.$t('task.tenImg'),
|
||||
type: 'warning'
|
||||
})
|
||||
},
|
||||
handleToPdfLoad() {
|
||||
this.pageNum = 1
|
||||
},
|
||||
// 上一页
|
||||
prePage() {
|
||||
let page = this.pageNum
|
||||
page = page > 1 ? page - 1 : this.pageTotalNum
|
||||
this.pageNum = page
|
||||
},
|
||||
|
||||
// 下一页
|
||||
nextPage() {
|
||||
let page = this.pageNum
|
||||
page = page < this.pageTotalNum ? page + 1 : 1
|
||||
this.pageNum = page
|
||||
},
|
||||
uploadError() {
|
||||
this.$emit('uploadError')
|
||||
this.$message.error(this.$t('task.uploadError'))
|
||||
},
|
||||
uploadSuccess(file, data) {
|
||||
if (file) {
|
||||
if (file.code === 200) {
|
||||
file.data.name = file.data.fileName
|
||||
// file.data.url = data.url
|
||||
this.upoladFileList.push(file.data)
|
||||
this.$emit('uploadSuccess', file.data)
|
||||
this.$message.success(this.$t('task.uploadSuccess'))
|
||||
this.$emit('removeSuccess')
|
||||
} else {
|
||||
this.$message({
|
||||
message: file.msg,
|
||||
type: 'warning'
|
||||
})
|
||||
this.$emit('removeSuccess')
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeAvatarUpload(file, fileList) {
|
||||
const name = file.name
|
||||
const size = file.size / 1024 / 1024
|
||||
const msg = name.substring(name.lastIndexOf('.') + 1)
|
||||
const rule = ['jpg', 'jpeg', 'png', 'doc', 'docx', 'xlsx', 'xls', 'pdf', 'PDF']
|
||||
if (!rule.includes(msg)) {
|
||||
this.$message({
|
||||
message: this.$t('task.fileType') + '.jpg,.png,.doc,.docx,xlsx,.xls,.pdf',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (size > 10) {
|
||||
this.$message({
|
||||
message: this.$t('task.fileSize'),
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (this.upoladFileList.length > 10) {
|
||||
this.$message({
|
||||
message: this.$t('task.tenImg'),
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
this.$emit('beforeUpload')
|
||||
},
|
||||
handleDownload(file) {
|
||||
const url = file.url // 1.修改url
|
||||
console.log(url)
|
||||
const name = file.name // 2. 修改name是包含文件格式后缀的,如果没有就要字符串拼接上去,这里决定文件下载的格式
|
||||
const downloadRes = async() => {
|
||||
const response = await fetch(url) // 内容转变成blob地址
|
||||
const blob = await response.blob() // 创建隐藏的可下载链接
|
||||
const objectUrl = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = objectUrl
|
||||
a.download = name
|
||||
a.click()
|
||||
a.remove()
|
||||
}
|
||||
downloadRes()
|
||||
},
|
||||
handlePreview(file) {
|
||||
const type = this.getFileExtName(file)
|
||||
if (type === '.pdf' || type === '.PDF') {
|
||||
this.isPdf = true
|
||||
} else {
|
||||
this.isPdf = false
|
||||
}
|
||||
this.formTitle = file.name
|
||||
this.dialogImageUrl = file.url
|
||||
console.log(this.dialogImageUrl)
|
||||
this.dialogVisible = true
|
||||
},
|
||||
|
||||
clearFileList() {
|
||||
this.upoladFileList = []
|
||||
},
|
||||
getFileExtName(file) {
|
||||
const name = file.name || file.fileName
|
||||
return name.substr(name.lastIndexOf('.')).toLowerCase()
|
||||
},
|
||||
setFileList(data) {
|
||||
this.upoladFileList = []
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i]['name'] = data[i].fileName
|
||||
data[i]['url'] = data[i].base ? data[i].base : data[i].url
|
||||
}
|
||||
this.upoladFileList = data
|
||||
// this.limit = data.length
|
||||
},
|
||||
handleRemove(file) {
|
||||
console.log(file)
|
||||
if (file.status === 'success') {
|
||||
this.$emit('beforeRemove')
|
||||
const name = file.fileName
|
||||
request
|
||||
.post(this.deleteUrl, { fileName: name })
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success(this.$t('task.deleteSuccess'))
|
||||
const index = this.upoladFileList.indexOf(file)
|
||||
this.upoladFileList.splice(index, 1)
|
||||
this.limit--
|
||||
this.$emit('removeSuccess')
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$emit('removeSuccess')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
})
|
||||
// const index = this.upoladFileList.indexOf(file)
|
||||
// this.upoladFileList.splice(index, 1)
|
||||
}
|
||||
// const index = this.upoladFileList.indexOf(file)
|
||||
// this.upoladFileList.splice(index, 1)
|
||||
// this.limit--
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .photoWall_wrapper .header_main_title {
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
/*background: #deedfd;*/
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
/*border-left: 6px solid #9ac1f8;*/
|
||||
}
|
||||
|
||||
::v-deep .photoWall_wrapper .main_title_type {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
// color: red;
|
||||
}
|
||||
::v-deep .up-col{
|
||||
margin-top: 10px;
|
||||
margin-left: -40px;
|
||||
}
|
||||
::v-deep .progress {
|
||||
margin-top: 10px;
|
||||
}
|
||||
::v-deep .upload-demo{
|
||||
padding-left: 0px;
|
||||
}
|
||||
::v-deep .el-upload-list--picture-card .el-upload-list__item {
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border: 1px solid #c0ccda;
|
||||
border-radius: 6px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-size: 10px;
|
||||
width: 110px !important;
|
||||
height: 100px !important;
|
||||
display: inline-block;
|
||||
//padding: 20px 10px 20px 10px !important;
|
||||
transition: none !important;
|
||||
}
|
||||
// ::v-deep .page-row{
|
||||
// width: 100%;
|
||||
// position: fixed;
|
||||
// top: 55px;
|
||||
// left: 20px;
|
||||
// margin-bottom: 20px;
|
||||
// z-index: 9999
|
||||
// }
|
||||
::v-deep .upload-demo .el-upload-list--picture-card .el-upload-list__item img {
|
||||
width: 110px;
|
||||
height: 60px;
|
||||
}
|
||||
.pdf{
|
||||
margin: 30px 0 10px;
|
||||
}
|
||||
.img-p{
|
||||
text-align: center;
|
||||
}
|
||||
.pagenum{
|
||||
margin-top:10px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
::v-deep .disUoloadSty .el-upload--picture-card{
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
::v-deep .upload-demo .el-upload--picture-card {
|
||||
width: 110px !important;
|
||||
height: 100px !important;
|
||||
line-height: 100px!important;
|
||||
}
|
||||
::v-deep .el-upload--picture-card{
|
||||
width: 110px !important;
|
||||
height: 80px !important;
|
||||
line-height: 80px!important;
|
||||
}
|
||||
|
||||
//.upload-demo .el-upload--picture-card i {
|
||||
// line-height: 80px!important;
|
||||
//}
|
||||
|
||||
::v-deep .upload-demo p {
|
||||
width: 110px!important;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
::v-deep .el-upload-list--picture-card .el-upload-list__item-actions span + span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100% !important;
|
||||
vertical-align: middle;
|
||||
border-radius: 6px;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
</style>
|
||||
253
src/components/scale-screen/scale-screen.vue
Normal file
@ -0,0 +1,253 @@
|
||||
<!--
|
||||
* @Author: wei
|
||||
* @description: 大屏自适应容器组件
|
||||
* @LastEditTime: 2022-09-09 16:42:40
|
||||
-->
|
||||
<template>
|
||||
<!-- <section class="screen-box" :style="boxStyle"> -->
|
||||
<div ref="screenWrapper" class="screen-wrapper" :style="wrapperStyle">
|
||||
<slot />
|
||||
</div>
|
||||
<!-- </section> -->
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* 防抖函数
|
||||
* @param {T} fn
|
||||
* @param {number} delay
|
||||
* @return
|
||||
*/
|
||||
function debounce(fn, delay) {
|
||||
let timer = null
|
||||
return function(...args) {
|
||||
timer = setTimeout(
|
||||
() => {
|
||||
typeof fn === 'function' && fn.apply(null, args)
|
||||
clearTimeout(timer)
|
||||
},
|
||||
delay > 0 ? delay : 100
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'VScaleScreen',
|
||||
props: {
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 1920
|
||||
},
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: 1080
|
||||
},
|
||||
fullScreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
autoScale: {
|
||||
type: [Object, Boolean],
|
||||
default: true
|
||||
},
|
||||
selfAdaption: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
boxStyle: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
wrapperStyle: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentWidth: 0,
|
||||
currentHeight: 0,
|
||||
originalWidth: 0,
|
||||
originalHeight: 0,
|
||||
onResize: null,
|
||||
observer: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
screenWrapper() {
|
||||
return this.$refs['screenWrapper']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selfAdaption(val) {
|
||||
if (val) {
|
||||
this.resize()
|
||||
this.addListener()
|
||||
} else {
|
||||
this.clearListener()
|
||||
this.clearStyle()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.onResize = debounce(() => {
|
||||
this.resize()
|
||||
}, this.delay)
|
||||
this.$nextTick(() => {
|
||||
if (this.selfAdaption) {
|
||||
this.resize()
|
||||
this.addListener()
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearListener()
|
||||
// this.observer.disconnect()
|
||||
},
|
||||
methods: {
|
||||
initSize() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// console.log("初始化样式");
|
||||
// 给父元素设置 overflow:hidden
|
||||
this.screenWrapper.parentNode.style.overflow = 'hidden'
|
||||
this.screenWrapper.parentNode.scrollLeft = 0
|
||||
this.screenWrapper.parentNode.scrollTop = 0
|
||||
|
||||
this.$nextTick(() => {
|
||||
// region 获取大屏真实尺寸
|
||||
if (this.width && this.height) {
|
||||
this.currentWidth = this.width
|
||||
this.currentHeight = this.height
|
||||
} else {
|
||||
this.currentWidth = this.screenWrapper.clientWidth
|
||||
this.currentHeight = this.screenWrapper.clientHeight
|
||||
}
|
||||
// endregion
|
||||
// region 获取画布尺寸
|
||||
if (!this.originalHeight || !this.originalWidth) {
|
||||
this.originalWidth = window.screen.width
|
||||
this.originalHeight = window.screen.height
|
||||
}
|
||||
// endregion
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
updateSize() {
|
||||
if (this.currentWidth && this.currentHeight) {
|
||||
this.screenWrapper.style.width = `${this.currentWidth}px`
|
||||
this.screenWrapper.style.height = `${this.currentHeight}px`
|
||||
} else {
|
||||
this.screenWrapper.style.width = `${this.originalWidth}px`
|
||||
this.screenWrapper.style.height = `${this.originalHeight}px`
|
||||
}
|
||||
},
|
||||
handleAutoScale(scale) {
|
||||
if (!this.autoScale) return
|
||||
const screenWrapper = this.screenWrapper
|
||||
const domWidth = screenWrapper.clientWidth
|
||||
const domHeight = screenWrapper.clientHeight
|
||||
const currentWidth = document.body.clientWidth
|
||||
const currentHeight = document.body.clientHeight
|
||||
screenWrapper.style.transform = `scale(${scale},${scale}) `
|
||||
let mx = Math.max((currentWidth - domWidth * scale) / 2, 0)
|
||||
let my = Math.max((currentHeight - domHeight * scale) / 2, 0)
|
||||
if (typeof this.autoScale === 'object') {
|
||||
// @ts-ignore
|
||||
!this.autoScale.x && (mx = 0)
|
||||
// @ts-ignore
|
||||
!this.autoScale.y && (my = 0)
|
||||
}
|
||||
// console.log({
|
||||
// mx,
|
||||
// my,
|
||||
// currentWidth,
|
||||
// currentHeight,
|
||||
// domWidth,
|
||||
// domHeight,
|
||||
// scale,
|
||||
// });
|
||||
this.screenWrapper.style.margin = `${my}px ${mx}px`
|
||||
},
|
||||
updateScale() {
|
||||
const screenWrapper = this.screenWrapper
|
||||
// 获取真实视口尺寸
|
||||
const currentWidth = document.body.clientWidth
|
||||
const currentHeight = document.body.clientHeight
|
||||
// 获取大屏最终的宽高onResize
|
||||
const realWidth = this.currentWidth || this.originalWidth
|
||||
const realHeight = this.currentHeight || this.originalHeight
|
||||
// 计算缩放比例
|
||||
const widthScale = currentWidth / realWidth
|
||||
const heightScale = currentHeight / realHeight
|
||||
// console.log({currentWidth, currentHeight,realWidth,realHeight});
|
||||
|
||||
// 若要铺满全屏,则按照各自比例缩放
|
||||
if (this.fullScreen) {
|
||||
screenWrapper.style.transform = `scale(${widthScale},${heightScale})`
|
||||
return false
|
||||
}
|
||||
// 按照宽高最小比例进行缩放
|
||||
const scale = Math.min(widthScale, heightScale)
|
||||
this.handleAutoScale(scale)
|
||||
},
|
||||
initMutationObserver() {
|
||||
const screenWrapper = this.screenWrapper
|
||||
const observer = (this.observer = new MutationObserver(() => {
|
||||
this.onResize()
|
||||
}))
|
||||
|
||||
observer.observe(screenWrapper, {
|
||||
attributes: true,
|
||||
attributeFilter: ['style'],
|
||||
attributeOldValue: true
|
||||
})
|
||||
},
|
||||
clearListener() {
|
||||
window.removeEventListener('resize', this.onResize)
|
||||
},
|
||||
addListener() {
|
||||
window.addEventListener('resize', this.onResize)
|
||||
},
|
||||
clearStyle() {
|
||||
// console.log("清除");
|
||||
const screenWrapper = this.screenWrapper
|
||||
screenWrapper.parentNode.style.overflow = 'auto'
|
||||
|
||||
screenWrapper.style = ''
|
||||
},
|
||||
async resize() {
|
||||
if (!this.selfAdaption) {
|
||||
return
|
||||
}
|
||||
await this.initSize()
|
||||
this.updateSize()
|
||||
this.updateScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.screen-box {
|
||||
overflow: hidden;
|
||||
background-size: 100% 100%;
|
||||
background: #000;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.screen-wrapper {
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 500ms;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
z-index: 100;
|
||||
transform-origin: left top;
|
||||
}
|
||||
</style>
|
||||
493
src/components/uploadPanel/index.vue
Normal file
@ -0,0 +1,493 @@
|
||||
<template>
|
||||
<div class="photoWall_wrapper">
|
||||
<el-row>
|
||||
|
||||
<el-col :span="24" class="up-col" style="margin-left: 0px">
|
||||
<el-upload
|
||||
ref="upload1"
|
||||
class="upload-demo"
|
||||
:before-remove="handleRemove"
|
||||
:limit="limit"
|
||||
:show-file-list="showFileList"
|
||||
:multiple="isMultiple"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
:disabled="readonly"
|
||||
:data="para"
|
||||
:action="uploadUrl"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadError"
|
||||
:headers="myHeaders"
|
||||
:accept="documentType"
|
||||
list-type="picture-card"
|
||||
:file-list="upoladFileList"
|
||||
:on-change="handleAddChange"
|
||||
:on-exceed="handleEditChange"
|
||||
>
|
||||
|
||||
<i v-if="!readonly" slot="default" class="el-icon-plus" />
|
||||
<div slot="file" slot-scope="{file}">
|
||||
<div v-if="getFileExtName(file)==='.jpg'||getFileExtName(file)==='.png'">
|
||||
<img :src="file.url" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.doc'||getFileExtName(file)==='.docx'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="word" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.pdf'||getFileExtName(file)==='.PDF'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="pdfimg" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.xlsx'||getFileExtName(file)==='.xls'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="excel" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else-if="getFileExtName(file)==='.zip'||getFileExtName(file)==='.rar'">
|
||||
<img class="el-upload-list__item-thumbnail" :src="zip" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<img class="el-upload-list__item-thumbnail" :src="all" alt>
|
||||
<p class="img-p">{{ file.name }}</p>
|
||||
</div>
|
||||
<el-tooltip :content="file.name" placement="top" effect="light">
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
v-if="getFileExtName(file)==='.jpg'||getFileExtName(file)==='.PDF'||getFileExtName(file)==='.pdf'||getFileExtName(file)==='.png'"
|
||||
class="el-upload-list__item-preview"
|
||||
@click="handlePreview(file)"
|
||||
>
|
||||
<i class="el-icon-zoom-in" />
|
||||
</span>
|
||||
<span v-if="showUpload" class="el-upload-list__item-delete" @click="handleDownload(file)">
|
||||
<i class="el-icon-download" />
|
||||
</span>
|
||||
<span
|
||||
v-if="directionControl&&searchControl&&!readonly"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file)"
|
||||
>
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-upload>
|
||||
<span class="main_title_type">{{ $t('task.uploadTip') }}({{ documentType }})</span>
|
||||
<el-dialog
|
||||
:append-to-body="true"
|
||||
:title="formTitle"
|
||||
:visible.sync="dialogVisible"
|
||||
width="40%"
|
||||
>
|
||||
<img v-if="!isPdf" width="100%" :src="dialogImageUrl" alt style="pointer-events:none;">
|
||||
<div
|
||||
v-else
|
||||
v-loading="pageTotalNum === undefined"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
>
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<el-row
|
||||
class="page-row"
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-button-group>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-arrow-left"
|
||||
size="mini"
|
||||
@click="prePage"
|
||||
>上一页
|
||||
</el-button>
|
||||
<el-button type="primary" size="mini" @click="nextPage">
|
||||
下一页
|
||||
<i class="el-icon-arrow-right el-icon--right" />
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="pagenum">{{ pageNum }} / {{ pageTotalNum }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<pdf
|
||||
class="pdf"
|
||||
:page="pageNum"
|
||||
:src="dialogImageUrl"
|
||||
@progress="loadedRatio = $event"
|
||||
@num-pages="pageTotalNum = $event"
|
||||
@loaded="handleToPdfLoad"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<img :src="url" alt="">
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pdf from 'vue-pdf'
|
||||
import all from '@/assets/images/all.png'
|
||||
import word from '@/assets/images/word.png'
|
||||
import zip from '@/assets/images/zip.png'
|
||||
import pdfimg from '@/assets/images/pdf.png'
|
||||
import excel from '@/assets/images/excel.png'
|
||||
import { getMyHeaders, handleDownPic } from '@/utils'
|
||||
|
||||
export default {
|
||||
components: { pdf },
|
||||
props: {
|
||||
uploadType: { // 哪一个模块上传 workOrder 代表工单
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 只读
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
photoSource: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文件限制:票据图片只能是JPG、PNG格式!
|
||||
fileLimit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
directionControl: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
searchControl: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
bizType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
bizCode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/upload'
|
||||
},
|
||||
downloadUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/download'
|
||||
},
|
||||
selectFilesUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/preview'
|
||||
},
|
||||
uploadParam: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
documentType: {
|
||||
type: String,
|
||||
default: 'jpg,jpeg,png,doc,docx,xlsx,xls,pdf,PDF'
|
||||
},
|
||||
deleteUrl: {
|
||||
type: String,
|
||||
default: process.env.VUE_APP_BASE_API + '/media/currencyFile/delete'
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 3
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
all,
|
||||
word,
|
||||
excel,
|
||||
zip,
|
||||
pdfimg,
|
||||
showFileList: true,
|
||||
para: { type: this.uploadType },
|
||||
fatherInfo: [],
|
||||
againStatus: false,
|
||||
isMultiple: false,
|
||||
isPdf: false,
|
||||
title: '附件列表',
|
||||
myHeaders: getMyHeaders(),
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
upoladFileList: [],
|
||||
loadProgress: 0, // 动态显示进度条
|
||||
progressFlag: false, // 关闭进度条 <!-- :http-request="httpRequestUpload" -->
|
||||
isPdfLoaded: false,
|
||||
isPdfLoading: false,
|
||||
formTitle: '',
|
||||
pageNum: 1,
|
||||
pageTotalNum: 0, // 总页数
|
||||
loadedRatio: 0, // 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了
|
||||
showBtnDealImg: true,
|
||||
noneBtnImg: false,
|
||||
url: ''
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.para.type = this.uploadType
|
||||
},
|
||||
methods: {
|
||||
beforeRemove(e) {
|
||||
this.handleRemove(e)
|
||||
},
|
||||
// 限制文件大小
|
||||
handleAddChange(file, fileList) {
|
||||
|
||||
},
|
||||
// 图片个数提示
|
||||
handleEditChange(file, fileList) {
|
||||
this.$message({
|
||||
message: `只能传${this.limit}个文件`,
|
||||
type: 'warning'
|
||||
})
|
||||
},
|
||||
handleToPdfLoad() {
|
||||
this.pageNum = 1
|
||||
},
|
||||
// 上一页
|
||||
prePage() {
|
||||
let page = this.pageNum
|
||||
page = page > 1 ? page - 1 : this.pageTotalNum
|
||||
this.pageNum = page
|
||||
},
|
||||
|
||||
// 下一页
|
||||
nextPage() {
|
||||
let page = this.pageNum
|
||||
page = page < this.pageTotalNum ? page + 1 : 1
|
||||
this.pageNum = page
|
||||
},
|
||||
uploadError() {
|
||||
this.$emit('uploadError')
|
||||
this.$message.error('上传失败')
|
||||
},
|
||||
uploadSuccess(file, data) {
|
||||
if (file) {
|
||||
if (file.code === 200) {
|
||||
file.data.name = file.data.fileName
|
||||
file.data.url = data.url
|
||||
this.upoladFileList.push(file.data)
|
||||
this.$emit('uploadSuccess', file.data)
|
||||
this.$message.success('上传成功')
|
||||
this.$emit('removeSuccess')
|
||||
} else {
|
||||
this.$message({
|
||||
message: file.msg,
|
||||
type: 'warning'
|
||||
})
|
||||
this.$emit('removeSuccess')
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeAvatarUpload(file, fileList) {
|
||||
const name = file.name
|
||||
const size = file.size / 1024 / 1024
|
||||
const msg = name.substring(name.lastIndexOf('.') + 1)
|
||||
const rule = this.documentType.split(',')
|
||||
if (!rule.includes(msg)) {
|
||||
this.$message({
|
||||
message: `文件类型为${this.documentType}`,
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (size > 10) {
|
||||
this.$message({
|
||||
message: '文件不能大于10MB',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (this.upoladFileList.length > this.limit) {
|
||||
this.$message({
|
||||
message: `最多只能传${this.limit}张图片`,
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
this.$emit('beforeUpload')
|
||||
},
|
||||
handleDownload(file) {
|
||||
const id = file.id
|
||||
const options = { id, fileType: this.uploadType }
|
||||
Object.assign(options, {})
|
||||
options.title = file.name
|
||||
handleDownPic(this.downloadUrl, options, (e) => {
|
||||
// console.log(e)
|
||||
})
|
||||
},
|
||||
handlePreview(file) {
|
||||
const type = this.getFileExtName(file)
|
||||
if (type === '.pdf' || type === '.PDF') {
|
||||
this.isPdf = true
|
||||
} else {
|
||||
this.isPdf = false
|
||||
}
|
||||
this.formTitle = file.name
|
||||
this.dialogImageUrl = file.url
|
||||
this.dialogVisible = true
|
||||
},
|
||||
setFileList(data) {
|
||||
this.upoladFileList = []
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i]['name'] = data[i].fileName
|
||||
data[i]['url'] = data[i].base ? data[i].base : data[i].url
|
||||
data[i]['id'] = data[i].pictureId ? data[i].pictureId : data[i].id
|
||||
}
|
||||
this.upoladFileList = data
|
||||
// this.limit = data.length
|
||||
},
|
||||
getFileList() {
|
||||
return this.upoladFileList.filter((k) => k.id == null)
|
||||
},
|
||||
clearFileList() {
|
||||
this.upoladFileList = []
|
||||
},
|
||||
getFileExtName(file) {
|
||||
const name = file.name || file.fileName
|
||||
return name.substr(name.lastIndexOf('.')).toLowerCase()
|
||||
},
|
||||
handleRemove(file) {
|
||||
if (file.status === 'success') {
|
||||
const index = this.upoladFileList.indexOf(file)
|
||||
this.upoladFileList.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .photoWall_wrapper .header_main_title {
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
/*background: #deedfd;*/
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
/*border-left: 6px solid #9ac1f8;*/
|
||||
}
|
||||
|
||||
::v-deep .photoWall_wrapper .main_title_type {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
// color: red;
|
||||
}
|
||||
::v-deep .up-col{
|
||||
margin-top: 10px;
|
||||
margin-left: -40px;
|
||||
}
|
||||
::v-deep .progress {
|
||||
margin-top: 10px;
|
||||
}
|
||||
::v-deep .upload-demo{
|
||||
padding-left: 0px;
|
||||
}
|
||||
::v-deep .el-upload-list--picture-card .el-upload-list__item {
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border: 1px solid #c0ccda;
|
||||
border-radius: 6px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-size: 10px;
|
||||
width: 110px !important;
|
||||
height: 100px !important;
|
||||
display: inline-block;
|
||||
//padding: 20px 10px 20px 10px !important;
|
||||
transition: none !important;
|
||||
}
|
||||
// ::v-deep .page-row{
|
||||
// width: 100%;
|
||||
// position: fixed;
|
||||
// top: 55px;
|
||||
// left: 20px;
|
||||
// margin-bottom: 20px;
|
||||
// z-index: 9999
|
||||
// }
|
||||
::v-deep .upload-demo .el-upload-list--picture-card .el-upload-list__item img {
|
||||
width: 110px;
|
||||
height: 60px;
|
||||
}
|
||||
.pdf{
|
||||
margin: 30px 0 10px;
|
||||
}
|
||||
.img-p{
|
||||
text-align: center;
|
||||
}
|
||||
.pagenum{
|
||||
margin-top:10px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
::v-deep .disUoloadSty .el-upload--picture-card{
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
::v-deep .upload-demo .el-upload--picture-card {
|
||||
width: 110px !important;
|
||||
height: 100px !important;
|
||||
line-height: 100px!important;
|
||||
}
|
||||
::v-deep .el-upload--picture-card{
|
||||
width: 110px !important;
|
||||
height: 80px !important;
|
||||
line-height: 80px!important;
|
||||
}
|
||||
|
||||
//.upload-demo .el-upload--picture-card i {
|
||||
// line-height: 80px!important;
|
||||
//}
|
||||
|
||||
::v-deep .upload-demo p {
|
||||
width: 110px!important;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
::v-deep .el-upload-list--picture-card .el-upload-list__item-actions span + span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100% !important;
|
||||
vertical-align: middle;
|
||||
border-radius: 6px;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
</style>
|
||||