631 lines
21 KiB
Vue
631 lines
21 KiB
Vue
<template>
|
|
<div class="attribute">
|
|
<div class="row">
|
|
<div class="col attribute-select-box">
|
|
<span class="label" style="line-height: 32px">内容类型</span>
|
|
<el-select style="width: 175px" v-model="attributeType" @change="attributeChange" placeholder="请选择">
|
|
<el-option v-for="item in attributeSelect" :key="item.key" :label="item.name" :value="item.key">
|
|
</el-option>
|
|
</el-select>
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-richText" v-show="attributeType === 'richText'">
|
|
<div class="row">
|
|
<div class="col">
|
|
<span class="label">编辑内容</span>
|
|
<button @click="openRichTextEditor">打开文本编辑器</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row attribute-content attribute-content-link" v-show="attributeType === 'link'">
|
|
<div class="col">
|
|
<span class="label">添加链接</span>
|
|
<div style="flex: 1; position: relative">
|
|
<input class="input link_add" type="text" v-model="addlinkInput" />
|
|
<i class="link_add_btn" @click="_addLink"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-link" v-show="attributeType === 'link'">
|
|
<div class="table">
|
|
<div class="table-head">
|
|
<div class="tr">
|
|
<div class="th">名称</div>
|
|
<div class="th">链接</div>
|
|
<div class="th">操作</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-body" v-if="attribute.link && attribute.link.content && attribute.link.content.length > 0">
|
|
<div class="tr" v-for="(item, index) in attribute.link.content">
|
|
<div class="td" v-if="linkEditActive.index === index">
|
|
<input class="input" type="text" v-model="linkEditActive.name" />
|
|
</div>
|
|
<div class="td" v-else>{{ item.name }}</div>
|
|
<div class="td" v-if="linkEditActive.index === index">
|
|
<textarea class="input link-edit" type="text" v-model="linkEditActive.url"></textarea>
|
|
</div>
|
|
<div class="td" v-else>{{ item.url }}</div>
|
|
<div class="td" v-if="linkEditActive.index === index">
|
|
<button @click="linkConfirmEdit(index)">确认</button>
|
|
<button @click="linkCancelEdit">取消</button>
|
|
</div>
|
|
<div class="td" v-else>
|
|
<button @click="linkEdit(index, item)">编辑</button>
|
|
<button @click="linkDelete(index)">删除</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-empty" v-else>
|
|
<div class="empty-img"></div>
|
|
<p>暂无数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-camera" v-show="attributeType === 'camera'">
|
|
<div class="row">
|
|
<div class="col">
|
|
<span class="label">编辑内容</span>
|
|
<input class="input" type="text" v-model="cameraParams.keyWord" style="width: 180px;margin-right: 10px;" />
|
|
<button class="select btn" @click="cameraSelect({page: 1, limit: cameraParams.pageSize })">搜索</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="table camera-table">
|
|
<div class="table-head">
|
|
<div class="tr">
|
|
<div class="th">操作</div>
|
|
<div class="th">设备名称</div>
|
|
<div class="th" style="width: 80px; flex: 0 80px; min-width: 80px">设备类型</div>
|
|
<div class="th" style="width: 126px; flex: 0 126px; min-width: 126px">设备IP</div>
|
|
<div class="th" style="width: 80px; flex: 0 80px; min-width: 80px">设备端口</div>
|
|
<div class="th" style="width: 80px; flex: 0 80px; min-width: 80px">用户名</div>
|
|
<div class="th">密码</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-body" v-if="cameraList && cameraList.length > 0">
|
|
<div class="tr" v-for="(item, index) in cameraList">
|
|
<div class="td">
|
|
<input type="checkbox" :value="item.id" v-model="item.checked"
|
|
@change="changeAttributeCamera(item)" />
|
|
<span>绑定</span>
|
|
</div>
|
|
<div class="td">{{ item.cameraName }}</div>
|
|
<div class="td" style="width: 80px; flex: 0 80px; min-width: 80px">{{ item.type }}</div>
|
|
<div class="td" style="width: 126px; flex: 0 126px; min-width: 126px">{{ item.ip }}</div>
|
|
<div class="td" style="width: 80px; flex: 0 80px; min-width: 80px">{{ item.port }}</div>
|
|
<div class="td" style="width: 80px; flex: 0 80px; min-width: 80px">{{ item.username }}</div>
|
|
<div class="td">{{ item.password }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-empty" v-else>
|
|
<div class="empty-img"></div>
|
|
<p>暂无数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<Pagination :total="cameraParams.total" v-model:page="cameraParams.page" v-model:limit="cameraParams.pageSize" :pageSizes="false" @pagination="cameraSelect" />
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-isc" v-show="attributeType === 'isc'">
|
|
<!-- <div class="row">
|
|
<div class="col">
|
|
<span class="label">编辑内容</span>
|
|
<input class="input" type="text" @model="ISCName" style="width: 100px;">
|
|
<button class="select btn" @click="ISCSelect">搜索</button>
|
|
</div>
|
|
</div> -->
|
|
<div>
|
|
<div class="table isc-table">
|
|
<div class="table-head">
|
|
<div class="tr">
|
|
<div class="th" style="width: 74px; flex: 0 74px; min-width: 74px">操作</div>
|
|
<div class="th">设备名称</div>
|
|
<div class="th" style="width: 180px; flex: 0 180px; min-width: 180px">设备状态</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-body" style="display: none">
|
|
<div class="tr">
|
|
<div class="td">
|
|
<input type="checkbox" value="2" />
|
|
<span>绑定</span>
|
|
</div>
|
|
<div class="td">设备名称</div>
|
|
<div class="td" style="width: 180px; flex: 0 180px; min-width: 180px">设备状态</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-empty">
|
|
<div class="empty-img"></div>
|
|
<p>暂无数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="" row>
|
|
<ul class="pagination"></ul>
|
|
</div>
|
|
</div>
|
|
<div class="row attribute-content attribute-content-vr" v-show="attributeType === 'vr'">
|
|
<div class="col">
|
|
<span class="label">添加链接</span>
|
|
<div style="flex: 1; position: relative">
|
|
<input class="input vr_add" type="text" v-model="addvrInput" />
|
|
<i class="vr_add_btn" @click="_addRr"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-vr" v-show="attributeType === 'vr'">
|
|
<div class="table">
|
|
<div class="table-head">
|
|
<div class="tr">
|
|
<div class="th">名称</div>
|
|
<div class="th">链接</div>
|
|
<div class="th">操作</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-body" v-if="attribute.vr && attribute.vr.content && attribute.vr.content.length > 0">
|
|
<div class="tr" v-for="(item, index) in attribute.vr.content">
|
|
<div class="td" v-if="vrEditActive.index === index">
|
|
<input class="input" type="text" v-model="vrEditActive.name" />
|
|
</div>
|
|
<div class="td" v-else>{{ item.name }}</div>
|
|
<div class="td" v-if="vrEditActive.index === index">
|
|
<textarea class="input link-edit" type="text" v-model="vrEditActive.url"></textarea>
|
|
</div>
|
|
<div class="td" v-else>{{ item.url }}</div>
|
|
<div class="td" v-if="vrEditActive.index === index">
|
|
<button @click="vrConfirmEdit(index)">确认</button>
|
|
<button @click="vrCancelEdit">取消</button>
|
|
</div>
|
|
<div class="td" v-else>
|
|
<button @click="vrEdit(index, item)">编辑</button>
|
|
<button @click="vrDelete(index)">删除</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-empty" v-else>
|
|
<div class="empty-img"></div>
|
|
<p>暂无数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attribute-content attribute-content-goods" v-show="attributeType === 'goods'">
|
|
<div>
|
|
<div class="row">
|
|
<div class="col">
|
|
<span class="label">编辑内容</span>
|
|
<input class="input goods-select-input" type="text" style="width: 180px;margin-right: 10px;"
|
|
v-model="goodsKeywords">
|
|
<button class="select btn" @click="goodsFilter">搜索</button>
|
|
</div>
|
|
</div>
|
|
<div class="table goods-table">
|
|
<div class="table-head">
|
|
<div class="tr">
|
|
<div class="th" style="width: 60px; flex: 0 60px;min-width: 60px;">序号</div>
|
|
<div class="th" style="flex: 0 0 280px;">名称</div>
|
|
<div class="th">数量</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-body" v-if="goodsList && goodsList.length > 0">
|
|
<div class="tr" v-for="(item, index) in goodsList">
|
|
<div class="td" style="width: 60px; flex: 0 60px;min-width: 60px;">{{ index + 1 }}</div>
|
|
<div class="td" style="flex: 0 0 280px;">{{ item.name }}</div>
|
|
<div class="td"><input class="input" type="number" title="" min="0" max="999999999" v-model="item.cnt"
|
|
@blur="changeAttributeGoods(item)">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-empty" v-else>
|
|
<div class="empty-img"></div>
|
|
<p>暂无数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import { inject } from 'vue'
|
|
import { deviceApi } from '@/api/deviceManage'
|
|
import { MaterialApi } from '@/api/material'
|
|
|
|
let ipcRenderer;
|
|
if (window && window.process && window.process.type === 'renderer') {
|
|
ipcRenderer = require('electron').ipcRenderer
|
|
}
|
|
|
|
const baseDialog: any = ref(null)
|
|
const eventBus: any = inject('bus')
|
|
const attributeType = ref('richText')
|
|
const goodsKeywords = ref('')
|
|
const cameraParams = ref({
|
|
keyWord: '',
|
|
pageSize: 5,
|
|
page: 1,
|
|
total: 0
|
|
})
|
|
const cameraList:any = ref([])
|
|
|
|
const props = defineProps({
|
|
entityOptions: {
|
|
type: Object,
|
|
default: {}
|
|
}
|
|
})
|
|
|
|
const attribute = ref(props.entityOptions.options.attribute)
|
|
if (!props.entityOptions.options.richTextContent) {
|
|
props.entityOptions.options.richTextContent = ''
|
|
}
|
|
const richTextContent = ref(props.entityOptions.options.richTextContent)
|
|
|
|
const allGoodsList: any = ref([])
|
|
const goodsList: any = ref([])
|
|
const goodsFilter = () => {
|
|
if (allGoodsList.value.length) {
|
|
goodsList.value = allGoodsList.value.filter(function (item) {
|
|
item.cnt = 0
|
|
return (item.name.indexOf(goodsKeywords.value) !== -1);
|
|
});
|
|
for (let i = props.entityOptions.attributeGoods.length - 1; i >= 0; i--) {
|
|
for (let m = 0; m < goodsList.value.length; m++) {
|
|
if ('id' in goodsList.value[m]) {
|
|
if (goodsList.value[m].id === props.entityOptions.attributeGoods[i].id) {
|
|
goodsList.value[m].name = props.entityOptions.attributeGoods[i].name
|
|
goodsList.value[m].cnt = props.entityOptions.attributeGoods[i].cnt
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const goodsSelect = async (page) => {
|
|
let formData = new FormData()
|
|
formData.append('pageNum', 1)
|
|
formData.append('pageSize', 999999)
|
|
formData.append('name', goodsKeywords.value)
|
|
const res = await MaterialApi.getList(formData)
|
|
if (res.code === 200) {
|
|
allGoodsList.value = res.data.records
|
|
}
|
|
for (let i = props.entityOptions.attributeGoods.length - 1; i >= 0; i--) {
|
|
let flag = false
|
|
for (let m = 0; m < allGoodsList.value.length; m++) {
|
|
if ('id' in allGoodsList.value[m]) {
|
|
if (allGoodsList.value[m].id === props.entityOptions.attributeGoods[i].id) {
|
|
flag = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (!flag) {
|
|
props.entityOptions.attributeGoods.splice(i, 1)
|
|
}
|
|
}
|
|
goodsFilter()
|
|
console.log('props.entityOptions.attributeGoods', props.entityOptions.attributeGoods)
|
|
}
|
|
const cameraSelect = ({ page, limit }) => {
|
|
if (!props.entityOptions.attributeSelect) {
|
|
return
|
|
}
|
|
else {
|
|
let flag = false
|
|
for (let i = 0; i < props.entityOptions.attributeSelect.length; i++) {
|
|
if (props.entityOptions.attributeSelect[i].key === 'camera') {
|
|
flag = true
|
|
break
|
|
}
|
|
}
|
|
if (!flag) {
|
|
return
|
|
}
|
|
}
|
|
cameraParams.value.page = page
|
|
cameraParams.value.pageSize = limit
|
|
let url = ""
|
|
const params:any = {
|
|
cameraName: cameraParams.value.keyWord,
|
|
pageNum: cameraParams.value.page,
|
|
pageSize: cameraParams.value.pageSize
|
|
};
|
|
deviceApi.deviceList(params).then((res) => {
|
|
if (res.code === 0 || res.code === 200) {
|
|
if (res.data) {
|
|
cameraParams.value.total = res.data.total
|
|
if (res.data.records && res.data.records.length > 0) {
|
|
cameraList.value = res.data.records
|
|
for (let i = 0; i < cameraList.value.length; i++) {
|
|
cameraList.value[i].checked = false
|
|
for (let j = 0; j < props.entityOptions.attributeCamera.length; j++) {
|
|
if (cameraList.value[i].id == props.entityOptions.attributeCamera[j].id) {
|
|
cameraList.value[i].checked = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
console.error(res.message)
|
|
}
|
|
})
|
|
}
|
|
|
|
let attributeSelect = ref([
|
|
{
|
|
name: '富文本',
|
|
value: '富文本',
|
|
key: 'richText'
|
|
},
|
|
{
|
|
name: '链接',
|
|
value: '链接',
|
|
key: 'link'
|
|
}
|
|
])
|
|
|
|
if (props.entityOptions.type === 'BillboardObject') {
|
|
attributeSelect.value.push(
|
|
{
|
|
name: 'IP摄像头',
|
|
value: 'IP摄像头',
|
|
key: 'camera'
|
|
},
|
|
// {
|
|
// name: 'ISC摄像头',
|
|
// value: 'ISC摄像头',
|
|
// key: 'isc'
|
|
// },
|
|
// {
|
|
// name: '传感器',
|
|
// value: '传感器',
|
|
// key: 'sensor'
|
|
// },
|
|
{
|
|
name: '全景图',
|
|
value: '全景图',
|
|
key: 'vr'
|
|
},
|
|
{
|
|
name: '物资',
|
|
value: '物资',
|
|
key: 'goods'
|
|
},
|
|
)
|
|
goodsSelect(1) // 物资
|
|
cameraSelect({page: cameraParams.value.page, limit: cameraParams.value.pageSize }) // ip摄像头
|
|
}
|
|
|
|
|
|
const addlinkInput = ref('')
|
|
const addvrInput = ref('')
|
|
const linkEditActive: any = ref({})
|
|
const vrEditActive: any = ref({})
|
|
|
|
const openRichTextEditor = () => {
|
|
eventBus.emit('openRichText', props.entityOptions.name, richTextContent.value, (val: any) => {
|
|
richTextContent.value = val
|
|
props.entityOptions.options.richTextContent = richTextContent.value
|
|
})
|
|
}
|
|
const _addLink = async () => {
|
|
if (addlinkInput.value) {
|
|
let link = {
|
|
name: '链接',
|
|
url: addlinkInput.value
|
|
}
|
|
attribute.value.link.content.push(link)
|
|
addlinkInput.value = ''
|
|
} else {
|
|
const options = {
|
|
properties: ['openFile', 'multiSelections'], // 允许选择多个文件
|
|
filters: [
|
|
{ name: '图片', extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg', 'bmp'] },
|
|
{ name: '音视频', extensions: ['mp4', 'mp3'] },
|
|
{ name: 'pdf', extensions: ['pdf'] },
|
|
]
|
|
};
|
|
if (ipcRenderer) {
|
|
ipcRenderer.send('open-directory-dialog', options);
|
|
// 监听主进程返回的结果
|
|
ipcRenderer.once('selectedItem', (event, filePaths) => {
|
|
if (filePaths.length > 0) {
|
|
filePaths.forEach((item) => {
|
|
attribute.value.link.content.push({
|
|
name: '链接',
|
|
url: item
|
|
})
|
|
})
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
// const pickerOpts = {
|
|
// types: [
|
|
// {
|
|
// description: '图片',
|
|
// accept:
|
|
// {
|
|
// 'image/jpg': ['.jpg', '.jpeg'],
|
|
// 'image/gif': ['.gif'],
|
|
// 'image/webp': ['.webp'],
|
|
// 'image/png': ['.png'],
|
|
// 'image/svg+xml': ['.svg'],
|
|
// 'image/x-ms-bmp': ['.bmp'],
|
|
// }
|
|
// },
|
|
// {
|
|
// description: '音视频',
|
|
// accept:
|
|
// {
|
|
// 'video/mp4': ['.mp4'],
|
|
// 'audio/mpeg': ['.mp3'],
|
|
// }
|
|
// },
|
|
// {
|
|
// description: 'pdf',
|
|
// accept:
|
|
// {
|
|
// 'application/pdf': ['.pdf'],
|
|
// }
|
|
// }
|
|
// ],
|
|
// excludeAcceptAllOption: true,
|
|
// multiple: true
|
|
// };
|
|
// if ((window as any).showOpenFilePicker) {
|
|
// const fileHandles = await (window as any).showOpenFilePicker(pickerOpts);
|
|
// // const files = await Promise.all(fileHandles.map(fileHandle => fileHandle.getFile()));
|
|
// // const dataTransfer = new DataTransfer();
|
|
// // handleFileImgInput(files, parentId, 'vr')
|
|
// }
|
|
}
|
|
|
|
// $sendElectronChanel('open-directory-dialog', (a: any,b: any)=>{
|
|
// console.log(a,b)
|
|
// })
|
|
|
|
}
|
|
}
|
|
const linkEdit = (index: any, item: { name: any; url: any; }) => {
|
|
let active = {
|
|
index: index,
|
|
name: item.name,
|
|
url: item.url
|
|
}
|
|
linkEditActive.value = active
|
|
}
|
|
const linkDelete = (index: any) => {
|
|
attribute.value.link.content.splice(index, 1)
|
|
}
|
|
const linkConfirmEdit = (index: string | number) => {
|
|
attribute.value.link.content[index] = {
|
|
name: linkEditActive.value.name,
|
|
url: linkEditActive.value.url
|
|
}
|
|
linkEditActive.value = {}
|
|
}
|
|
const linkCancelEdit = () => {
|
|
linkEditActive.value = {}
|
|
}
|
|
const _addRr = () => {
|
|
if (addvrInput.value) {
|
|
let link = {
|
|
name: '全景图',
|
|
url: addvrInput.value
|
|
}
|
|
attribute.value.vr.content.push(link)
|
|
addvrInput.value = ''
|
|
} else {
|
|
const options = {
|
|
properties: ['openFile', 'multiSelections'],
|
|
filters: [
|
|
{ name: '全景图', extensions: ['jpg'] },
|
|
]
|
|
};
|
|
ipcRenderer.send('open-directory-dialog', options);
|
|
// 监听主进程返回的结果
|
|
ipcRenderer.once('selectedItem', (event, filePaths) => {
|
|
if (filePaths.length > 0) {
|
|
filePaths.forEach((item) => {
|
|
attribute.value.link.content.push({
|
|
name: '全景图',
|
|
url: item
|
|
})
|
|
})
|
|
}
|
|
});
|
|
// document.getElementById('fileInputlink')?.click()
|
|
// eventBus.emit('defineClickAddLinkCb', (list: any[]) => {
|
|
// list.forEach((item: { previewUrl: any; }) => {
|
|
// attribute.value.vr.content.push({
|
|
// name: '全景图',
|
|
// url: item.previewUrl
|
|
// })
|
|
// })
|
|
// })
|
|
}
|
|
}
|
|
|
|
const vrEdit = (index: any, item: { name: any; url: any; }) => {
|
|
let active = {
|
|
index: index,
|
|
name: item.name,
|
|
url: item.url
|
|
}
|
|
vrEditActive.value = active
|
|
}
|
|
const vrDelete = (index: any) => {
|
|
attribute.value.vr.content.splice(index, 1)
|
|
}
|
|
const vrConfirmEdit = (index: string | number) => {
|
|
attribute.value.vr.content[index] = vrEditActive.value
|
|
vrEditActive.value = {}
|
|
}
|
|
const vrCancelEdit = () => {
|
|
vrEditActive.value = {}
|
|
}
|
|
|
|
const attributeChange = () => { }
|
|
|
|
const changeAttributeGoods = (item) => {
|
|
let flag = false
|
|
for (let m = props.entityOptions.attributeGoods.length - 1; m >= 0; m--) {
|
|
if ('id' in item) {
|
|
if (item.id === props.entityOptions.attributeGoods[m].id) {
|
|
flag = true
|
|
if (item.cnt) {
|
|
props.entityOptions.attributeGoods[m].cnt = item.cnt
|
|
}
|
|
else {
|
|
props.entityOptions.attributeGoods.splice(m, 1)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (!flag) {
|
|
if (!item.cnt) {
|
|
return
|
|
}
|
|
let data = {
|
|
id: item.id,
|
|
name: item.name,
|
|
cnt: item.cnt,
|
|
}
|
|
props.entityOptions.attributeGoods.push({ ...data })
|
|
}
|
|
}
|
|
const changeAttributeCamera = (e) => {
|
|
console.log(e)
|
|
props.entityOptions.attributeCamera = [{ ...e }]
|
|
for (let i = 0; i < cameraList.value.length; i++) {
|
|
if (cameraList.value[i].id !== e.id) {
|
|
cameraList.value[i].checked = false
|
|
}
|
|
}
|
|
// if (e.checked) {
|
|
// // 只选中一个
|
|
// props.entityOptions.attributeCamera = [{...e}]
|
|
// for (let i = 0; i < cameraList.value.length; i++) {
|
|
// if (cameraList.value[i].deviceId !== e.deviceId) {
|
|
// cameraList.value[i].checked = false
|
|
// }
|
|
// }
|
|
// }
|
|
// else {
|
|
// let newArray = that.attributeCamera.filter((item) => {
|
|
// if ('deviceId' in data.data.list[i]) {
|
|
// return item.deviceId !== data.data.list[i].deviceId
|
|
// }
|
|
// })
|
|
// that.attributeCamera = newArray
|
|
// }
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss"></style>
|