fix: bug#28560【通知配置】微信-企业消息的同步用户页面,列表字段展示错误,【钉钉用户名】需改为【企业微信用户名】
* feat: 社区版功能过滤 * fix: bug#28523 【设备】设备运行状态界面,设备在线状态下,点击断开链接,事件展示错误 * fix: bug#28521 产品(设备)需按照当前产品选择协议来确定是否展示远程升级 * feat: 2.2新增功能社区版功能屏蔽 * feat: 场景联动定时场景按日历社区版屏蔽 * fix: bug#28524 【产品】产品选择设备接入网关,有多个配置时,只展示了一个 * fix: 修改iot平台主题色 * fix: 优化设备接入配置 * fix: 兼容2.1版本创建的菜单数据 * fix: 菜单配置兼容2.1菜单 * fix: bug#28524 【产品】产品选择设备接入网关,有多个配置时,只展示了一个 * fix: bug#28520【设备】当配置未开启时,前端应不展示配置按钮 * fix: bug#28533仪表盘本年流量消耗界面展示需优化 * fix: bug#28520、28534【设备】设备详情-物模型-其他配置 在点击配置时界面提示错误、【设备】当配置未开启时,前端应不展示配置按钮 * fix: bug#28531【设备】详情中查看预处理数据时提示错误 * fix: bug#28545【菜单管理】新增菜单,权限控制处无法正常加载出权限 * fix: 菜单配置->菜单权限同步功能 * fix: bug#28520【设备】当配置未开启时,前端应不展示配置按钮 * fix(media): bug#28595屏蔽固定地址通道列表的厂商字段 * fix(NoticeRule): 文字组织替换部门 * fix(Alarm): bug#28571手动触发展示说明 * fix(media): bug#28553界面展示异常 * fix(iotCard): bug#28567 * fix(media): bug#28595屏蔽固定地址通道列表的厂商字段 * fix: bug#28560【通知配置】微信-企业消息的同步用户页面,列表字段展示错误,【钉钉用户名】需改为【企业微信用户名】 * fix: bug#28544【通知配置】用户自己创建的数据,没有权限调试,报错:暂无权限,请联系管理员! * fix: bug#28549【采集器】在点位进行批量操作时,开启推送控制,进行保存异常 * fix: bug#28540【组织管理】设备资产分配页,设备列表形式展示,资产权限显示不完整 * fix: bug#28537【产品】新增的网关设备,接入方式选择"边缘网关接入"时,物模型中功能定义界面展示异常 * fix: bug#28550【远程升级】升级任务中的任务详情列表中文案修改 * fix: bug#28551【通知模版】和【通知配置】两者保存的查询条件共用了 * fix: bug#28560【通知配置】微信-企业消息的同步用户页面,列表字段展示错误,【钉钉用户名】需改为【企业微信用户名】
This commit is contained in:
parent
3da54bb59b
commit
2b3e3280ac
|
@ -1,7 +1,4 @@
|
|||
export default {
|
||||
theme: {
|
||||
'primary-color': '#1677FF',
|
||||
},
|
||||
logo: '/favicon.ico', // 浏览器标签页logo
|
||||
title: 'Jetlinks', // 浏览器标签页title
|
||||
layout: {
|
||||
|
|
|
@ -33,7 +33,7 @@ watch(() => JSON.stringify(route.query || {}), () => {
|
|||
|
||||
ConfigProvider.config({
|
||||
theme: {
|
||||
primaryColor: "#315efb"
|
||||
primaryColor: "#1677FF"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -662,7 +662,7 @@ export const queryDeviceThreshold = (productId: string, deviceId: string, prope
|
|||
* @param productId
|
||||
* @param propertyId
|
||||
*/
|
||||
export const queryProductThreshold = (productId: string, propertyId: string) => server.get(`/message/preprocessor/product/${productId}/property/${propertyId}`)
|
||||
export const queryProductThreshold = (productId: string, propertyId: string,hiddenError:boolean) => server.get(`/message/preprocessor/product/${productId}/property/${propertyId}`,{},{},hiddenError)
|
||||
|
||||
/**
|
||||
* 阈值限制-删除产品物模型的阈值
|
||||
|
|
|
@ -35,8 +35,8 @@ const defaultOwnParams = [
|
|||
{
|
||||
terms: [
|
||||
{
|
||||
value: "%show\":true%",
|
||||
termType: "like",
|
||||
value: "%show\":false%",
|
||||
termType: "nlike",
|
||||
column: "options"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia';
|
|||
import { systemVersion } from '@/api/comm'
|
||||
import { useMenuStore } from './menu'
|
||||
import {getDetails_api, settingDetail} from '@/api/system/basis';
|
||||
import { queryProductThreshold } from '@/api/device/instance'
|
||||
import type { ConfigInfoType } from '@/views/system/Basis/typing';
|
||||
import { LocalStore } from '@/utils/comm'
|
||||
import { SystemConst } from '@/utils/consts'
|
||||
|
@ -24,6 +25,7 @@ type SystemStateType = {
|
|||
pure: boolean
|
||||
}
|
||||
calendarTagColor:Map<string,string>
|
||||
showThreshold:boolean
|
||||
}
|
||||
|
||||
export const useSystem = defineStore('system', {
|
||||
|
@ -42,11 +44,13 @@ export const useSystem = defineStore('system', {
|
|||
collapsed: false,
|
||||
pure: false
|
||||
},
|
||||
calendarTagColor:new Map()
|
||||
calendarTagColor:new Map(),
|
||||
showThreshold: true
|
||||
}),
|
||||
actions: {
|
||||
getSystemVersion(): Promise<any[]> {
|
||||
this.getSystemConfig();
|
||||
this.getThreshold()
|
||||
return new Promise(async (res, rej) => {
|
||||
const resp = await systemVersion()
|
||||
if (resp.success && resp.result) {
|
||||
|
@ -100,6 +104,13 @@ export const useSystem = defineStore('system', {
|
|||
this.calendarTagColor.set(i, answer.result[i]);
|
||||
});
|
||||
}
|
||||
},
|
||||
async getThreshold(){
|
||||
await queryProductThreshold('test','test',true).catch((res:any)=>{
|
||||
if(res.response.status === 404){
|
||||
this.showThreshold = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
@import 'jetlinks-ui-components/es/style/variable.less';
|
||||
@import './scrollbar.less';
|
||||
|
||||
html {
|
||||
--ant-primary-color: #1677FF !important;
|
||||
}
|
||||
|
||||
.ellipsisFn(@num: 1, @width: 100%) {
|
||||
display: -webkit-box;
|
||||
max-width: @width;
|
||||
|
|
|
@ -90,11 +90,12 @@ export const patch = function <T>(url: string, data = {}, ext: any = {}) {
|
|||
* @param {Object} [ext] 扩展参数
|
||||
* @returns {AxiosInstance}
|
||||
*/
|
||||
export const get = function <T>(url: string, params = {}, ext?: any) {
|
||||
export const get = function <T>(url: string, params = {}, ext?: any, _hideError = false) {
|
||||
return request<any, AxiosResponseRewrite<T>>({
|
||||
method: 'GET',
|
||||
url,
|
||||
params,
|
||||
_hideError,
|
||||
...ext
|
||||
})
|
||||
}
|
||||
|
@ -200,7 +201,7 @@ const errorHandler = (error: any) => {
|
|||
path: LoginPath
|
||||
})
|
||||
}, 0)
|
||||
} else if (status === 404) {
|
||||
} else if (status === 404 && !error.config._hideError) {
|
||||
const data = error?.response?.data
|
||||
const message = error?.response?.data?.message || `${data?.error} ${data?.path}`
|
||||
showNotification(error?.code, message, '404')
|
||||
|
|
|
@ -570,10 +570,18 @@ const onCheckChange = () => {
|
|||
};
|
||||
|
||||
const handleBatchDelete = () => {
|
||||
if (!_selectedRowKeys.value.length) {
|
||||
onlyMessage('至少选择一条数据', 'error');
|
||||
return
|
||||
}
|
||||
handleDelete();
|
||||
};
|
||||
|
||||
const handleBatchUpdate = () => {
|
||||
if (!_selectedRowKeys.value.length) {
|
||||
onlyMessage('至少选择一条数据', 'error');
|
||||
return
|
||||
}
|
||||
const dataSet = new Set(_selectedRowKeys.value);
|
||||
const dataMap = new Map();
|
||||
tableRef?.value?._dataSource.forEach((i: any) => {
|
||||
|
|
|
@ -19,9 +19,9 @@ const systemNotice = [
|
|||
},
|
||||
{
|
||||
provider: 'alarm-org',
|
||||
name: '部门告警',
|
||||
name: '组织告警',
|
||||
description:
|
||||
'当部门类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
'当组织类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
},
|
||||
{
|
||||
provider: 'alarm-other',
|
||||
|
|
|
@ -170,7 +170,7 @@ const columns = [
|
|||
dataIndex: 'completeTime',
|
||||
},
|
||||
{
|
||||
title: '设备版本',
|
||||
title: '固件版本',
|
||||
key: 'version',
|
||||
dataIndex: 'version',
|
||||
width: 100,
|
||||
|
|
|
@ -68,6 +68,11 @@ const events: any = ref(undefined);
|
|||
watch(
|
||||
() => current.value,
|
||||
(value) => {
|
||||
tabList.value = [{
|
||||
key: 'property',
|
||||
tab: '属性',
|
||||
type: 'property',
|
||||
}]
|
||||
const metadata = JSON.parse(value?.metadata || '{}');
|
||||
properties.value = metadata.properties;
|
||||
events.value = metadata.events;
|
||||
|
|
|
@ -134,9 +134,11 @@ import { useMenuStore } from '@/store/menu';
|
|||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import { EventEmitter } from '@/utils/utils';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
import { useSystem } from '@/store/system';
|
||||
|
||||
const menuStory = useMenuStore();
|
||||
|
||||
const { showThreshold } = useSystem();
|
||||
const route = useRoute();
|
||||
const routerParams = useRouterParams();
|
||||
const instanceStore = useInstanceStore();
|
||||
|
@ -212,19 +214,24 @@ const getStatus = (id: string) => {
|
|||
|
||||
const getDetail = () => {
|
||||
const keys = list.value.map((i) => i.key);
|
||||
if (permissionStore.hasPermission('rule-engine/Alarm/Log:view')) {
|
||||
if (permissionStore.hasPermission('rule-engine/Alarm/Log:view') && isNoCommunity && showThreshold) {
|
||||
list.value.push({
|
||||
key: 'AlarmRecord',
|
||||
tab: '预处理数据',
|
||||
});
|
||||
}
|
||||
if (permissionStore.hasPermission('iot-card/CardManagement:view')) {
|
||||
if (permissionStore.hasPermission('iot-card/CardManagement:view') && isNoCommunity) {
|
||||
list.value.push({
|
||||
key: 'CardManagement',
|
||||
tab: '物联网卡',
|
||||
});
|
||||
}
|
||||
if (permissionStore.hasPermission('device/Firmware:view')) {
|
||||
if (
|
||||
permissionStore.hasPermission('device/Firmware:view') &&
|
||||
instanceStore.current?.features?.find(
|
||||
(item: any) => item?.id === 'supportFirmware',
|
||||
) && isNoCommunity
|
||||
) {
|
||||
list.value.push({
|
||||
key: 'Firmware',
|
||||
tab: '远程升级',
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<!-- 设备接入 -->
|
||||
<template>
|
||||
<div v-if="access.id === undefined || null" style='margin-top: 20%; transform: translateY(-50%);'>
|
||||
<div
|
||||
v-if="access.id === undefined || null"
|
||||
style="margin-top: 20%; transform: translateY(-50%)"
|
||||
>
|
||||
<j-empty :image="simpleImage">
|
||||
<template #description>
|
||||
<span
|
||||
|
@ -25,7 +28,7 @@
|
|||
type="primary"
|
||||
size="small"
|
||||
:tooltip="{
|
||||
title: tooltip
|
||||
title: tooltip,
|
||||
}"
|
||||
:disabled="checkDisabled"
|
||||
ghost
|
||||
|
@ -74,66 +77,80 @@
|
|||
<div v-else>{{ '暂无连接信息' }}</div>
|
||||
</div>
|
||||
<!-- 产品类型 -->
|
||||
<j-form ref="pluginFormRef" :model="productData" layout="vertical" v-if='productTypes.length'>
|
||||
<j-form-item name='id' label='产品类型' :rules='[{ required: true, message: "请选择产品类型"}]'>
|
||||
<j-select
|
||||
v-model:value='productData.id'
|
||||
:options='productTypes'
|
||||
@change='productTypeChange'
|
||||
placeholder='请选择产品类型'
|
||||
/>
|
||||
</j-form-item>
|
||||
|
||||
<j-form
|
||||
ref="pluginFormRef"
|
||||
:model="productData"
|
||||
layout="vertical"
|
||||
v-if="productTypes.length"
|
||||
>
|
||||
<j-form-item
|
||||
name="id"
|
||||
label="产品类型"
|
||||
:rules="[{ required: true, message: '请选择产品类型' }]"
|
||||
>
|
||||
<j-select
|
||||
v-model:value="productData.id"
|
||||
:options="productTypes"
|
||||
@change="productTypeChange"
|
||||
placeholder="请选择产品类型"
|
||||
/>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
<!-- 其它接入配置 -->
|
||||
<Title
|
||||
v-if="metadata?.name"
|
||||
:data="metadata?.name"
|
||||
class="config"
|
||||
>
|
||||
<template #extra>
|
||||
<j-tooltip title="此配置来自于产品接入方式所选择的协议">
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</Title>
|
||||
<j-form ref="formRef" :model="formData.data" layout="vertical">
|
||||
<j-form-item
|
||||
:name="item.property"
|
||||
v-for="item in metadata?.properties || []"
|
||||
:key="item"
|
||||
:label="item.name"
|
||||
:rules="[
|
||||
{
|
||||
required: !!item?.type?.expands?.required,
|
||||
message: `${
|
||||
item.type.type === 'enum' || 'boolean'
|
||||
? '请选择'
|
||||
: '请输入'
|
||||
}${item.name}`,
|
||||
},
|
||||
]"
|
||||
<div v-for="(i,index) in metadata">
|
||||
<Title v-if="i?.name" :data="i?.name" class="config">
|
||||
<template #extra>
|
||||
<j-tooltip
|
||||
title="此配置来自于产品接入方式所选择的协议"
|
||||
>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</Title>
|
||||
<j-form
|
||||
ref="formRef"
|
||||
:model="formData.data"
|
||||
layout="vertical"
|
||||
>
|
||||
<j-input
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'string'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input>
|
||||
<j-input-password
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'password'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input-password>
|
||||
<j-select
|
||||
placeholder="请选择"
|
||||
v-if="item.type.type === 'enum' || item.type.type === 'boolean'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
:options="getOptions(item)"
|
||||
<j-form-item
|
||||
:name="item.property"
|
||||
v-for="item in i?.properties || []"
|
||||
:key="item"
|
||||
:label="item.name"
|
||||
:rules="[
|
||||
{
|
||||
required: !!item?.type?.expands?.required,
|
||||
message: `${
|
||||
item.type.type === 'enum' || 'boolean'
|
||||
? '请选择'
|
||||
: '请输入'
|
||||
}${item.name}`,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<!-- <j-select-option
|
||||
<j-input
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'string'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input>
|
||||
<j-input-password
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'password'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input-password>
|
||||
<j-select
|
||||
placeholder="请选择"
|
||||
v-if="
|
||||
item.type.type === 'enum' ||
|
||||
item.type.type === 'boolean'
|
||||
"
|
||||
v-model:value="formData.data[item.property]"
|
||||
:options="getOptions(item)"
|
||||
>
|
||||
<!-- <j-select-option
|
||||
v-for="el in item?.type?.type === 'enum' &&
|
||||
item?.type?.elements
|
||||
? item?.type?.elements
|
||||
|
@ -143,10 +160,19 @@
|
|||
>
|
||||
{{ el.text }}
|
||||
</j-select-option> -->
|
||||
</j-select>
|
||||
<j-input-number v-if="['int','float','double','long'].includes(item.type.type)" v-model:value="formData.data[item.property]" placeholder="请输入"></j-input-number>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-select>
|
||||
<j-input-number
|
||||
v-if="
|
||||
['int', 'float', 'double', 'long'].includes(
|
||||
item.type.type,
|
||||
)
|
||||
"
|
||||
v-model:value="formData.data[item.property]"
|
||||
placeholder="请输入"
|
||||
></j-input-number>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</div>
|
||||
<Title data="存储策略">
|
||||
<template #extra>
|
||||
<j-tooltip
|
||||
|
@ -175,7 +201,7 @@
|
|||
type="primary"
|
||||
@click="submitDevice"
|
||||
hasPermission="device/Instance:update"
|
||||
:loading='submitLoading'
|
||||
:loading="submitLoading"
|
||||
>保存</PermissionButton
|
||||
>
|
||||
</j-col>
|
||||
|
@ -254,26 +280,30 @@
|
|||
</div>
|
||||
<!-- 选择设备 -->
|
||||
<AccessModal
|
||||
v-if='visible'
|
||||
:product-id='productStore.current.id'
|
||||
:deviceType='productStore.current.deviceType'
|
||||
:accessId='accessId'
|
||||
:providersList='dataSource'
|
||||
@cancel=' visible = false'
|
||||
@submit='checkAccess'
|
||||
v-if="visible"
|
||||
:product-id="productStore.current.id"
|
||||
:deviceType="productStore.current.deviceType"
|
||||
:accessId="accessId"
|
||||
:providersList="dataSource"
|
||||
@cancel="visible = false"
|
||||
@submit="checkAccess"
|
||||
/>
|
||||
<!-- 物模型处理方式 -->
|
||||
<MetaDataModal
|
||||
v-if="metadataVisible"
|
||||
:metadata="productData.metadata"
|
||||
:access="access"
|
||||
:data="metadataModalCacheData"
|
||||
@cancel="
|
||||
() => {
|
||||
(metadataVisible = false), (metadataModalCacheData = {});
|
||||
}
|
||||
"
|
||||
@submit="MetaDataModalSubmit"
|
||||
/>
|
||||
<!-- 物模型处理方式 -->
|
||||
<MetaDataModal
|
||||
v-if='metadataVisible'
|
||||
:metadata='productData.metadata'
|
||||
:access='access'
|
||||
:data='metadataModalCacheData'
|
||||
@cancel=' () => { metadataVisible = false, metadataModalCacheData = {}}'
|
||||
@submit='MetaDataModalSubmit'
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name='AccessConfig'>
|
||||
<script lang="ts" setup name="AccessConfig">
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { ConfigMetadata } from '@/views/device/Product/typings';
|
||||
import { Empty } from 'jetlinks-ui-components';
|
||||
|
@ -282,20 +312,21 @@ import { usePermissionStore } from '@/store/permission';
|
|||
import { steps, steps1 } from './util';
|
||||
import './index.less';
|
||||
import {
|
||||
getProviders,
|
||||
_deploy,
|
||||
_undeploy,
|
||||
queryList,
|
||||
getConfigView,
|
||||
getConfigMetadata,
|
||||
productGuide,
|
||||
productGuideSave,
|
||||
getStoragList,
|
||||
saveDevice,
|
||||
updateDevice,
|
||||
detail,
|
||||
modify, getAccessConfig
|
||||
} from '@/api/device/product'
|
||||
getProviders,
|
||||
_deploy,
|
||||
_undeploy,
|
||||
queryList,
|
||||
getConfigView,
|
||||
getConfigMetadata,
|
||||
productGuide,
|
||||
productGuideSave,
|
||||
getStoragList,
|
||||
saveDevice,
|
||||
updateDevice,
|
||||
detail,
|
||||
modify,
|
||||
getAccessConfig,
|
||||
} from '@/api/device/product';
|
||||
|
||||
import Driver from 'driver.js';
|
||||
import 'driver.js/dist/driver.min.css';
|
||||
|
@ -304,16 +335,20 @@ import type { TableColumnType } from 'ant-design-vue';
|
|||
import { useMenuStore } from '@/store/menu';
|
||||
import _ from 'lodash-es';
|
||||
import { accessConfigTypeFilter } from '@/utils/setting';
|
||||
import AccessModal from './accessModal.vue'
|
||||
import MetaDataModal from './metadataModal.vue'
|
||||
import { getPluginData, getProductByPluginId, savePluginData } from '@/api/link/plugin'
|
||||
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig'
|
||||
import AccessModal from './accessModal.vue';
|
||||
import MetaDataModal from './metadataModal.vue';
|
||||
import {
|
||||
getPluginData,
|
||||
getProductByPluginId,
|
||||
savePluginData,
|
||||
} from '@/api/link/plugin';
|
||||
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import { pick } from 'lodash-es';
|
||||
|
||||
const productStore = useProductStore();
|
||||
const tableRef = ref();
|
||||
const formRef = ref();
|
||||
const formRef = ref([]);
|
||||
const menuStore = useMenuStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const render = new marked.Renderer();
|
||||
|
@ -326,9 +361,9 @@ marked.setOptions({
|
|||
const simpleImage = ref(Empty.PRESENTED_IMAGE_SIMPLE);
|
||||
const visible = ref<boolean>(false);
|
||||
const access = ref<Record<string, any>>({});
|
||||
const accessId = ref<string>(productStore.current.accessId)
|
||||
const accessId = ref<string>(productStore.current.accessId);
|
||||
const config = ref<any>({});
|
||||
const metadata = ref<ConfigMetadata>({ properties: [] });
|
||||
const metadata = ref<ConfigMetadata[]>([{ properties: [] }]);
|
||||
const dataSource = ref<string[]>([]);
|
||||
const storageList = ref<any[]>([]);
|
||||
const markdownToHtml = shallowRef('');
|
||||
|
@ -350,7 +385,7 @@ const formData = reactive<Record<string, any>>({
|
|||
data: productStore.current?.configuration || {},
|
||||
});
|
||||
//获取物模型下拉选项
|
||||
const getOptions = (i:any) =>{
|
||||
const getOptions = (i: any) => {
|
||||
if (i.type.type === 'enum') {
|
||||
return (i.type?.elements || []).map((item) => {
|
||||
return {
|
||||
|
@ -367,26 +402,26 @@ const getOptions = (i:any) =>{
|
|||
{
|
||||
label: i.type?.trueText,
|
||||
value: i.type?.trueValue,
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const fun = () =>{
|
||||
console.log(formData.data,productStore.current?.configuration)
|
||||
}
|
||||
fun()
|
||||
};
|
||||
const fun = () => {
|
||||
console.log(formData.data, productStore.current?.configuration);
|
||||
};
|
||||
fun();
|
||||
// 产品类型
|
||||
const productTypes = ref([])
|
||||
const productTypes = ref([]);
|
||||
const productData = reactive({
|
||||
id: undefined,
|
||||
metadata: {} // 物模型
|
||||
})
|
||||
const pluginFormRef = ref()
|
||||
const metadataVisible = ref(false)
|
||||
const metadataModalCacheData = ref()
|
||||
id: undefined,
|
||||
metadata: {}, // 物模型
|
||||
});
|
||||
const pluginFormRef = ref();
|
||||
const metadataVisible = ref(false);
|
||||
const metadataModalCacheData = ref();
|
||||
|
||||
const submitLoading = ref(false)
|
||||
const submitLoading = ref(false);
|
||||
/**
|
||||
* 显示弹窗
|
||||
*/
|
||||
|
@ -554,44 +589,48 @@ const queryAccessDetail = async (id: string) => {
|
|||
}).then((res: any) => {
|
||||
if (res.status === 200) {
|
||||
access.value = res.result.data[0];
|
||||
if (access.value?.transportDetail?.metadata) {
|
||||
const metadata = JSON.parse(access.value?.transportDetail?.metadata)
|
||||
productData.metadata = pick(metadata,['functions','properties','events','tags'])
|
||||
}
|
||||
if (access.value?.transportDetail?.metadata) {
|
||||
const metadata = JSON.parse(
|
||||
access.value?.transportDetail?.metadata,
|
||||
);
|
||||
productData.metadata = pick(metadata, [
|
||||
'functions',
|
||||
'properties',
|
||||
'events',
|
||||
'tags',
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleColumns = () => {
|
||||
const Group = {
|
||||
title: '分组',
|
||||
dataIndex: 'group',
|
||||
key: 'group',
|
||||
ellipsis: true,
|
||||
align: 'center',
|
||||
width: 100,
|
||||
customCell: (record: any, rowIndex: number) => {
|
||||
const obj = {
|
||||
children: record,
|
||||
rowSpan: 0,
|
||||
};
|
||||
const list = config.value?.routes || [];
|
||||
const Group = {
|
||||
title: '分组',
|
||||
dataIndex: 'group',
|
||||
key: 'group',
|
||||
ellipsis: true,
|
||||
align: 'center',
|
||||
width: 100,
|
||||
customCell: (record: any, rowIndex: number) => {
|
||||
const obj = {
|
||||
children: record,
|
||||
rowSpan: 0,
|
||||
};
|
||||
const list = config.value?.routes || [];
|
||||
|
||||
const arr = list.filter(
|
||||
(res: any) => res.group === record.group,
|
||||
);
|
||||
const arr = list.filter((res: any) => res.group === record.group);
|
||||
|
||||
const isRowIndex =
|
||||
rowIndex === 0 ||
|
||||
list[rowIndex - 1].group !== record.group;
|
||||
isRowIndex && (obj.rowSpan = arr.length);
|
||||
const isRowIndex =
|
||||
rowIndex === 0 || list[rowIndex - 1].group !== record.group;
|
||||
isRowIndex && (obj.rowSpan = arr.length);
|
||||
|
||||
return obj;
|
||||
},
|
||||
};
|
||||
columnsMQTT.value = [Group, ...ColumnsMQTT];
|
||||
columnsHTTP.value = [Group, ...ColumnsHTTP];
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
};
|
||||
columnsMQTT.value = [Group, ...ColumnsMQTT];
|
||||
columnsHTTP.value = [Group, ...ColumnsHTTP];
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询协议信息
|
||||
|
@ -603,7 +642,7 @@ const getConfigDetail = (
|
|||
getConfigView(messageProtocol, transportProtocol).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
config.value = resp.result;
|
||||
handleColumns()
|
||||
handleColumns();
|
||||
if (config.value?.document) {
|
||||
markdownToHtml.value = marked(config.value.document);
|
||||
}
|
||||
|
@ -640,56 +679,73 @@ const getGuide = async (isDriver1: boolean = false) => {
|
|||
};
|
||||
|
||||
const checkAccess = async (data: any) => {
|
||||
console.log(data)
|
||||
visible.value = false
|
||||
accessId.value = data.access.id
|
||||
access.value = data.access
|
||||
config.value = data.access?.transportDetail || {}
|
||||
productTypes.value = []
|
||||
productData.id = undefined
|
||||
productData.metadata = {}
|
||||
metadata.value = data.metadata?.[0] || {
|
||||
properties: []
|
||||
}
|
||||
if (metadata.value?.properties) {
|
||||
metadata.value?.properties.forEach((item) => {
|
||||
if (
|
||||
item.name === '流传输模式' &&
|
||||
(!productStore.current?.configuration ||
|
||||
!productStore.current?.configuration.hasOwnProperty(
|
||||
item.property,
|
||||
))
|
||||
) {
|
||||
formData.data[item.property] =
|
||||
item.type.expands?.defaultValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (data.access.channel === 'plugin') { // 插件设备
|
||||
markdownToHtml.value = ''
|
||||
productTypes.value = data.productTypes.map(item => ({ ...item, label: item.name, value: item.id}))
|
||||
} else {
|
||||
handleColumns()
|
||||
markdownToHtml.value = config.value?.document ? marked(config.value.document) : '';
|
||||
getGuide(!!data.metadata.length); //
|
||||
|
||||
if (data.access?.transportDetail?.metadata) {
|
||||
const metadata = JSON.parse(data.access?.transportDetail?.metadata)
|
||||
productData.metadata = pick(metadata,['functions','properties','events','tags'])
|
||||
visible.value = false;
|
||||
accessId.value = data.access.id;
|
||||
access.value = data.access;
|
||||
config.value = data.access?.transportDetail || {};
|
||||
productTypes.value = [];
|
||||
productData.id = undefined;
|
||||
productData.metadata = {};
|
||||
metadata.value = data.metadata || [
|
||||
{
|
||||
properties: [],
|
||||
},
|
||||
];
|
||||
if (metadata.value.length) {
|
||||
metadata.value.forEach((i: any) => {
|
||||
i?.properties.forEach((item: any) => {
|
||||
if (
|
||||
item.name === '流传输模式' &&
|
||||
(!productStore.current?.configuration ||
|
||||
!productStore.current?.configuration.hasOwnProperty(
|
||||
item.property,
|
||||
))
|
||||
) {
|
||||
formData.data[item.property] =
|
||||
item.type.expands?.defaultValue;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.access.channel === 'plugin') {
|
||||
// 插件设备
|
||||
markdownToHtml.value = '';
|
||||
productTypes.value = data.productTypes.map((item) => ({
|
||||
...item,
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
} else {
|
||||
handleColumns();
|
||||
markdownToHtml.value = config.value?.document
|
||||
? marked(config.value.document)
|
||||
: '';
|
||||
getGuide(!!data.metadata.length); //
|
||||
|
||||
if (data.access?.transportDetail?.metadata) {
|
||||
const metadata = JSON.parse(data.access?.transportDetail?.metadata);
|
||||
productData.metadata = pick(metadata, [
|
||||
'functions',
|
||||
'properties',
|
||||
'events',
|
||||
'tags',
|
||||
]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const productTypeChange = (id: string, items: any) => {
|
||||
productData.metadata = items?.metadata ? pick(items.metadata,['functions','properties','events','tags']) : {}
|
||||
}
|
||||
productData.metadata = items?.metadata
|
||||
? pick(items.metadata, ['functions', 'properties', 'events', 'tags'])
|
||||
: {};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取协议类型名称
|
||||
*/
|
||||
const getProvidersList = async () => {
|
||||
const res: any = await getProviders();
|
||||
dataSource.value = res.result;
|
||||
const res: any = await getProviders();
|
||||
dataSource.value = res.result;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -699,22 +755,26 @@ const getData = async (accessId?: string) => {
|
|||
const _accessId = accessId || productStore.current?.accessId;
|
||||
if (productStore.current?.id) {
|
||||
getConfigMetadata(productStore.current?.id).then((resp: any) => {
|
||||
metadata.value = (resp?.result[0] as ConfigMetadata) || {
|
||||
properties: [],
|
||||
};
|
||||
metadata.value = resp?.result || [
|
||||
{
|
||||
properties: [],
|
||||
},
|
||||
];
|
||||
// 流传输模式 初始为udp模式
|
||||
if (metadata.value?.properties) {
|
||||
metadata.value?.properties.forEach((item) => {
|
||||
if (
|
||||
item.name === '流传输模式' &&
|
||||
(!productStore.current?.configuration ||
|
||||
!productStore.current?.configuration.hasOwnProperty(
|
||||
item.property,
|
||||
))
|
||||
) {
|
||||
formData.data[item.property] =
|
||||
item.type.expands?.defaultValue;
|
||||
}
|
||||
if (metadata.value.length) {
|
||||
metadata.value.forEach((i: any) => {
|
||||
i?.properties.forEach((item: any) => {
|
||||
if (
|
||||
item.name === '流传输模式' &&
|
||||
(!productStore.current?.configuration ||
|
||||
!productStore.current?.configuration.hasOwnProperty(
|
||||
item.property,
|
||||
))
|
||||
) {
|
||||
formData.data[item.property] =
|
||||
item.type.expands?.defaultValue;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (accessId) {
|
||||
|
@ -729,31 +789,45 @@ const getData = async (accessId?: string) => {
|
|||
// if (metadataResp.success) {
|
||||
// metadata.value = (metadataResp.result?.[0] as ConfigMetadata[]) || [];
|
||||
// }
|
||||
queryAccessDetail(_accessId);
|
||||
if (productStore.current?.accessProvider === 'plugin_gateway') {
|
||||
queryPluginAccessDetail(_accessId).then(async res => { //
|
||||
if (res.success) {
|
||||
const pluginRes = await getPluginData('product', _accessId, productStore.current?.id)
|
||||
const resp = await getProductByPluginId(res.result.channelId).catch(() => ({ success: false, result: []}))
|
||||
if (resp.success) {
|
||||
productTypes.value = resp.result.map(item => {
|
||||
if (pluginRes?.result?.externalId === item.id) {
|
||||
productData.id = pluginRes?.result?.externalId
|
||||
productData.metadata = pick(item.metadata,['functions','properties','events','tags'])
|
||||
queryAccessDetail(_accessId);
|
||||
if (productStore.current?.accessProvider === 'plugin_gateway') {
|
||||
queryPluginAccessDetail(_accessId).then(async (res) => {
|
||||
//
|
||||
if (res.success) {
|
||||
const pluginRes = await getPluginData(
|
||||
'product',
|
||||
_accessId,
|
||||
productStore.current?.id,
|
||||
);
|
||||
const resp = await getProductByPluginId(
|
||||
res.result.channelId,
|
||||
).catch(() => ({ success: false, result: [] }));
|
||||
if (resp.success) {
|
||||
productTypes.value = resp.result.map((item) => {
|
||||
if (pluginRes?.result?.externalId === item.id) {
|
||||
productData.id = pluginRes?.result?.externalId;
|
||||
productData.metadata = pick(item.metadata, [
|
||||
'functions',
|
||||
'properties',
|
||||
'events',
|
||||
'tags',
|
||||
]);
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
return { ...item, label: item.name, value: item.id }
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
getConfigDetail(
|
||||
productStore.current?.messageProtocol || '',
|
||||
productStore.current?.transportProtocol || '',
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
getConfigDetail(
|
||||
productStore.current?.messageProtocol || '',
|
||||
productStore.current?.transportProtocol || '',
|
||||
);
|
||||
}
|
||||
}
|
||||
getStoragList().then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
|
@ -766,100 +840,106 @@ const getData = async (accessId?: string) => {
|
|||
* 保存设备接入
|
||||
*/
|
||||
const submitDevice = async () => {
|
||||
if (pluginFormRef.value) { // 插件
|
||||
const pluginRef = await pluginFormRef.value.validate();
|
||||
if (!pluginRef) return
|
||||
if (pluginFormRef.value) {
|
||||
// 插件
|
||||
const pluginRef = await pluginFormRef.value.validate();
|
||||
if (!pluginRef) return;
|
||||
}
|
||||
|
||||
const res = await formRef.value.validate();
|
||||
if (!res) return
|
||||
const allValidate = formRef.value.map((item:any)=>{
|
||||
return item?.validate()
|
||||
})
|
||||
const res = await Promise.all(allValidate)
|
||||
// const res = await formRef.value.validate();
|
||||
if (!res) return;
|
||||
const values = { storePolicy: form.storePolicy, ...formData.data };
|
||||
const id = productStore.current?.id;
|
||||
// 该产品是否有物模型,有则弹窗进行处理
|
||||
const _metadata = JSON.parse(productStore.current?.metadata || '{}')
|
||||
const _metadata = JSON.parse(productStore.current?.metadata || '{}');
|
||||
if (
|
||||
(_metadata.properties?.length ||
|
||||
_metadata.events?.length ||
|
||||
_metadata.functions?.length ||
|
||||
_metadata.tags?.length
|
||||
) &&
|
||||
(
|
||||
productData.metadata?.properties?.length ||
|
||||
productData.metadata?.events?.length ||
|
||||
productData.metadata?.functions?.length ||
|
||||
productData.metadata?.tags?.length
|
||||
)
|
||||
(_metadata.properties?.length ||
|
||||
_metadata.events?.length ||
|
||||
_metadata.functions?.length ||
|
||||
_metadata.tags?.length) &&
|
||||
(productData.metadata?.properties?.length ||
|
||||
productData.metadata?.events?.length ||
|
||||
productData.metadata?.functions?.length ||
|
||||
productData.metadata?.tags?.length)
|
||||
) {
|
||||
metadataModalCacheData.value = {
|
||||
id,
|
||||
values,
|
||||
productTypeId: productData.id
|
||||
}
|
||||
metadataVisible.value = true
|
||||
metadataModalCacheData.value = {
|
||||
id,
|
||||
values,
|
||||
productTypeId: productData.id,
|
||||
};
|
||||
metadataVisible.value = true;
|
||||
} else {
|
||||
updateAccessData(id, values)
|
||||
updateAccessData(id, values);
|
||||
}
|
||||
};
|
||||
|
||||
const updateAccessData = async (id: string, values: any) => {
|
||||
const result: any = {};
|
||||
// flatObj(values, result);
|
||||
// const { storePolicy, ...extra } = result;
|
||||
const { storePolicy, ...extra } = values
|
||||
// 产品有物模型,设备接入没有,取产品物模型;设备接入有物模型,产品没有,取设备接入的物模型;否则取空字符串;不能为undefined或者null
|
||||
let _metadata = ''
|
||||
if (productStore.current?.metadata) {
|
||||
_metadata = productStore.current?.metadata
|
||||
} else if (productData.metadata && Object.keys(productData.metadata).length) {
|
||||
_metadata = JSON.stringify(productData.metadata)
|
||||
}
|
||||
// 更新选择设备(设备接入)
|
||||
const accessObj = {
|
||||
...productStore.current,
|
||||
metadata: _metadata,
|
||||
transportProtocol: access.value?.transport,
|
||||
protocolName: access.value?.protocolDetail?.name,
|
||||
accessId: access.value?.id,
|
||||
accessName: access.value?.name,
|
||||
accessProvider: access.value?.provider,
|
||||
messageProtocol: access.value?.protocol,
|
||||
}
|
||||
submitLoading.value = true
|
||||
const updateDeviceResp = await updateDevice(accessObj).catch(() => { success: false})
|
||||
|
||||
if (!updateDeviceResp.success) {
|
||||
submitLoading.value = false
|
||||
}
|
||||
|
||||
if (access.value?.provider === "plugin_gateway" && productData.id) {
|
||||
await savePluginData(
|
||||
'product',
|
||||
access.value?.id,
|
||||
productStore.current.id,
|
||||
productData.id
|
||||
).catch(() => ({}))
|
||||
}
|
||||
// 更新产品配置信息
|
||||
const resp = await modify(id || '', {
|
||||
id: id,
|
||||
configuration: { ...extra },
|
||||
storePolicy: storePolicy,
|
||||
}).finally(()=>{
|
||||
submitLoading.value = false
|
||||
})
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
productStore.current!.storePolicy = storePolicy;
|
||||
if ((window as any).onTabSaveSuccess) {
|
||||
if (resp.result) {
|
||||
(window as any).onTabSaveSuccess(resp);
|
||||
setTimeout(() => window.close(), 300);
|
||||
}
|
||||
} else {
|
||||
getDetailInfo();
|
||||
const result: any = {};
|
||||
// flatObj(values, result);
|
||||
// const { storePolicy, ...extra } = result;
|
||||
const { storePolicy, ...extra } = values;
|
||||
// 产品有物模型,设备接入没有,取产品物模型;设备接入有物模型,产品没有,取设备接入的物模型;否则取空字符串;不能为undefined或者null
|
||||
let _metadata = '';
|
||||
if (productStore.current?.metadata) {
|
||||
_metadata = productStore.current?.metadata;
|
||||
} else if (
|
||||
productData.metadata &&
|
||||
Object.keys(productData.metadata).length
|
||||
) {
|
||||
_metadata = JSON.stringify(productData.metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新选择设备(设备接入)
|
||||
const accessObj = {
|
||||
...productStore.current,
|
||||
metadata: _metadata,
|
||||
transportProtocol: access.value?.transport,
|
||||
protocolName: access.value?.protocolDetail?.name,
|
||||
accessId: access.value?.id,
|
||||
accessName: access.value?.name,
|
||||
accessProvider: access.value?.provider,
|
||||
messageProtocol: access.value?.protocol,
|
||||
};
|
||||
submitLoading.value = true;
|
||||
const updateDeviceResp = await updateDevice(accessObj).catch(() => {
|
||||
success: false;
|
||||
});
|
||||
|
||||
if (!updateDeviceResp.success) {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
|
||||
if (access.value?.provider === 'plugin_gateway' && productData.id) {
|
||||
await savePluginData(
|
||||
'product',
|
||||
access.value?.id,
|
||||
productStore.current.id,
|
||||
productData.id,
|
||||
).catch(() => ({}));
|
||||
}
|
||||
// 更新产品配置信息
|
||||
const resp = await modify(id || '', {
|
||||
id: id,
|
||||
configuration: { ...extra },
|
||||
storePolicy: storePolicy,
|
||||
}).finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
productStore.current!.storePolicy = storePolicy;
|
||||
if ((window as any).onTabSaveSuccess) {
|
||||
if (resp.result) {
|
||||
(window as any).onTabSaveSuccess(resp);
|
||||
setTimeout(() => window.close(), 300);
|
||||
}
|
||||
} else {
|
||||
getDetailInfo();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const flatObj = (obj: any, result: any) => {
|
||||
Object.keys(obj).forEach((key: string) => {
|
||||
|
@ -872,16 +952,16 @@ const flatObj = (obj: any, result: any) => {
|
|||
};
|
||||
|
||||
const getDetailInfo = async () => {
|
||||
await productStore.getDetail(productStore.detail.id)
|
||||
MetaDataModalSubmit()
|
||||
await productStore.getDetail(productStore.detail.id);
|
||||
MetaDataModalSubmit();
|
||||
};
|
||||
|
||||
const MetaDataModalSubmit = () => {
|
||||
// 跳转物模型标签
|
||||
productStore.tabActiveKey = 'Metadata'
|
||||
}
|
||||
// 跳转物模型标签
|
||||
productStore.tabActiveKey = 'Metadata';
|
||||
};
|
||||
|
||||
getProvidersList()
|
||||
getProvidersList();
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
|
@ -892,21 +972,21 @@ watchEffect(() => {
|
|||
});
|
||||
|
||||
const tooltip = computed(() => {
|
||||
if (productStore.current?.count > 0) {
|
||||
return '产品下有设备实例时不能更换接入方式'
|
||||
}
|
||||
if (productStore.current.state === 1) {
|
||||
return '停用产品后才可更换接入方式'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
if (productStore.current?.count > 0) {
|
||||
return '产品下有设备实例时不能更换接入方式';
|
||||
}
|
||||
if (productStore.current.state === 1) {
|
||||
return '停用产品后才可更换接入方式';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
const checkDisabled = computed(() => {
|
||||
if (productStore.current?.count > 0 || productStore.current.state === 1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if (productStore.current?.count > 0 || productStore.current.state === 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
nextTick(() => {
|
||||
getData();
|
||||
|
|
|
@ -160,7 +160,10 @@ import { useMenuStore } from '@/store/menu';
|
|||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import { EventEmitter } from '@/utils/utils';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
import { useSystem } from '@/store/system';
|
||||
|
||||
const { showThreshold } = useSystem()
|
||||
const permissionStore = usePermissionStore();
|
||||
const menuStory = useMenuStore();
|
||||
const route = useRoute();
|
||||
|
@ -274,45 +277,29 @@ const getProtocol = async () => {
|
|||
productStore.current?.messageProtocol,
|
||||
);
|
||||
if (res.status === 200) {
|
||||
const paring = res.result?.transports[0]?.features?.find(
|
||||
const transport = res.result?.transports?.find((item: any) => {
|
||||
return item.id === productStore.current?.transportProtocol;
|
||||
});
|
||||
const paring = transport?.features?.find(
|
||||
(item: any) => item.id === 'transparentCodec',
|
||||
);
|
||||
const supportFirmware = transport?.features?.find(
|
||||
(item: any) => item.id === 'supportFirmware',
|
||||
);
|
||||
if (paring) {
|
||||
list.value = [
|
||||
{
|
||||
key: 'Info',
|
||||
tab: '配置信息',
|
||||
},
|
||||
{
|
||||
key: 'Metadata',
|
||||
tab: '物模型',
|
||||
class: 'objectModel',
|
||||
},
|
||||
{
|
||||
key: 'Device',
|
||||
tab: '设备接入',
|
||||
},
|
||||
{
|
||||
key: 'DataAnalysis',
|
||||
tab: '数据解析',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
list.value = [
|
||||
{
|
||||
key: 'Info',
|
||||
tab: '配置信息',
|
||||
},
|
||||
{
|
||||
key: 'Metadata',
|
||||
tab: '物模型',
|
||||
class: 'objectModel',
|
||||
},
|
||||
{
|
||||
key: 'Device',
|
||||
tab: '设备接入',
|
||||
},
|
||||
];
|
||||
list.value.push({
|
||||
key: 'DataAnalysis',
|
||||
tab: '数据解析',
|
||||
});
|
||||
}
|
||||
if (
|
||||
supportFirmware &&
|
||||
permissionStore.hasPermission('device/Firmware:view') && isNoCommunity
|
||||
) {
|
||||
list.value.push({
|
||||
key: 'Firmware',
|
||||
tab: '远程升级',
|
||||
});
|
||||
}
|
||||
}
|
||||
//当前设备接入选择的协议
|
||||
|
@ -329,19 +316,13 @@ const getProtocol = async () => {
|
|||
if (
|
||||
permissionStore.hasPermission(
|
||||
'rule-engine/Alarm/Configuration:view',
|
||||
)
|
||||
) && isNoCommunity && showThreshold
|
||||
) {
|
||||
list.value.push({
|
||||
key: 'AlarmRecord',
|
||||
tab: '预处理数据',
|
||||
});
|
||||
}
|
||||
if (permissionStore.hasPermission('device/Firmware:view')) {
|
||||
list.value.push({
|
||||
key: 'Firmware',
|
||||
tab: '远程升级',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
|
|
|
@ -653,6 +653,11 @@ watch(() => metadata.value, () => {
|
|||
group: undefined
|
||||
}
|
||||
}
|
||||
if(props.type === 'functions' && !item.output){
|
||||
item['output'] = {
|
||||
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
initOptions(dataSource.value)
|
||||
|
|
|
@ -268,6 +268,7 @@ import { omit, cloneDeep } from 'lodash-es';
|
|||
import { PopoverModal } from '@/components/Metadata/Table';
|
||||
import { useTableWrapper } from '@/components/Metadata/Table/context';
|
||||
import { useThreshold } from './hooks';
|
||||
import { useSystem } from '@/store/system';
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
|
@ -309,6 +310,7 @@ const props = defineProps({
|
|||
|
||||
const type = inject('_metadataType');
|
||||
|
||||
const { showThreshold } = useSystem()
|
||||
const productStore = useProductStore();
|
||||
const deviceStore = useInstanceStore();
|
||||
const tableWrapperRef = useTableWrapper();
|
||||
|
@ -382,7 +384,7 @@ const showMetrics = computed(() => {
|
|||
const showExtra = computed(() => {
|
||||
return (
|
||||
['int', 'long', 'float', 'double'].includes(props.type as any) &&
|
||||
props.metadataType === 'properties'
|
||||
props.metadataType === 'properties' && showThreshold
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ export const useThreshold = (props: Record<string, any>) => {
|
|||
}
|
||||
const thresholdDetailQuery = () => {
|
||||
if (props.target === 'product') {
|
||||
queryProduct(productStore.current.id, props.id)
|
||||
queryProduct(productStore.current.id, props.id,false)
|
||||
} else {
|
||||
queryDevice(deviceStore.current.productId, deviceStore.current.id, props.id)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -204,11 +204,7 @@ const rules = {
|
|||
};
|
||||
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return (
|
||||
option.componentOptions.children[0].text
|
||||
.toLowerCase()
|
||||
.indexOf(input.toLowerCase()) >= 0
|
||||
);
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
|
||||
const platformConfigList = computed(() => {
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<j-col :span="8">
|
||||
<div class="data-statistics-item">
|
||||
<div class="flow-info" style="width: 100%">
|
||||
<div class="label">本年流量消耗1</div>
|
||||
<div class="label">本年流量消耗</div>
|
||||
<j-tooltip placement="bottomLeft">
|
||||
<template #title>
|
||||
<span>{{ yearTotal }} M</span>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/>
|
||||
<div class="right">
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
:columns="newColumns"
|
||||
target="channel"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<JProTable
|
||||
ref="listRef"
|
||||
model="table"
|
||||
:columns="columns"
|
||||
:columns="newColumns"
|
||||
:request="(e:any) => ChannelApi.list(e, route?.query.id as string)"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'modifyTime', order: 'desc' }],
|
||||
|
@ -238,6 +238,14 @@ const columns = [
|
|||
},
|
||||
];
|
||||
|
||||
const newColumns = computed(()=>{
|
||||
if(route.query.type=== 'fixed-media'){
|
||||
return columns.filter(item=>item.key!=='manufacturer')
|
||||
}else{
|
||||
return columns
|
||||
}
|
||||
});
|
||||
|
||||
const params = ref<Record<string, any>>({});
|
||||
const deviceData = ref<any>();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
padding-left: @padding;
|
||||
height: calc(100vh - 190px);
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
|
|
|
@ -151,8 +151,10 @@ const getTemplateList = async () => {
|
|||
};
|
||||
const { result } = await ConfigApi.getTemplate(params, props.data.id);
|
||||
templateList.value = result;
|
||||
formData.value.templateId = result[0]?.id as string;
|
||||
getTemplateDetail();
|
||||
if (result.length) {
|
||||
formData.value.templateId = result[0]?.id as string;
|
||||
getTemplateDetail();
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -173,7 +175,7 @@ const getTemplateDetail = async () => {
|
|||
(m: any) => ({
|
||||
...m,
|
||||
type: m.expands ? m.expands.businessType : m.type,
|
||||
value: undefined,
|
||||
value: undefined,
|
||||
// 电话字段校验
|
||||
otherRules:
|
||||
m.id === 'calledNumber' || m.id === 'phoneNumber'
|
||||
|
|
|
@ -207,7 +207,7 @@ const onTreeSelect = (keys: any) => {
|
|||
|
||||
const columns = [
|
||||
{
|
||||
title: '钉钉用户名',
|
||||
title: props.data.type === 'weixin' ? '企业微信用户名' : '钉钉用户名',
|
||||
dataIndex: 'thirdPartyUserName',
|
||||
key: 'thirdPartyUserName',
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<page-container>
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="notice-config"
|
||||
target="notice-template"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<FullPage>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
{{ value.name }}
|
||||
</span>
|
||||
</Ellipsis>
|
||||
<div v-if="showBindTags && activeBranches.length">
|
||||
<div v-if="showBindTags && activeBranches.length && value.triggerType === 'device'">
|
||||
<div style="margin-top: 16px; margin-bottom: 8px" class="card-item-content-text">
|
||||
关联条件
|
||||
</div>
|
||||
|
|
|
@ -1,285 +1,291 @@
|
|||
<template>
|
||||
<j-form
|
||||
ref='timerForm'
|
||||
:model='formModel'
|
||||
:colon='false'
|
||||
layout='vertical'
|
||||
>
|
||||
<j-form-item name='trigger'>
|
||||
<j-radio-group
|
||||
v-model:value='formModel.trigger'
|
||||
:options='triggerOptions'
|
||||
option-type='button'
|
||||
button-style='solid'
|
||||
@change='triggerChange'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item v-if='showCron' name='cron' :rules="cronRules">
|
||||
<j-input placeholder='corn表达式' v-model:value='formModel.cron' @change='updateValue' />
|
||||
</j-form-item>
|
||||
<j-form-item v-else-if="showMulti" name="multi" :rules="multiRules">
|
||||
<Calendar v-model:value="formModel.multi" @change='updateValue'/>
|
||||
</j-form-item>
|
||||
<template v-else>
|
||||
<j-form-item name='when'>
|
||||
<WhenOption v-model:value='formModel.when' :type='formModel.trigger' @change='updateValue' />
|
||||
</j-form-item>
|
||||
<j-form-item name='mod'>
|
||||
<j-radio-group
|
||||
v-model:value='formModel.mod'
|
||||
:options='[
|
||||
{ label: "周期执行", value: "period" },
|
||||
{ label: "执行一次", value: "once" },
|
||||
]'
|
||||
option-type='button'
|
||||
button-style='solid'
|
||||
@change='updateValue'
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<j-space v-if='showOnce && !showMulti' style='display: flex;gap: 24px'>
|
||||
<j-form-item :name="['once', 'time']">
|
||||
<j-time-picker
|
||||
valueFormat='HH:mm:ss'
|
||||
v-model:value='formModel.once.time'
|
||||
style='width: 100%'
|
||||
format='HH:mm:ss'
|
||||
@change='updateValue'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item> 执行一次</j-form-item>
|
||||
</j-space>
|
||||
<j-space v-if='showPeriod && !showMulti' style='display: flex;gap: 24px'>
|
||||
<j-form-item>
|
||||
<j-time-range-picker
|
||||
valueFormat='HH:mm:ss'
|
||||
:value='[
|
||||
formModel.period.from,
|
||||
formModel.period.to,
|
||||
]'
|
||||
@change='(v) => {
|
||||
formModel.period.from = v[0]
|
||||
formModel.period.to = v[1]
|
||||
updateValue()
|
||||
}'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item>每</j-form-item>
|
||||
<j-form-item
|
||||
:name='["period", "every"]'
|
||||
:rules='[{ required: true, message: "请输入时间" }]'
|
||||
>
|
||||
<j-input-number
|
||||
placeholder='请输入时间'
|
||||
style='max-width: 170px'
|
||||
:precision='0'
|
||||
:min='1'
|
||||
:max='unitMax'
|
||||
v-model:value='formModel.period.every'
|
||||
@change='updateValue'
|
||||
>
|
||||
<template #addonAfter>
|
||||
<j-select
|
||||
v-model:value='formModel.period.unit'
|
||||
:options='[
|
||||
{ label: "秒", value: "seconds" },
|
||||
{ label: "分", value: "minutes" },
|
||||
{ label: "小时", value: "hours" },
|
||||
]'
|
||||
@select='periodUnitChange'
|
||||
<j-form ref="timerForm" :model="formModel" :colon="false" layout="vertical">
|
||||
<j-form-item name="trigger">
|
||||
<j-radio-group
|
||||
v-model:value="formModel.trigger"
|
||||
:options="triggerOptions"
|
||||
option-type="button"
|
||||
button-style="solid"
|
||||
@change="triggerChange"
|
||||
/>
|
||||
</template>
|
||||
</j-input-number>
|
||||
</j-form-item>
|
||||
<j-form-item>执行一次</j-form-item>
|
||||
</j-space>
|
||||
</j-form>
|
||||
</j-form-item>
|
||||
<j-form-item v-if="showCron" name="cron" :rules="cronRules">
|
||||
<j-input
|
||||
placeholder="corn表达式"
|
||||
v-model:value="formModel.cron"
|
||||
@change="updateValue"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item v-else-if="showMulti" name="multi" :rules="multiRules">
|
||||
<Calendar v-model:value="formModel.multi" @change="updateValue" />
|
||||
</j-form-item>
|
||||
<template v-else>
|
||||
<j-form-item name="when">
|
||||
<WhenOption
|
||||
v-model:value="formModel.when"
|
||||
:type="formModel.trigger"
|
||||
@change="updateValue"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item name="mod">
|
||||
<j-radio-group
|
||||
v-model:value="formModel.mod"
|
||||
:options="[
|
||||
{ label: '周期执行', value: 'period' },
|
||||
{ label: '执行一次', value: 'once' },
|
||||
]"
|
||||
option-type="button"
|
||||
button-style="solid"
|
||||
@change="updateValue"
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<j-space v-if="showOnce && !showMulti" style="display: flex; gap: 24px">
|
||||
<j-form-item :name="['once', 'time']">
|
||||
<j-time-picker
|
||||
valueFormat="HH:mm:ss"
|
||||
v-model:value="formModel.once.time"
|
||||
style="width: 100%"
|
||||
format="HH:mm:ss"
|
||||
@change="updateValue"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item> 执行一次</j-form-item>
|
||||
</j-space>
|
||||
<j-space
|
||||
v-if="showPeriod && !showMulti"
|
||||
style="display: flex; gap: 24px"
|
||||
>
|
||||
<j-form-item>
|
||||
<j-time-range-picker
|
||||
valueFormat="HH:mm:ss"
|
||||
:value="[formModel.period.from, formModel.period.to]"
|
||||
@change="
|
||||
(v) => {
|
||||
formModel.period.from = v[0];
|
||||
formModel.period.to = v[1];
|
||||
updateValue();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item>每</j-form-item>
|
||||
<j-form-item
|
||||
:name="['period', 'every']"
|
||||
:rules="[{ required: true, message: '请输入时间' }]"
|
||||
>
|
||||
<j-input-number
|
||||
placeholder="请输入时间"
|
||||
style="max-width: 170px"
|
||||
:precision="0"
|
||||
:min="1"
|
||||
:max="unitMax"
|
||||
v-model:value="formModel.period.every"
|
||||
@change="updateValue"
|
||||
>
|
||||
<template #addonAfter>
|
||||
<j-select
|
||||
v-model:value="formModel.period.unit"
|
||||
:options="[
|
||||
{ label: '秒', value: 'seconds' },
|
||||
{ label: '分', value: 'minutes' },
|
||||
{ label: '小时', value: 'hours' },
|
||||
]"
|
||||
@select="periodUnitChange"
|
||||
/>
|
||||
</template>
|
||||
</j-input-number>
|
||||
</j-form-item>
|
||||
<j-form-item>执行一次</j-form-item>
|
||||
</j-space>
|
||||
</j-form>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Timer'>
|
||||
import type { PropType } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import WhenOption from './WhenOption.vue'
|
||||
import {cloneDeep, pick} from 'lodash-es'
|
||||
import type { OperationTimer } from '../../../typings'
|
||||
import { defineExpose } from 'vue'
|
||||
import Calendar from './Calendar.vue'
|
||||
import cronstrue from 'cronstrue'
|
||||
<script setup lang="ts" name="Timer">
|
||||
import type { PropType } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import WhenOption from './WhenOption.vue';
|
||||
import { cloneDeep, pick } from 'lodash-es';
|
||||
import type { OperationTimer } from '../../../typings';
|
||||
import { defineExpose } from 'vue';
|
||||
import Calendar from './Calendar.vue';
|
||||
import cronstrue from 'cronstrue';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
|
||||
type NameType = string[] | string
|
||||
type NameType = string[] | string;
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: Partial<OperationTimer>): void
|
||||
}
|
||||
(e: 'update:value', data: Partial<OperationTimer>): void;
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: [String, Array] as PropType<NameType>,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: undefined
|
||||
}
|
||||
})
|
||||
name: {
|
||||
type: [String, Array] as PropType<NameType>,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
const unitMax = ref<number>(99)
|
||||
const emit = defineEmits<Emit>();
|
||||
const unitMax = ref<number>(99);
|
||||
|
||||
const cronRules = [
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
{
|
||||
validator: async (_: any, v: string) => {
|
||||
|
||||
if (v) {
|
||||
try {
|
||||
console.log(v, cronstrue.toString(v))
|
||||
} catch (e) {
|
||||
return Promise.reject(new Error('请输入正确的cron表达式'));
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(new Error('请输入cron表达式'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
]
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
{
|
||||
validator: async (_: any, v: string) => {
|
||||
if (v) {
|
||||
try {
|
||||
console.log(v, cronstrue.toString(v));
|
||||
} catch (e) {
|
||||
return Promise.reject(new Error('请输入正确的cron表达式'));
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(new Error('请输入cron表达式'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const multiRules = [
|
||||
{
|
||||
validator: async (_: any, v: string) => {
|
||||
if (!v.spec?.length) {
|
||||
return Promise.reject('请添加自定义日历规则');
|
||||
} else {
|
||||
const index = v.spec.findIndex(item => !item.scheduleTags.length)
|
||||
if (index > -1) {
|
||||
return Promise.reject(`规则【${index + 1}】请选择日期类型`);
|
||||
}
|
||||
}
|
||||
{
|
||||
validator: async (_: any, v: string) => {
|
||||
if (!v.spec?.length) {
|
||||
return Promise.reject('请添加自定义日历规则');
|
||||
} else {
|
||||
const index = v.spec.findIndex(
|
||||
(item) => !item.scheduleTags.length,
|
||||
);
|
||||
if (index > -1) {
|
||||
return Promise.reject(`规则【${index + 1}】请选择日期类型`);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
}
|
||||
}
|
||||
]
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const triggerOptions = computed(() => {
|
||||
let _options = [
|
||||
{ label: "按周", value: "week" },
|
||||
{ label: "按月", value: "month" },
|
||||
{ label: "cron表达式", value: "cron" },
|
||||
{ label: "自定义日历", value: "multi" }
|
||||
]
|
||||
let _options = isNoCommunity ? [
|
||||
{ label: '按周', value: 'week' },
|
||||
{ label: '按月', value: 'month' },
|
||||
{ label: 'cron表达式', value: 'cron' },
|
||||
{ label: '自定义日历', value: 'multi' },
|
||||
] : [
|
||||
{ label: '按周', value: 'week' },
|
||||
{ label: '按月', value: 'month' },
|
||||
{ label: 'cron表达式', value: 'cron' },
|
||||
]
|
||||
|
||||
// if (props.type === 'timer') {
|
||||
// _options = [..._options, {
|
||||
// label: "自定义日历", value: "multi"
|
||||
// }]
|
||||
// }
|
||||
return _options
|
||||
})
|
||||
// if (props.type === 'timer') {
|
||||
// _options = [..._options, {
|
||||
// label: "自定义日历", value: "multi"
|
||||
// }]
|
||||
// }
|
||||
return _options;
|
||||
});
|
||||
|
||||
const formModel = reactive<OperationTimer>({
|
||||
trigger: 'week',
|
||||
when: props.value.when || [],
|
||||
mod: 'period',
|
||||
cron: undefined,
|
||||
once: {
|
||||
time: dayjs(new Date()).format('HH:mm:ss')
|
||||
},
|
||||
period: {
|
||||
from: dayjs(new Date()).startOf('day').format('HH:mm:ss'),
|
||||
to: dayjs(new Date()).endOf('day').format('HH:mm:ss'),
|
||||
every: 1,
|
||||
unit: 'seconds'
|
||||
},
|
||||
multi: {
|
||||
type: "and",
|
||||
spec: []
|
||||
}
|
||||
})
|
||||
const timerForm = ref()
|
||||
trigger: 'week',
|
||||
when: props.value.when || [],
|
||||
mod: 'period',
|
||||
cron: undefined,
|
||||
once: {
|
||||
time: dayjs(new Date()).format('HH:mm:ss'),
|
||||
},
|
||||
period: {
|
||||
from: dayjs(new Date()).startOf('day').format('HH:mm:ss'),
|
||||
to: dayjs(new Date()).endOf('day').format('HH:mm:ss'),
|
||||
every: 1,
|
||||
unit: 'seconds',
|
||||
},
|
||||
multi: {
|
||||
type: 'and',
|
||||
spec: [],
|
||||
},
|
||||
});
|
||||
const timerForm = ref();
|
||||
|
||||
const showCron = computed(() => {
|
||||
return formModel.trigger === 'cron'
|
||||
})
|
||||
return formModel.trigger === 'cron';
|
||||
});
|
||||
const showMulti = computed(() => {
|
||||
return formModel.trigger === 'multi'
|
||||
})
|
||||
return formModel.trigger === 'multi';
|
||||
});
|
||||
|
||||
const showOnce = computed(() => {
|
||||
return formModel.trigger !== 'cron' && formModel.mod === 'once'
|
||||
})
|
||||
return formModel.trigger !== 'cron' && formModel.mod === 'once';
|
||||
});
|
||||
|
||||
const showPeriod = computed(() => {
|
||||
return formModel.trigger !== 'cron' && formModel.mod === 'period'
|
||||
})
|
||||
return formModel.trigger !== 'cron' && formModel.mod === 'period';
|
||||
});
|
||||
|
||||
const updateValue = () => {
|
||||
|
||||
const cloneValue = cloneDeep(formModel)
|
||||
let keys: string[] = ['trigger']
|
||||
if (cloneValue.trigger === 'cron') {
|
||||
keys.push('cron')
|
||||
} else if (cloneValue.trigger === 'multi') {
|
||||
keys.push('multi')
|
||||
} else {
|
||||
keys = keys.concat(['mod', 'when'])
|
||||
|
||||
if (cloneValue.mod === 'period') {
|
||||
keys.push('period')
|
||||
const cloneValue = cloneDeep(formModel);
|
||||
let keys: string[] = ['trigger'];
|
||||
if (cloneValue.trigger === 'cron') {
|
||||
keys.push('cron');
|
||||
} else if (cloneValue.trigger === 'multi') {
|
||||
keys.push('multi');
|
||||
} else {
|
||||
keys.push('once')
|
||||
keys = keys.concat(['mod', 'when']);
|
||||
|
||||
if (cloneValue.mod === 'period') {
|
||||
keys.push('period');
|
||||
} else {
|
||||
keys.push('once');
|
||||
}
|
||||
}
|
||||
}
|
||||
emit('update:value', pick(cloneValue, keys))
|
||||
}
|
||||
emit('update:value', pick(cloneValue, keys));
|
||||
};
|
||||
|
||||
const triggerChange = () => {
|
||||
formModel.when = []
|
||||
formModel.cron = undefined
|
||||
updateValue()
|
||||
}
|
||||
formModel.when = [];
|
||||
formModel.cron = undefined;
|
||||
updateValue();
|
||||
};
|
||||
|
||||
/**
|
||||
* 频率单位切换
|
||||
* @param v
|
||||
*/
|
||||
const periodUnitChange = (v: any) => {
|
||||
if(v === 'hours') {
|
||||
unitMax.value = 99999
|
||||
} else {
|
||||
unitMax.value = 99
|
||||
}
|
||||
formModel.period!.every = 1
|
||||
updateValue()
|
||||
}
|
||||
if (v === 'hours') {
|
||||
unitMax.value = 99999;
|
||||
} else {
|
||||
unitMax.value = 99;
|
||||
}
|
||||
formModel.period!.every = 1;
|
||||
updateValue();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
validateFields: () => new Promise(async (resolve) => {
|
||||
const data = await timerForm.value?.validateFields()
|
||||
resolve(data)
|
||||
})
|
||||
})
|
||||
validateFields: () =>
|
||||
new Promise(async (resolve) => {
|
||||
const data = await timerForm.value?.validateFields();
|
||||
resolve(data);
|
||||
}),
|
||||
});
|
||||
|
||||
Object.assign(formModel, props.value)
|
||||
formModel.when = props.value.when || []
|
||||
Object.assign(formModel, props.value);
|
||||
formModel.when = props.value.when || [];
|
||||
|
||||
watchEffect(() => {
|
||||
if(props.value?.period?.unit === 'hours') {
|
||||
unitMax.
|
||||
value = 99999
|
||||
} else {
|
||||
unitMax.value = 99
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if (props.value?.period?.unit === 'hours') {
|
||||
unitMax.value = 99999;
|
||||
} else {
|
||||
unitMax.value = 99;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
|
||||
</style>
|
||||
<style scoped lang="less"></style>
|
||||
|
|
|
@ -305,8 +305,8 @@ const queryParams = {
|
|||
{
|
||||
terms: [
|
||||
{
|
||||
value: '%show":true%',
|
||||
termType: 'like',
|
||||
value: '%show":false%',
|
||||
termType: 'nlike',
|
||||
column: 'options',
|
||||
type: 'and',
|
||||
},
|
||||
|
|
|
@ -458,7 +458,7 @@ const form = reactive<formType>({
|
|||
headerTheme: configInfo.front?.headerTheme,
|
||||
logo: configInfo.front?.logo || '/logo.png',
|
||||
ico: configInfo.front?.ico || '/favicon.ico',
|
||||
showRecordNumber: configInfo.front?.showRecordNumber,
|
||||
showRecordNumber: configInfo.front?.showRecordNumber || false,
|
||||
recordNumber: configInfo.front?.recordNumber,
|
||||
background: configInfo.front?.background || '/images/login.png',
|
||||
apiKey: configInfo.amap?.apiKey,
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
}"
|
||||
:params="queryParams"
|
||||
:rowSelection="{
|
||||
// selectedRowKeys: table._selectedRowKeys.value,
|
||||
// onChange:(keys:string[])=>table._selectedRowKeys.value = [...keys],
|
||||
// onSelectNone: table.cancelSelect
|
||||
selectedRowKeys: table._selectedRowKeys.value,
|
||||
onSelect: table.onSelect,
|
||||
onSelectAll: table.onSelectAll,
|
||||
|
@ -307,6 +304,7 @@ const columns = [
|
|||
dataIndex: 'permission',
|
||||
key: 'permission',
|
||||
ellipsis: true,
|
||||
width: 300,
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -326,7 +326,7 @@ const form = reactive({
|
|||
|
||||
init: () => {
|
||||
// 获取菜单详情
|
||||
routeParams.id &&
|
||||
routeParams.id ?
|
||||
getMenuInfo_api(routeParams.id).then((resp: any) => {
|
||||
form.data = {
|
||||
...(resp.result as formType),
|
||||
|
@ -338,7 +338,7 @@ const form = reactive({
|
|||
};
|
||||
form.sourceCode = resp.result.code;
|
||||
showPermissionChoose.value = true
|
||||
});
|
||||
}) : showPermissionChoose.value = true
|
||||
|
||||
if (isNoCommunity) {
|
||||
// 获取关联菜单
|
||||
|
@ -350,8 +350,8 @@ const form = reactive({
|
|||
{
|
||||
terms: [
|
||||
{
|
||||
value: '%show":true%',
|
||||
termType: 'like',
|
||||
value: '%show":false%',
|
||||
termType: 'nlike',
|
||||
column: 'options',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -10,30 +10,30 @@
|
|||
<div class="content">
|
||||
<j-card title="菜单配置" style="width: 80%">
|
||||
<div class="tree">
|
||||
<j-scrollbar>
|
||||
<j-tree
|
||||
v-if="treeData.length !== 0"
|
||||
defaultExpandAll
|
||||
multiple
|
||||
draggable
|
||||
:tree-data="treeData"
|
||||
@select="onSelect"
|
||||
:selectedKeys="selectedKeys"
|
||||
@drop="onDrop"
|
||||
@dragend="onDragend"
|
||||
>
|
||||
<template #title="row">
|
||||
<div class="tree-content">
|
||||
<div class="tree-content-title">
|
||||
<AIcon type="HolderOutlined" />
|
||||
<div style="margin-left: 8px">
|
||||
{{ row.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</j-tree>
|
||||
</j-scrollbar>
|
||||
<j-scrollbar>
|
||||
<j-tree
|
||||
v-if="treeData.length !== 0"
|
||||
defaultExpandAll
|
||||
multiple
|
||||
draggable
|
||||
:tree-data="treeData"
|
||||
@select="onSelect"
|
||||
:selectedKeys="selectedKeys"
|
||||
@drop="onDrop"
|
||||
@dragend="onDragend"
|
||||
>
|
||||
<template #title="row">
|
||||
<div class="tree-content">
|
||||
<div class="tree-content-title">
|
||||
<AIcon type="HolderOutlined" />
|
||||
<div style="margin-left: 8px">
|
||||
{{ row.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</j-tree>
|
||||
</j-scrollbar>
|
||||
</div>
|
||||
</j-card>
|
||||
</div>
|
||||
|
@ -43,6 +43,17 @@
|
|||
style="margin-left: 10%"
|
||||
>保存</j-button
|
||||
>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:popConfirm="{
|
||||
title: '确认同步系统菜单权限?',
|
||||
okText: ' 确定',
|
||||
cancelText: '取消',
|
||||
onConfirm: synchronization,
|
||||
}"
|
||||
style="margin-left: 20px"
|
||||
>同步系统菜单权限
|
||||
</PermissionButton>
|
||||
</j-card>
|
||||
<j-modal
|
||||
modalType="message"
|
||||
|
@ -72,20 +83,18 @@ import {
|
|||
mergeArr,
|
||||
findAllParentsAndChildren,
|
||||
handleSorts,
|
||||
handleSortsArr
|
||||
handleSortsArr,
|
||||
} from './utils';
|
||||
import BaseMenu from '@/views/init-home/data/baseMenu';
|
||||
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import {
|
||||
USER_CENTER_MENU_CODE,
|
||||
messageSubscribe
|
||||
} from '@/utils/consts';
|
||||
import { USER_CENTER_MENU_CODE, messageSubscribe } from '@/utils/consts';
|
||||
import { protocolList } from '@/utils/consts';
|
||||
import { getProviders } from '@/api/data-collect/channel';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
import { USER_CENTER_MENU_DATA } from '@/views/init-home/data/baseMenu'
|
||||
import { USER_CENTER_MENU_DATA } from '@/views/init-home/data/baseMenu';
|
||||
import { unionBy } from 'lodash';
|
||||
|
||||
const selectedKeys: any = ref([]);
|
||||
const treeData = ref<any>([]);
|
||||
|
@ -121,15 +130,15 @@ const params = {
|
|||
*/
|
||||
let filterProtocolList: any[] = [];
|
||||
const getProvidersFn = async () => {
|
||||
if(!isNoCommunity){
|
||||
return
|
||||
}else{
|
||||
if (!isNoCommunity) {
|
||||
return;
|
||||
} else {
|
||||
const res: any = await getProviders();
|
||||
filterProtocolList = protocolList.filter((item) => {
|
||||
return res.result?.find((val: any) => item.alias == val.id);
|
||||
})
|
||||
return res.result?.find((val: any) => item.alias == val.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
getProvidersFn();
|
||||
/**
|
||||
* 作用:过滤掉非选中菜单重新组成新的数组
|
||||
|
@ -162,46 +171,52 @@ getProvidersFn();
|
|||
* @param selectedKeys 选中的菜单
|
||||
* 选中和非选中改变show的值
|
||||
*/
|
||||
const dealTree = (nodes: Array<any>, selectedKeys: Array<any>,parentId?:string) =>{
|
||||
const dealTree = (
|
||||
nodes: Array<any>,
|
||||
selectedKeys: Array<any>,
|
||||
parentId?: string,
|
||||
) => {
|
||||
const filtered = [];
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (!node.code) {
|
||||
continue;
|
||||
}
|
||||
node.parentId = parentId ? undefined : parentId
|
||||
node?.options ? node.options.show = false : node.options = { show : false }
|
||||
node.parentId = parentId ? undefined : parentId;
|
||||
node?.options
|
||||
? (node.options.show = false)
|
||||
: (node.options = { show: false });
|
||||
|
||||
if (selectedKeys.indexOf(node.code) !== -1) {
|
||||
node.options.show = true
|
||||
node.options.show = true;
|
||||
if (node.children) {
|
||||
node.children = dealTree(node.children, selectedKeys,node.id);
|
||||
node.children = dealTree(node.children, selectedKeys, node.id);
|
||||
}
|
||||
} else if (node.children) {
|
||||
node.children = dealTree(node.children, selectedKeys,node.id);
|
||||
const children =node.children.filter((item:any)=>{
|
||||
item.options.show === true
|
||||
})
|
||||
node.children = dealTree(node.children, selectedKeys, node.id);
|
||||
const children = node.children.filter((item: any) => {
|
||||
item.options.show === true;
|
||||
});
|
||||
if (children.length > 0) {
|
||||
node.options.show = true
|
||||
node.options.show = true;
|
||||
}
|
||||
}else{
|
||||
node.options.show = false
|
||||
} else {
|
||||
node.options.show = false;
|
||||
}
|
||||
filtered.push(node)
|
||||
filtered.push(node);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
};
|
||||
const handleOk = async () => {
|
||||
// const _dataArr = filterTree(cloneDeep(treeData.value), selectedKeys.value);
|
||||
const _dataArr = dealTree(cloneDeep(treeData.value),selectedKeys.value)
|
||||
const _dataSorts = handleSorts(_dataArr)
|
||||
const _dataArr = dealTree(cloneDeep(treeData.value), selectedKeys.value);
|
||||
const _dataSorts = handleSorts(_dataArr);
|
||||
loading.value = true;
|
||||
_dataSorts.push(USER_CENTER_MENU_DATA)
|
||||
_dataSorts.push(USER_CENTER_MENU_DATA);
|
||||
const res = await updateMenus(_dataSorts).catch(() => {});
|
||||
if (res?.status === 200) {
|
||||
onlyMessage('操作成功', 'success');
|
||||
location.reload()
|
||||
location.reload();
|
||||
}
|
||||
loading.value = false;
|
||||
visible.value = false;
|
||||
|
@ -245,6 +260,36 @@ const onDragend = (info: AntTreeNodeDropEvent) => {
|
|||
}
|
||||
};
|
||||
|
||||
const synchronization = async () => {
|
||||
const menu = synchronizationMenu(cloneDeep(systemMenu.value), BaseMenu);
|
||||
menu.push(USER_CENTER_MENU_DATA);
|
||||
const res = await updateMenus(menu).catch(() => {});
|
||||
if (res?.status === 200) {
|
||||
onlyMessage('操作成功', 'success');
|
||||
location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
//双重遍历系统菜单和初始化菜单做菜单和按钮权限和接口权限的合并处理
|
||||
const synchronizationMenu = (menu: any, baseMenu: any) => {
|
||||
const newMenu = menu.map((i: any) => {
|
||||
baseMenu.find((item: any) => {
|
||||
if (i.id === item.id) {
|
||||
i.buttons = unionBy(i.buttons, item.buttons, 'id');
|
||||
i.permissions = unionBy(
|
||||
i.permissions,
|
||||
item.permissions,
|
||||
'permission',
|
||||
);
|
||||
if (item.children && i.children) {
|
||||
i.children = synchronizationMenu(i.children, item.children);
|
||||
}
|
||||
}
|
||||
});
|
||||
return i;
|
||||
});
|
||||
return unionBy(newMenu, baseMenu, 'code');
|
||||
};
|
||||
onMounted(() => {
|
||||
getSystemPermission_api().then((resp: any) => {
|
||||
// const filterBaseMenu = BaseMenu.filter(item => ![
|
||||
|
@ -258,9 +303,9 @@ onMounted(() => {
|
|||
if (resp.status == 200) {
|
||||
systemMenu.value = resp.result?.filter(
|
||||
(item: { code: string }) =>
|
||||
![
|
||||
USER_CENTER_MENU_CODE,messageSubscribe
|
||||
].includes(item.code),
|
||||
![USER_CENTER_MENU_CODE, messageSubscribe].includes(
|
||||
item.code,
|
||||
),
|
||||
);
|
||||
//初始化菜单
|
||||
// initData(baseMenu.value); // 不要克隆,通过引用 处理key和name
|
||||
|
@ -285,7 +330,7 @@ const filterMenus = (menus: any[]) => {
|
|||
if (!filterProtocolList.length && item.code == 'link/DataCollect') {
|
||||
return false;
|
||||
}
|
||||
return item
|
||||
return item;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -132,7 +132,7 @@ export const inItSelected = (Menu:any) =>{
|
|||
arr.forEach((item: any) => {
|
||||
item.title = item.code;
|
||||
item.key = item.code; // treeData需要唯一key
|
||||
item?.options?.show ? checkedKeys.push(item.code) : '';
|
||||
item?.options?.show === false ? '' : checkedKeys.push(item.code);
|
||||
if (item?.children) {
|
||||
getMap(item?.children);
|
||||
}
|
||||
|
|
|
@ -211,8 +211,8 @@ const table = reactive({
|
|||
type: 'or',
|
||||
terms: [
|
||||
{
|
||||
value: '%show":true%',
|
||||
termType: 'like',
|
||||
value: '%show":false%',
|
||||
termType: 'nlike',
|
||||
column: 'options',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -72,7 +72,7 @@ const systemNotice = [
|
|||
},
|
||||
{
|
||||
provider: 'alarm-org',
|
||||
name: '部门告警',
|
||||
name: '组织告警',
|
||||
},
|
||||
{
|
||||
provider: 'alarm-other',
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts", "src/vite-env.d.ts", "config/**/*.ts", "plugin/**/*.ts"]
|
||||
"include": ["vite.config.ts", "src/vite-env.d.ts", "config/**/*.ts", "plugin/**/*.ts", "src/**/*.vue"]
|
||||
}
|
||||
|
|
|
@ -96,8 +96,8 @@ export default defineConfig(({ mode}) => {
|
|||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://192.168.32.217:8844', //张本地
|
||||
// target: 'http://120.77.179.54:8844', // 120测试
|
||||
target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
// target: 'http://192.168.32.167:8844', // 本地开发环境1
|
||||
// target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
target: 'http://192.168.33.97:8844', // 本地开发环境1
|
||||
// target: 'http://192.168.33.6:38848', // 社区版开发环境
|
||||
// target: 'http://192.168.32.207:8844', // 刘本地
|
||||
// target: 'http://192.168.32.187:8844', // 谭本地
|
||||
|
@ -114,7 +114,6 @@ export default defineConfig(({ mode}) => {
|
|||
less: {
|
||||
modifyVars: {
|
||||
'root-entry-name': 'variable',
|
||||
'primary-color': '#1677FF',
|
||||
hack: `true; @import (reference) "${path.resolve('src/style/variable.less')}";`,
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
|
|
Loading…
Reference in New Issue