初次提交

This commit is contained in:
2025-06-30 10:17:15 +08:00
commit 5446088524
989 changed files with 365987 additions and 0 deletions

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View 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"
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

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

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

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

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

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

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

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

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

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

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

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

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

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