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:
XieYongHong 2024-08-12 16:11:27 +08:00 committed by GitHub
parent 3da54bb59b
commit 2b3e3280ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 2254 additions and 2106 deletions

View File

@ -1,7 +1,4 @@
export default { export default {
theme: {
'primary-color': '#1677FF',
},
logo: '/favicon.ico', // 浏览器标签页logo logo: '/favicon.ico', // 浏览器标签页logo
title: 'Jetlinks', // 浏览器标签页title title: 'Jetlinks', // 浏览器标签页title
layout: { layout: {

View File

@ -33,7 +33,7 @@ watch(() => JSON.stringify(route.query || {}), () => {
ConfigProvider.config({ ConfigProvider.config({
theme: { theme: {
primaryColor: "#315efb" primaryColor: "#1677FF"
} }
}) })
</script> </script>

View File

@ -662,7 +662,7 @@ export const queryDeviceThreshold = (productId: string, deviceId: string, prope
* @param productId * @param productId
* @param propertyId * @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)
/** /**
* - * -

View File

@ -35,8 +35,8 @@ const defaultOwnParams = [
{ {
terms: [ terms: [
{ {
value: "%show\":true%", value: "%show\":false%",
termType: "like", termType: "nlike",
column: "options" column: "options"
} }
], ],

View File

@ -2,6 +2,7 @@ import { defineStore } from 'pinia';
import { systemVersion } from '@/api/comm' import { systemVersion } from '@/api/comm'
import { useMenuStore } from './menu' import { useMenuStore } from './menu'
import {getDetails_api, settingDetail} from '@/api/system/basis'; import {getDetails_api, settingDetail} from '@/api/system/basis';
import { queryProductThreshold } from '@/api/device/instance'
import type { ConfigInfoType } from '@/views/system/Basis/typing'; import type { ConfigInfoType } from '@/views/system/Basis/typing';
import { LocalStore } from '@/utils/comm' import { LocalStore } from '@/utils/comm'
import { SystemConst } from '@/utils/consts' import { SystemConst } from '@/utils/consts'
@ -24,6 +25,7 @@ type SystemStateType = {
pure: boolean pure: boolean
} }
calendarTagColor:Map<string,string> calendarTagColor:Map<string,string>
showThreshold:boolean
} }
export const useSystem = defineStore('system', { export const useSystem = defineStore('system', {
@ -42,11 +44,13 @@ export const useSystem = defineStore('system', {
collapsed: false, collapsed: false,
pure: false pure: false
}, },
calendarTagColor:new Map() calendarTagColor:new Map(),
showThreshold: true
}), }),
actions: { actions: {
getSystemVersion(): Promise<any[]> { getSystemVersion(): Promise<any[]> {
this.getSystemConfig(); this.getSystemConfig();
this.getThreshold()
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
const resp = await systemVersion() const resp = await systemVersion()
if (resp.success && resp.result) { if (resp.success && resp.result) {
@ -100,6 +104,13 @@ export const useSystem = defineStore('system', {
this.calendarTagColor.set(i, answer.result[i]); 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
}
})
} }
} }
}) })

View File

@ -2,10 +2,6 @@
@import 'jetlinks-ui-components/es/style/variable.less'; @import 'jetlinks-ui-components/es/style/variable.less';
@import './scrollbar.less'; @import './scrollbar.less';
html {
--ant-primary-color: #1677FF !important;
}
.ellipsisFn(@num: 1, @width: 100%) { .ellipsisFn(@num: 1, @width: 100%) {
display: -webkit-box; display: -webkit-box;
max-width: @width; max-width: @width;

View File

@ -90,11 +90,12 @@ export const patch = function <T>(url: string, data = {}, ext: any = {}) {
* @param {Object} [ext] * @param {Object} [ext]
* @returns {AxiosInstance} * @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>>({ return request<any, AxiosResponseRewrite<T>>({
method: 'GET', method: 'GET',
url, url,
params, params,
_hideError,
...ext ...ext
}) })
} }
@ -200,7 +201,7 @@ const errorHandler = (error: any) => {
path: LoginPath path: LoginPath
}) })
}, 0) }, 0)
} else if (status === 404) { } else if (status === 404 && !error.config._hideError) {
const data = error?.response?.data const data = error?.response?.data
const message = error?.response?.data?.message || `${data?.error} ${data?.path}` const message = error?.response?.data?.message || `${data?.error} ${data?.path}`
showNotification(error?.code, message, '404') showNotification(error?.code, message, '404')

View File

@ -570,10 +570,18 @@ const onCheckChange = () => {
}; };
const handleBatchDelete = () => { const handleBatchDelete = () => {
if (!_selectedRowKeys.value.length) {
onlyMessage('至少选择一条数据', 'error');
return
}
handleDelete(); handleDelete();
}; };
const handleBatchUpdate = () => { const handleBatchUpdate = () => {
if (!_selectedRowKeys.value.length) {
onlyMessage('至少选择一条数据', 'error');
return
}
const dataSet = new Set(_selectedRowKeys.value); const dataSet = new Set(_selectedRowKeys.value);
const dataMap = new Map(); const dataMap = new Map();
tableRef?.value?._dataSource.forEach((i: any) => { tableRef?.value?._dataSource.forEach((i: any) => {

View File

@ -19,9 +19,9 @@ const systemNotice = [
}, },
{ {
provider: 'alarm-org', provider: 'alarm-org',
name: '部门告警', name: '组织告警',
description: description:
'当部门类型的告警被触发时,你将在已订阅的方式中收到通知', '当组织类型的告警被触发时,你将在已订阅的方式中收到通知',
}, },
{ {
provider: 'alarm-other', provider: 'alarm-other',

View File

@ -170,7 +170,7 @@ const columns = [
dataIndex: 'completeTime', dataIndex: 'completeTime',
}, },
{ {
title: '设备版本', title: '固件版本',
key: 'version', key: 'version',
dataIndex: 'version', dataIndex: 'version',
width: 100, width: 100,

View File

@ -68,6 +68,11 @@ const events: any = ref(undefined);
watch( watch(
() => current.value, () => current.value,
(value) => { (value) => {
tabList.value = [{
key: 'property',
tab: '属性',
type: 'property',
}]
const metadata = JSON.parse(value?.metadata || '{}'); const metadata = JSON.parse(value?.metadata || '{}');
properties.value = metadata.properties; properties.value = metadata.properties;
events.value = metadata.events; events.value = metadata.events;

View File

@ -134,9 +134,11 @@ import { useMenuStore } from '@/store/menu';
import { useRouterParams } from '@/utils/hooks/useParams'; import { useRouterParams } from '@/utils/hooks/useParams';
import { EventEmitter } from '@/utils/utils'; import { EventEmitter } from '@/utils/utils';
import { usePermissionStore } from '@/store/permission'; import { usePermissionStore } from '@/store/permission';
import { isNoCommunity } from '@/utils/utils';
import { useSystem } from '@/store/system';
const menuStory = useMenuStore(); const menuStory = useMenuStore();
const { showThreshold } = useSystem();
const route = useRoute(); const route = useRoute();
const routerParams = useRouterParams(); const routerParams = useRouterParams();
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
@ -212,19 +214,24 @@ const getStatus = (id: string) => {
const getDetail = () => { const getDetail = () => {
const keys = list.value.map((i) => i.key); 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({ list.value.push({
key: 'AlarmRecord', key: 'AlarmRecord',
tab: '预处理数据', tab: '预处理数据',
}); });
} }
if (permissionStore.hasPermission('iot-card/CardManagement:view')) { if (permissionStore.hasPermission('iot-card/CardManagement:view') && isNoCommunity) {
list.value.push({ list.value.push({
key: 'CardManagement', key: 'CardManagement',
tab: '物联网卡', 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({ list.value.push({
key: 'Firmware', key: 'Firmware',
tab: '远程升级', tab: '远程升级',

View File

@ -1,6 +1,9 @@
<!-- 设备接入 --> <!-- 设备接入 -->
<template> <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"> <j-empty :image="simpleImage">
<template #description> <template #description>
<span <span
@ -25,7 +28,7 @@
type="primary" type="primary"
size="small" size="small"
:tooltip="{ :tooltip="{
title: tooltip title: tooltip,
}" }"
:disabled="checkDisabled" :disabled="checkDisabled"
ghost ghost
@ -74,25 +77,32 @@
<div v-else>{{ '暂无连接信息' }}</div> <div v-else>{{ '暂无连接信息' }}</div>
</div> </div>
<!-- 产品类型 --> <!-- 产品类型 -->
<j-form ref="pluginFormRef" :model="productData" layout="vertical" v-if='productTypes.length'> <j-form
<j-form-item name='id' label='产品类型' :rules='[{ required: true, message: "请选择产品类型"}]'> ref="pluginFormRef"
:model="productData"
layout="vertical"
v-if="productTypes.length"
>
<j-form-item
name="id"
label="产品类型"
:rules="[{ required: true, message: '请选择产品类型' }]"
>
<j-select <j-select
v-model:value='productData.id' v-model:value="productData.id"
:options='productTypes' :options="productTypes"
@change='productTypeChange' @change="productTypeChange"
placeholder='请选择产品类型' placeholder="请选择产品类型"
/> />
</j-form-item> </j-form-item>
</j-form> </j-form>
<!-- 其它接入配置 --> <!-- 其它接入配置 -->
<Title <div v-for="(i,index) in metadata">
v-if="metadata?.name" <Title v-if="i?.name" :data="i?.name" class="config">
:data="metadata?.name"
class="config"
>
<template #extra> <template #extra>
<j-tooltip title="此配置来自于产品接入方式所选择的协议"> <j-tooltip
title="此配置来自于产品接入方式所选择的协议"
>
<AIcon <AIcon
type="QuestionCircleOutlined" type="QuestionCircleOutlined"
style="margin-left: 2px" style="margin-left: 2px"
@ -100,10 +110,14 @@
</j-tooltip> </j-tooltip>
</template> </template>
</Title> </Title>
<j-form ref="formRef" :model="formData.data" layout="vertical"> <j-form
ref="formRef"
:model="formData.data"
layout="vertical"
>
<j-form-item <j-form-item
:name="item.property" :name="item.property"
v-for="item in metadata?.properties || []" v-for="item in i?.properties || []"
:key="item" :key="item"
:label="item.name" :label="item.name"
:rules="[ :rules="[
@ -129,7 +143,10 @@
></j-input-password> ></j-input-password>
<j-select <j-select
placeholder="请选择" placeholder="请选择"
v-if="item.type.type === 'enum' || item.type.type === 'boolean'" v-if="
item.type.type === 'enum' ||
item.type.type === 'boolean'
"
v-model:value="formData.data[item.property]" v-model:value="formData.data[item.property]"
:options="getOptions(item)" :options="getOptions(item)"
> >
@ -144,9 +161,18 @@
{{ el.text }} {{ el.text }}
</j-select-option> --> </j-select-option> -->
</j-select> </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-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-item>
</j-form> </j-form>
</div>
<Title data="存储策略"> <Title data="存储策略">
<template #extra> <template #extra>
<j-tooltip <j-tooltip
@ -175,7 +201,7 @@
type="primary" type="primary"
@click="submitDevice" @click="submitDevice"
hasPermission="device/Instance:update" hasPermission="device/Instance:update"
:loading='submitLoading' :loading="submitLoading"
>保存</PermissionButton >保存</PermissionButton
> >
</j-col> </j-col>
@ -254,26 +280,30 @@
</div> </div>
<!-- 选择设备 --> <!-- 选择设备 -->
<AccessModal <AccessModal
v-if='visible' v-if="visible"
:product-id='productStore.current.id' :product-id="productStore.current.id"
:deviceType='productStore.current.deviceType' :deviceType="productStore.current.deviceType"
:accessId='accessId' :accessId="accessId"
:providersList='dataSource' :providersList="dataSource"
@cancel=' visible = false' @cancel="visible = false"
@submit='checkAccess' @submit="checkAccess"
/> />
<!-- 物模型处理方式 --> <!-- 物模型处理方式 -->
<MetaDataModal <MetaDataModal
v-if='metadataVisible' v-if="metadataVisible"
:metadata='productData.metadata' :metadata="productData.metadata"
:access='access' :access="access"
:data='metadataModalCacheData' :data="metadataModalCacheData"
@cancel=' () => { metadataVisible = false, metadataModalCacheData = {}}' @cancel="
@submit='MetaDataModalSubmit' () => {
(metadataVisible = false), (metadataModalCacheData = {});
}
"
@submit="MetaDataModalSubmit"
/> />
</template> </template>
<script lang="ts" setup name='AccessConfig'> <script lang="ts" setup name="AccessConfig">
import { useProductStore } from '@/store/product'; import { useProductStore } from '@/store/product';
import { ConfigMetadata } from '@/views/device/Product/typings'; import { ConfigMetadata } from '@/views/device/Product/typings';
import { Empty } from 'jetlinks-ui-components'; import { Empty } from 'jetlinks-ui-components';
@ -294,8 +324,9 @@ import {
saveDevice, saveDevice,
updateDevice, updateDevice,
detail, detail,
modify, getAccessConfig modify,
} from '@/api/device/product' getAccessConfig,
} from '@/api/device/product';
import Driver from 'driver.js'; import Driver from 'driver.js';
import 'driver.js/dist/driver.min.css'; import 'driver.js/dist/driver.min.css';
@ -304,16 +335,20 @@ import type { TableColumnType } from 'ant-design-vue';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import _ from 'lodash-es'; import _ from 'lodash-es';
import { accessConfigTypeFilter } from '@/utils/setting'; import { accessConfigTypeFilter } from '@/utils/setting';
import AccessModal from './accessModal.vue' import AccessModal from './accessModal.vue';
import MetaDataModal from './metadataModal.vue' import MetaDataModal from './metadataModal.vue';
import { getPluginData, getProductByPluginId, savePluginData } from '@/api/link/plugin' import {
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig' getPluginData,
getProductByPluginId,
savePluginData,
} from '@/api/link/plugin';
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { pick } from 'lodash-es'; import { pick } from 'lodash-es';
const productStore = useProductStore(); const productStore = useProductStore();
const tableRef = ref(); const tableRef = ref();
const formRef = ref(); const formRef = ref([]);
const menuStore = useMenuStore(); const menuStore = useMenuStore();
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
const render = new marked.Renderer(); const render = new marked.Renderer();
@ -326,9 +361,9 @@ marked.setOptions({
const simpleImage = ref(Empty.PRESENTED_IMAGE_SIMPLE); const simpleImage = ref(Empty.PRESENTED_IMAGE_SIMPLE);
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const access = ref<Record<string, any>>({}); 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 config = ref<any>({});
const metadata = ref<ConfigMetadata>({ properties: [] }); const metadata = ref<ConfigMetadata[]>([{ properties: [] }]);
const dataSource = ref<string[]>([]); const dataSource = ref<string[]>([]);
const storageList = ref<any[]>([]); const storageList = ref<any[]>([]);
const markdownToHtml = shallowRef(''); const markdownToHtml = shallowRef('');
@ -350,7 +385,7 @@ const formData = reactive<Record<string, any>>({
data: productStore.current?.configuration || {}, data: productStore.current?.configuration || {},
}); });
// //
const getOptions = (i:any) =>{ const getOptions = (i: any) => {
if (i.type.type === 'enum') { if (i.type.type === 'enum') {
return (i.type?.elements || []).map((item) => { return (i.type?.elements || []).map((item) => {
return { return {
@ -367,26 +402,26 @@ const getOptions = (i:any) =>{
{ {
label: i.type?.trueText, label: i.type?.trueText,
value: i.type?.trueValue, value: i.type?.trueValue,
} },
]; ];
} }
return undefined; return undefined;
} };
const fun = () =>{ const fun = () => {
console.log(formData.data,productStore.current?.configuration) console.log(formData.data, productStore.current?.configuration);
} };
fun() fun();
// //
const productTypes = ref([]) const productTypes = ref([]);
const productData = reactive({ const productData = reactive({
id: undefined, id: undefined,
metadata: {} // metadata: {}, //
}) });
const pluginFormRef = ref() const pluginFormRef = ref();
const metadataVisible = ref(false) const metadataVisible = ref(false);
const metadataModalCacheData = ref() const metadataModalCacheData = ref();
const submitLoading = ref(false) const submitLoading = ref(false);
/** /**
* 显示弹窗 * 显示弹窗
*/ */
@ -555,8 +590,15 @@ const queryAccessDetail = async (id: string) => {
if (res.status === 200) { if (res.status === 200) {
access.value = res.result.data[0]; access.value = res.result.data[0];
if (access.value?.transportDetail?.metadata) { if (access.value?.transportDetail?.metadata) {
const metadata = JSON.parse(access.value?.transportDetail?.metadata) const metadata = JSON.parse(
productData.metadata = pick(metadata,['functions','properties','events','tags']) access.value?.transportDetail?.metadata,
);
productData.metadata = pick(metadata, [
'functions',
'properties',
'events',
'tags',
]);
} }
} }
}); });
@ -577,13 +619,10 @@ const handleColumns = () => {
}; };
const list = config.value?.routes || []; const list = config.value?.routes || [];
const arr = list.filter( const arr = list.filter((res: any) => res.group === record.group);
(res: any) => res.group === record.group,
);
const isRowIndex = const isRowIndex =
rowIndex === 0 || rowIndex === 0 || list[rowIndex - 1].group !== record.group;
list[rowIndex - 1].group !== record.group;
isRowIndex && (obj.rowSpan = arr.length); isRowIndex && (obj.rowSpan = arr.length);
return obj; return obj;
@ -591,7 +630,7 @@ const handleColumns = () => {
}; };
columnsMQTT.value = [Group, ...ColumnsMQTT]; columnsMQTT.value = [Group, ...ColumnsMQTT];
columnsHTTP.value = [Group, ...ColumnsHTTP]; columnsHTTP.value = [Group, ...ColumnsHTTP];
} };
/** /**
* 查询协议信息 * 查询协议信息
@ -603,7 +642,7 @@ const getConfigDetail = (
getConfigView(messageProtocol, transportProtocol).then((resp) => { getConfigView(messageProtocol, transportProtocol).then((resp) => {
if (resp.status === 200) { if (resp.status === 200) {
config.value = resp.result; config.value = resp.result;
handleColumns() handleColumns();
if (config.value?.document) { if (config.value?.document) {
markdownToHtml.value = marked(config.value.document); markdownToHtml.value = marked(config.value.document);
} }
@ -640,19 +679,21 @@ const getGuide = async (isDriver1: boolean = false) => {
}; };
const checkAccess = async (data: any) => { const checkAccess = async (data: any) => {
console.log(data) visible.value = false;
visible.value = false accessId.value = data.access.id;
accessId.value = data.access.id access.value = data.access;
access.value = data.access config.value = data.access?.transportDetail || {};
config.value = data.access?.transportDetail || {} productTypes.value = [];
productTypes.value = [] productData.id = undefined;
productData.id = undefined productData.metadata = {};
productData.metadata = {} metadata.value = data.metadata || [
metadata.value = data.metadata?.[0] || { {
properties: [] properties: [],
} },
if (metadata.value?.properties) { ];
metadata.value?.properties.forEach((item) => { if (metadata.value.length) {
metadata.value.forEach((i: any) => {
i?.properties.forEach((item: any) => {
if ( if (
item.name === '流传输模式' && item.name === '流传输模式' &&
(!productStore.current?.configuration || (!productStore.current?.configuration ||
@ -664,25 +705,40 @@ const checkAccess = async (data: any) => {
item.type.expands?.defaultValue; item.type.expands?.defaultValue;
} }
}); });
});
} }
if (data.access.channel === 'plugin') { // if (data.access.channel === 'plugin') {
markdownToHtml.value = '' //
productTypes.value = data.productTypes.map(item => ({ ...item, label: item.name, value: item.id})) markdownToHtml.value = '';
productTypes.value = data.productTypes.map((item) => ({
...item,
label: item.name,
value: item.id,
}));
} else { } else {
handleColumns() handleColumns();
markdownToHtml.value = config.value?.document ? marked(config.value.document) : ''; markdownToHtml.value = config.value?.document
? marked(config.value.document)
: '';
getGuide(!!data.metadata.length); // getGuide(!!data.metadata.length); //
if (data.access?.transportDetail?.metadata) { if (data.access?.transportDetail?.metadata) {
const metadata = JSON.parse(data.access?.transportDetail?.metadata) const metadata = JSON.parse(data.access?.transportDetail?.metadata);
productData.metadata = pick(metadata,['functions','properties','events','tags']) productData.metadata = pick(metadata, [
'functions',
'properties',
'events',
'tags',
]);
} }
} }
} };
const productTypeChange = (id: string, items: any) => { 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'])
: {};
};
/** /**
* 获取协议类型名称 * 获取协议类型名称
@ -699,12 +755,15 @@ const getData = async (accessId?: string) => {
const _accessId = accessId || productStore.current?.accessId; const _accessId = accessId || productStore.current?.accessId;
if (productStore.current?.id) { if (productStore.current?.id) {
getConfigMetadata(productStore.current?.id).then((resp: any) => { getConfigMetadata(productStore.current?.id).then((resp: any) => {
metadata.value = (resp?.result[0] as ConfigMetadata) || { metadata.value = resp?.result || [
{
properties: [], properties: [],
}; },
];
// udp // udp
if (metadata.value?.properties) { if (metadata.value.length) {
metadata.value?.properties.forEach((item) => { metadata.value.forEach((i: any) => {
i?.properties.forEach((item: any) => {
if ( if (
item.name === '流传输模式' && item.name === '流传输模式' &&
(!productStore.current?.configuration || (!productStore.current?.configuration ||
@ -716,6 +775,7 @@ const getData = async (accessId?: string) => {
item.type.expands?.defaultValue; item.type.expands?.defaultValue;
} }
}); });
});
} }
if (accessId) { if (accessId) {
// //
@ -731,29 +791,43 @@ const getData = async (accessId?: string) => {
// } // }
queryAccessDetail(_accessId); queryAccessDetail(_accessId);
if (productStore.current?.accessProvider === 'plugin_gateway') { if (productStore.current?.accessProvider === 'plugin_gateway') {
queryPluginAccessDetail(_accessId).then(async res => { // queryPluginAccessDetail(_accessId).then(async (res) => {
//
if (res.success) { if (res.success) {
const pluginRes = await getPluginData('product', _accessId, productStore.current?.id) const pluginRes = await getPluginData(
const resp = await getProductByPluginId(res.result.channelId).catch(() => ({ success: false, result: []})) 'product',
_accessId,
productStore.current?.id,
);
const resp = await getProductByPluginId(
res.result.channelId,
).catch(() => ({ success: false, result: [] }));
if (resp.success) { if (resp.success) {
productTypes.value = resp.result.map(item => { productTypes.value = resp.result.map((item) => {
if (pluginRes?.result?.externalId === item.id) { if (pluginRes?.result?.externalId === item.id) {
productData.id = pluginRes?.result?.externalId productData.id = pluginRes?.result?.externalId;
productData.metadata = pick(item.metadata,['functions','properties','events','tags']) 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 { } else {
getConfigDetail( getConfigDetail(
productStore.current?.messageProtocol || '', productStore.current?.messageProtocol || '',
productStore.current?.transportProtocol || '', productStore.current?.transportProtocol || '',
); );
} }
} }
getStoragList().then((resp: any) => { getStoragList().then((resp: any) => {
if (resp.status === 200) { if (resp.status === 200) {
@ -766,52 +840,56 @@ const getData = async (accessId?: string) => {
* 保存设备接入 * 保存设备接入
*/ */
const submitDevice = async () => { const submitDevice = async () => {
if (pluginFormRef.value) { // if (pluginFormRef.value) {
//
const pluginRef = await pluginFormRef.value.validate(); const pluginRef = await pluginFormRef.value.validate();
if (!pluginRef) return if (!pluginRef) return;
} }
const allValidate = formRef.value.map((item:any)=>{
const res = await formRef.value.validate(); return item?.validate()
if (!res) return })
const res = await Promise.all(allValidate)
// const res = await formRef.value.validate();
if (!res) return;
const values = { storePolicy: form.storePolicy, ...formData.data }; const values = { storePolicy: form.storePolicy, ...formData.data };
const id = productStore.current?.id; const id = productStore.current?.id;
// //
const _metadata = JSON.parse(productStore.current?.metadata || '{}') const _metadata = JSON.parse(productStore.current?.metadata || '{}');
if ( if (
(_metadata.properties?.length || (_metadata.properties?.length ||
_metadata.events?.length || _metadata.events?.length ||
_metadata.functions?.length || _metadata.functions?.length ||
_metadata.tags?.length _metadata.tags?.length) &&
) && (productData.metadata?.properties?.length ||
(
productData.metadata?.properties?.length ||
productData.metadata?.events?.length || productData.metadata?.events?.length ||
productData.metadata?.functions?.length || productData.metadata?.functions?.length ||
productData.metadata?.tags?.length productData.metadata?.tags?.length)
)
) { ) {
metadataModalCacheData.value = { metadataModalCacheData.value = {
id, id,
values, values,
productTypeId: productData.id productTypeId: productData.id,
} };
metadataVisible.value = true metadataVisible.value = true;
} else { } else {
updateAccessData(id, values) updateAccessData(id, values);
} }
}; };
const updateAccessData = async (id: string, values: any) => { const updateAccessData = async (id: string, values: any) => {
const result: any = {}; const result: any = {};
// flatObj(values, result); // flatObj(values, result);
// const { storePolicy, ...extra } = result; // const { storePolicy, ...extra } = result;
const { storePolicy, ...extra } = values const { storePolicy, ...extra } = values;
// undefinednull // undefinednull
let _metadata = '' let _metadata = '';
if (productStore.current?.metadata) { if (productStore.current?.metadata) {
_metadata = productStore.current?.metadata _metadata = productStore.current?.metadata;
} else if (productData.metadata && Object.keys(productData.metadata).length) { } else if (
_metadata = JSON.stringify(productData.metadata) productData.metadata &&
Object.keys(productData.metadata).length
) {
_metadata = JSON.stringify(productData.metadata);
} }
// () // ()
const accessObj = { const accessObj = {
@ -823,30 +901,32 @@ const updateAccessData = async (id: string, values: any) => {
accessName: access.value?.name, accessName: access.value?.name,
accessProvider: access.value?.provider, accessProvider: access.value?.provider,
messageProtocol: access.value?.protocol, messageProtocol: access.value?.protocol,
} };
submitLoading.value = true submitLoading.value = true;
const updateDeviceResp = await updateDevice(accessObj).catch(() => { success: false}) const updateDeviceResp = await updateDevice(accessObj).catch(() => {
success: false;
});
if (!updateDeviceResp.success) { if (!updateDeviceResp.success) {
submitLoading.value = false submitLoading.value = false;
} }
if (access.value?.provider === "plugin_gateway" && productData.id) { if (access.value?.provider === 'plugin_gateway' && productData.id) {
await savePluginData( await savePluginData(
'product', 'product',
access.value?.id, access.value?.id,
productStore.current.id, productStore.current.id,
productData.id productData.id,
).catch(() => ({})) ).catch(() => ({}));
} }
// //
const resp = await modify(id || '', { const resp = await modify(id || '', {
id: id, id: id,
configuration: { ...extra }, configuration: { ...extra },
storePolicy: storePolicy, storePolicy: storePolicy,
}).finally(()=>{ }).finally(() => {
submitLoading.value = false submitLoading.value = false;
}) });
if (resp.status === 200) { if (resp.status === 200) {
onlyMessage('操作成功!'); onlyMessage('操作成功!');
productStore.current!.storePolicy = storePolicy; productStore.current!.storePolicy = storePolicy;
@ -859,7 +939,7 @@ const updateAccessData = async (id: string, values: any) => {
getDetailInfo(); getDetailInfo();
} }
} }
} };
const flatObj = (obj: any, result: any) => { const flatObj = (obj: any, result: any) => {
Object.keys(obj).forEach((key: string) => { Object.keys(obj).forEach((key: string) => {
@ -872,16 +952,16 @@ const flatObj = (obj: any, result: any) => {
}; };
const getDetailInfo = async () => { const getDetailInfo = async () => {
await productStore.getDetail(productStore.detail.id) await productStore.getDetail(productStore.detail.id);
MetaDataModalSubmit() MetaDataModalSubmit();
}; };
const MetaDataModalSubmit = () => { const MetaDataModalSubmit = () => {
// //
productStore.tabActiveKey = 'Metadata' productStore.tabActiveKey = 'Metadata';
} };
getProvidersList() getProvidersList();
/** /**
* 初始化 * 初始化
*/ */
@ -893,20 +973,20 @@ watchEffect(() => {
const tooltip = computed(() => { const tooltip = computed(() => {
if (productStore.current?.count > 0) { if (productStore.current?.count > 0) {
return '产品下有设备实例时不能更换接入方式' return '产品下有设备实例时不能更换接入方式';
} }
if (productStore.current.state === 1) { if (productStore.current.state === 1) {
return '停用产品后才可更换接入方式' return '停用产品后才可更换接入方式';
} }
return '' return '';
}) });
const checkDisabled = computed(() => { const checkDisabled = computed(() => {
if (productStore.current?.count > 0 || productStore.current.state === 1) { if (productStore.current?.count > 0 || productStore.current.state === 1) {
return true return true;
} }
return false return false;
}) });
nextTick(() => { nextTick(() => {
getData(); getData();

View File

@ -160,7 +160,10 @@ import { useMenuStore } from '@/store/menu';
import { useRouterParams } from '@/utils/hooks/useParams'; import { useRouterParams } from '@/utils/hooks/useParams';
import { EventEmitter } from '@/utils/utils'; import { EventEmitter } from '@/utils/utils';
import { usePermissionStore } from '@/store/permission'; import { usePermissionStore } from '@/store/permission';
import { isNoCommunity } from '@/utils/utils';
import { useSystem } from '@/store/system';
const { showThreshold } = useSystem()
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
const menuStory = useMenuStore(); const menuStory = useMenuStore();
const route = useRoute(); const route = useRoute();
@ -274,45 +277,29 @@ const getProtocol = async () => {
productStore.current?.messageProtocol, productStore.current?.messageProtocol,
); );
if (res.status === 200) { 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', (item: any) => item.id === 'transparentCodec',
); );
const supportFirmware = transport?.features?.find(
(item: any) => item.id === 'supportFirmware',
);
if (paring) { if (paring) {
list.value = [ list.value.push({
{
key: 'Info',
tab: '配置信息',
},
{
key: 'Metadata',
tab: '物模型',
class: 'objectModel',
},
{
key: 'Device',
tab: '设备接入',
},
{
key: 'DataAnalysis', key: 'DataAnalysis',
tab: '数据解析', tab: '数据解析',
}, });
]; }
} else { if (
list.value = [ supportFirmware &&
{ permissionStore.hasPermission('device/Firmware:view') && isNoCommunity
key: 'Info', ) {
tab: '配置信息', list.value.push({
}, key: 'Firmware',
{ tab: '远程升级',
key: 'Metadata', });
tab: '物模型',
class: 'objectModel',
},
{
key: 'Device',
tab: '设备接入',
},
];
} }
} }
// //
@ -329,19 +316,13 @@ const getProtocol = async () => {
if ( if (
permissionStore.hasPermission( permissionStore.hasPermission(
'rule-engine/Alarm/Configuration:view', 'rule-engine/Alarm/Configuration:view',
) ) && isNoCommunity && showThreshold
) { ) {
list.value.push({ list.value.push({
key: 'AlarmRecord', key: 'AlarmRecord',
tab: '预处理数据', tab: '预处理数据',
}); });
} }
if (permissionStore.hasPermission('device/Firmware:view')) {
list.value.push({
key: 'Firmware',
tab: '远程升级',
});
}
} }
}; };
/** /**

View File

@ -653,6 +653,11 @@ watch(() => metadata.value, () => {
group: undefined group: undefined
} }
} }
if(props.type === 'functions' && !item.output){
item['output'] = {
}
}
return item return item
}) })
initOptions(dataSource.value) initOptions(dataSource.value)

View File

@ -268,6 +268,7 @@ import { omit, cloneDeep } from 'lodash-es';
import { PopoverModal } from '@/components/Metadata/Table'; import { PopoverModal } from '@/components/Metadata/Table';
import { useTableWrapper } from '@/components/Metadata/Table/context'; import { useTableWrapper } from '@/components/Metadata/Table/context';
import { useThreshold } from './hooks'; import { useThreshold } from './hooks';
import { useSystem } from '@/store/system';
const props = defineProps({ const props = defineProps({
value: { value: {
@ -309,6 +310,7 @@ const props = defineProps({
const type = inject('_metadataType'); const type = inject('_metadataType');
const { showThreshold } = useSystem()
const productStore = useProductStore(); const productStore = useProductStore();
const deviceStore = useInstanceStore(); const deviceStore = useInstanceStore();
const tableWrapperRef = useTableWrapper(); const tableWrapperRef = useTableWrapper();
@ -382,7 +384,7 @@ const showMetrics = computed(() => {
const showExtra = computed(() => { const showExtra = computed(() => {
return ( return (
['int', 'long', 'float', 'double'].includes(props.type as any) && ['int', 'long', 'float', 'double'].includes(props.type as any) &&
props.metadataType === 'properties' props.metadataType === 'properties' && showThreshold
); );
}); });

View File

@ -90,7 +90,7 @@ export const useThreshold = (props: Record<string, any>) => {
} }
const thresholdDetailQuery = () => { const thresholdDetailQuery = () => {
if (props.target === 'product') { if (props.target === 'product') {
queryProduct(productStore.current.id, props.id) queryProduct(productStore.current.id, props.id,false)
} else { } else {
queryDevice(deviceStore.current.productId, deviceStore.current.id, props.id) queryDevice(deviceStore.current.productId, deviceStore.current.id, props.id)
} }

File diff suppressed because it is too large Load Diff

View File

@ -204,11 +204,7 @@ const rules = {
}; };
const filterOption = (input: string, option: any) => { const filterOption = (input: string, option: any) => {
return ( return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
option.componentOptions.children[0].text
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
);
}; };
const platformConfigList = computed(() => { const platformConfigList = computed(() => {

View File

@ -45,7 +45,7 @@
<j-col :span="8"> <j-col :span="8">
<div class="data-statistics-item"> <div class="data-statistics-item">
<div class="flow-info" style="width: 100%"> <div class="flow-info" style="width: 100%">
<div class="label">本年流量消耗1</div> <div class="label">本年流量消耗</div>
<j-tooltip placement="bottomLeft"> <j-tooltip placement="bottomLeft">
<template #title> <template #title>
<span>{{ yearTotal }} M</span> <span>{{ yearTotal }} M</span>

View File

@ -9,7 +9,7 @@
/> />
<div class="right"> <div class="right">
<pro-search <pro-search
:columns="columns" :columns="newColumns"
target="channel" target="channel"
@search="handleSearch" @search="handleSearch"
/> />
@ -17,7 +17,7 @@
<JProTable <JProTable
ref="listRef" ref="listRef"
model="table" model="table"
:columns="columns" :columns="newColumns"
:request="(e:any) => ChannelApi.list(e, route?.query.id as string)" :request="(e:any) => ChannelApi.list(e, route?.query.id as string)"
:defaultParams="{ :defaultParams="{
sorts: [{ name: 'modifyTime', order: 'desc' }], 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 params = ref<Record<string, any>>({});
const deviceData = ref<any>(); const deviceData = ref<any>();

View File

@ -32,6 +32,7 @@
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
padding-left: @padding; padding-left: @padding;
height: calc(100vh - 190px);
.top { .top {
display: flex; display: flex;

View File

@ -151,8 +151,10 @@ const getTemplateList = async () => {
}; };
const { result } = await ConfigApi.getTemplate(params, props.data.id); const { result } = await ConfigApi.getTemplate(params, props.data.id);
templateList.value = result; templateList.value = result;
if (result.length) {
formData.value.templateId = result[0]?.id as string; formData.value.templateId = result[0]?.id as string;
getTemplateDetail(); getTemplateDetail();
}
}; };
watch( watch(

View File

@ -207,7 +207,7 @@ const onTreeSelect = (keys: any) => {
const columns = [ const columns = [
{ {
title: '钉钉用户名', title: props.data.type === 'weixin' ? '企业微信用户名' : '钉钉用户名',
dataIndex: 'thirdPartyUserName', dataIndex: 'thirdPartyUserName',
key: 'thirdPartyUserName', key: 'thirdPartyUserName',
}, },

View File

@ -3,7 +3,7 @@
<page-container> <page-container>
<pro-search <pro-search
:columns="columns" :columns="columns"
target="notice-config" target="notice-template"
@search="handleSearch" @search="handleSearch"
/> />
<FullPage> <FullPage>

View File

@ -34,7 +34,7 @@
{{ value.name }} {{ value.name }}
</span> </span>
</Ellipsis> </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 style="margin-top: 16px; margin-bottom: 8px" class="card-item-content-text">
关联条件 关联条件
</div> </div>

View File

@ -1,92 +1,97 @@
<template> <template>
<j-form <j-form ref="timerForm" :model="formModel" :colon="false" layout="vertical">
ref='timerForm' <j-form-item name="trigger">
:model='formModel'
:colon='false'
layout='vertical'
>
<j-form-item name='trigger'>
<j-radio-group <j-radio-group
v-model:value='formModel.trigger' v-model:value="formModel.trigger"
:options='triggerOptions' :options="triggerOptions"
option-type='button' option-type="button"
button-style='solid' button-style="solid"
@change='triggerChange' @change="triggerChange"
/> />
</j-form-item> </j-form-item>
<j-form-item v-if='showCron' name='cron' :rules="cronRules"> <j-form-item v-if="showCron" name="cron" :rules="cronRules">
<j-input placeholder='corn表达式' v-model:value='formModel.cron' @change='updateValue' /> <j-input
placeholder="corn表达式"
v-model:value="formModel.cron"
@change="updateValue"
/>
</j-form-item> </j-form-item>
<j-form-item v-else-if="showMulti" name="multi" :rules="multiRules"> <j-form-item v-else-if="showMulti" name="multi" :rules="multiRules">
<Calendar v-model:value="formModel.multi" @change='updateValue'/> <Calendar v-model:value="formModel.multi" @change="updateValue" />
</j-form-item> </j-form-item>
<template v-else> <template v-else>
<j-form-item name='when'> <j-form-item name="when">
<WhenOption v-model:value='formModel.when' :type='formModel.trigger' @change='updateValue' /> <WhenOption
v-model:value="formModel.when"
:type="formModel.trigger"
@change="updateValue"
/>
</j-form-item> </j-form-item>
<j-form-item name='mod'> <j-form-item name="mod">
<j-radio-group <j-radio-group
v-model:value='formModel.mod' v-model:value="formModel.mod"
:options='[ :options="[
{ label: "周期执行", value: "period" }, { label: '周期执行', value: 'period' },
{ label: "执行一次", value: "once" }, { label: '执行一次', value: 'once' },
]' ]"
option-type='button' option-type="button"
button-style='solid' button-style="solid"
@change='updateValue' @change="updateValue"
/> />
</j-form-item> </j-form-item>
</template> </template>
<j-space v-if='showOnce && !showMulti' style='display: flex;gap: 24px'> <j-space v-if="showOnce && !showMulti" style="display: flex; gap: 24px">
<j-form-item :name="['once', 'time']"> <j-form-item :name="['once', 'time']">
<j-time-picker <j-time-picker
valueFormat='HH:mm:ss' valueFormat="HH:mm:ss"
v-model:value='formModel.once.time' v-model:value="formModel.once.time"
style='width: 100%' style="width: 100%"
format='HH:mm:ss' format="HH:mm:ss"
@change='updateValue' @change="updateValue"
/> />
</j-form-item> </j-form-item>
<j-form-item> 执行一次</j-form-item> <j-form-item> 执行一次</j-form-item>
</j-space> </j-space>
<j-space v-if='showPeriod && !showMulti' style='display: flex;gap: 24px'> <j-space
v-if="showPeriod && !showMulti"
style="display: flex; gap: 24px"
>
<j-form-item> <j-form-item>
<j-time-range-picker <j-time-range-picker
valueFormat='HH:mm:ss' valueFormat="HH:mm:ss"
:value='[ :value="[formModel.period.from, formModel.period.to]"
formModel.period.from, @change="
formModel.period.to, (v) => {
]' formModel.period.from = v[0];
@change='(v) => { formModel.period.to = v[1];
formModel.period.from = v[0] updateValue();
formModel.period.to = v[1] }
updateValue() "
}'
/> />
</j-form-item> </j-form-item>
<j-form-item></j-form-item> <j-form-item></j-form-item>
<j-form-item <j-form-item
:name='["period", "every"]' :name="['period', 'every']"
:rules='[{ required: true, message: "请输入时间" }]' :rules="[{ required: true, message: '请输入时间' }]"
> >
<j-input-number <j-input-number
placeholder='请输入时间' placeholder="请输入时间"
style='max-width: 170px' style="max-width: 170px"
:precision='0' :precision="0"
:min='1' :min="1"
:max='unitMax' :max="unitMax"
v-model:value='formModel.period.every' v-model:value="formModel.period.every"
@change='updateValue' @change="updateValue"
> >
<template #addonAfter> <template #addonAfter>
<j-select <j-select
v-model:value='formModel.period.unit' v-model:value="formModel.period.unit"
:options='[ :options="[
{ label: "秒", value: "seconds" }, { label: '秒', value: 'seconds' },
{ label: "分", value: "minutes" }, { label: '分', value: 'minutes' },
{ label: "小时", value: "hours" }, { label: '小时', value: 'hours' },
]' ]"
@select='periodUnitChange' @select="periodUnitChange"
/> />
</template> </template>
</j-input-number> </j-input-number>
@ -96,48 +101,48 @@
</j-form> </j-form>
</template> </template>
<script setup lang='ts' name='Timer'> <script setup lang="ts" name="Timer">
import type { PropType } from 'vue' import type { PropType } from 'vue';
import dayjs from 'dayjs' import dayjs from 'dayjs';
import WhenOption from './WhenOption.vue' import WhenOption from './WhenOption.vue';
import {cloneDeep, pick} from 'lodash-es' import { cloneDeep, pick } from 'lodash-es';
import type { OperationTimer } from '../../../typings' import type { OperationTimer } from '../../../typings';
import { defineExpose } from 'vue' import { defineExpose } from 'vue';
import Calendar from './Calendar.vue' import Calendar from './Calendar.vue';
import cronstrue from 'cronstrue' import cronstrue from 'cronstrue';
import { isNoCommunity } from '@/utils/utils';
type NameType = string[] | string type NameType = string[] | string;
type Emit = { type Emit = {
(e: 'update:value', data: Partial<OperationTimer>): void (e: 'update:value', data: Partial<OperationTimer>): void;
} };
const props = defineProps({ const props = defineProps({
name: { name: {
type: [String, Array] as PropType<NameType>, type: [String, Array] as PropType<NameType>,
default: '' default: '',
}, },
value: { value: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
type: { type: {
type: String, type: String,
default: undefined default: undefined,
} },
}) });
const emit = defineEmits<Emit>() const emit = defineEmits<Emit>();
const unitMax = ref<number>(99) const unitMax = ref<number>(99);
const cronRules = [ const cronRules = [
{ max: 64, message: '最多可输入64个字符' }, { max: 64, message: '最多可输入64个字符' },
{ {
validator: async (_: any, v: string) => { validator: async (_: any, v: string) => {
if (v) { if (v) {
try { try {
console.log(v, cronstrue.toString(v)) console.log(v, cronstrue.toString(v));
} catch (e) { } catch (e) {
return Promise.reject(new Error('请输入正确的cron表达式')); return Promise.reject(new Error('请输入正确的cron表达式'));
} }
@ -145,9 +150,9 @@ const cronRules = [
return Promise.reject(new Error('请输入cron表达式')); return Promise.reject(new Error('请输入cron表达式'));
} }
return Promise.resolve(); return Promise.resolve();
} },
} },
] ];
const multiRules = [ const multiRules = [
{ {
@ -155,23 +160,29 @@ const multiRules = [
if (!v.spec?.length) { if (!v.spec?.length) {
return Promise.reject('请添加自定义日历规则'); return Promise.reject('请添加自定义日历规则');
} else { } else {
const index = v.spec.findIndex(item => !item.scheduleTags.length) const index = v.spec.findIndex(
(item) => !item.scheduleTags.length,
);
if (index > -1) { if (index > -1) {
return Promise.reject(`规则【${index + 1}】请选择日期类型`); return Promise.reject(`规则【${index + 1}】请选择日期类型`);
} }
} }
return Promise.resolve() return Promise.resolve();
} },
} },
] ];
const triggerOptions = computed(() => { const triggerOptions = computed(() => {
let _options = [ let _options = isNoCommunity ? [
{ label: "按周", value: "week" }, { label: '按周', value: 'week' },
{ label: "按月", value: "month" }, { label: '按月', value: 'month' },
{ label: "cron表达式", value: "cron" }, { label: 'cron表达式', value: 'cron' },
{ label: "自定义日历", value: "multi" } { label: '自定义日历', value: 'multi' },
] : [
{ label: '按周', value: 'week' },
{ label: '按月', value: 'month' },
{ label: 'cron表达式', value: 'cron' },
] ]
// if (props.type === 'timer') { // if (props.type === 'timer') {
@ -179,8 +190,8 @@ const triggerOptions = computed(() => {
// label: "", value: "multi" // label: "", value: "multi"
// }] // }]
// } // }
return _options return _options;
}) });
const formModel = reactive<OperationTimer>({ const formModel = reactive<OperationTimer>({
trigger: 'week', trigger: 'week',
@ -188,98 +199,93 @@ const formModel = reactive<OperationTimer>({
mod: 'period', mod: 'period',
cron: undefined, cron: undefined,
once: { once: {
time: dayjs(new Date()).format('HH:mm:ss') time: dayjs(new Date()).format('HH:mm:ss'),
}, },
period: { period: {
from: dayjs(new Date()).startOf('day').format('HH:mm:ss'), from: dayjs(new Date()).startOf('day').format('HH:mm:ss'),
to: dayjs(new Date()).endOf('day').format('HH:mm:ss'), to: dayjs(new Date()).endOf('day').format('HH:mm:ss'),
every: 1, every: 1,
unit: 'seconds' unit: 'seconds',
}, },
multi: { multi: {
type: "and", type: 'and',
spec: [] spec: [],
} },
}) });
const timerForm = ref() const timerForm = ref();
const showCron = computed(() => { const showCron = computed(() => {
return formModel.trigger === 'cron' return formModel.trigger === 'cron';
}) });
const showMulti = computed(() => { const showMulti = computed(() => {
return formModel.trigger === 'multi' return formModel.trigger === 'multi';
}) });
const showOnce = computed(() => { const showOnce = computed(() => {
return formModel.trigger !== 'cron' && formModel.mod === 'once' return formModel.trigger !== 'cron' && formModel.mod === 'once';
}) });
const showPeriod = computed(() => { const showPeriod = computed(() => {
return formModel.trigger !== 'cron' && formModel.mod === 'period' return formModel.trigger !== 'cron' && formModel.mod === 'period';
}) });
const updateValue = () => { const updateValue = () => {
const cloneValue = cloneDeep(formModel);
const cloneValue = cloneDeep(formModel) let keys: string[] = ['trigger'];
let keys: string[] = ['trigger']
if (cloneValue.trigger === 'cron') { if (cloneValue.trigger === 'cron') {
keys.push('cron') keys.push('cron');
} else if (cloneValue.trigger === 'multi') { } else if (cloneValue.trigger === 'multi') {
keys.push('multi') keys.push('multi');
} else { } else {
keys = keys.concat(['mod', 'when']) keys = keys.concat(['mod', 'when']);
if (cloneValue.mod === 'period') { if (cloneValue.mod === 'period') {
keys.push('period') keys.push('period');
} else { } else {
keys.push('once') keys.push('once');
} }
} }
emit('update:value', pick(cloneValue, keys)) emit('update:value', pick(cloneValue, keys));
} };
const triggerChange = () => { const triggerChange = () => {
formModel.when = [] formModel.when = [];
formModel.cron = undefined formModel.cron = undefined;
updateValue() updateValue();
} };
/** /**
* 频率单位切换 * 频率单位切换
* @param v * @param v
*/ */
const periodUnitChange = (v: any) => { const periodUnitChange = (v: any) => {
if(v === 'hours') { if (v === 'hours') {
unitMax.value = 99999 unitMax.value = 99999;
} else { } else {
unitMax.value = 99 unitMax.value = 99;
} }
formModel.period!.every = 1 formModel.period!.every = 1;
updateValue() updateValue();
} };
defineExpose({ defineExpose({
validateFields: () => new Promise(async (resolve) => { validateFields: () =>
const data = await timerForm.value?.validateFields() new Promise(async (resolve) => {
resolve(data) const data = await timerForm.value?.validateFields();
}) resolve(data);
}) }),
});
Object.assign(formModel, props.value) Object.assign(formModel, props.value);
formModel.when = props.value.when || [] formModel.when = props.value.when || [];
watchEffect(() => { watchEffect(() => {
if(props.value?.period?.unit === 'hours') { if (props.value?.period?.unit === 'hours') {
unitMax. unitMax.value = 99999;
value = 99999
} else { } else {
unitMax.value = 99 unitMax.value = 99;
} }
}) });
</script> </script>
<style scoped lang='less'> <style scoped lang="less"></style>
</style>

View File

@ -305,8 +305,8 @@ const queryParams = {
{ {
terms: [ terms: [
{ {
value: '%show":true%', value: '%show":false%',
termType: 'like', termType: 'nlike',
column: 'options', column: 'options',
type: 'and', type: 'and',
}, },

View File

@ -458,7 +458,7 @@ const form = reactive<formType>({
headerTheme: configInfo.front?.headerTheme, headerTheme: configInfo.front?.headerTheme,
logo: configInfo.front?.logo || '/logo.png', logo: configInfo.front?.logo || '/logo.png',
ico: configInfo.front?.ico || '/favicon.ico', ico: configInfo.front?.ico || '/favicon.ico',
showRecordNumber: configInfo.front?.showRecordNumber, showRecordNumber: configInfo.front?.showRecordNumber || false,
recordNumber: configInfo.front?.recordNumber, recordNumber: configInfo.front?.recordNumber,
background: configInfo.front?.background || '/images/login.png', background: configInfo.front?.background || '/images/login.png',
apiKey: configInfo.amap?.apiKey, apiKey: configInfo.amap?.apiKey,

View File

@ -17,9 +17,6 @@
}" }"
:params="queryParams" :params="queryParams"
:rowSelection="{ :rowSelection="{
// selectedRowKeys: table._selectedRowKeys.value,
// onChange:(keys:string[])=>table._selectedRowKeys.value = [...keys],
// onSelectNone: table.cancelSelect
selectedRowKeys: table._selectedRowKeys.value, selectedRowKeys: table._selectedRowKeys.value,
onSelect: table.onSelect, onSelect: table.onSelect,
onSelectAll: table.onSelectAll, onSelectAll: table.onSelectAll,
@ -307,6 +304,7 @@ const columns = [
dataIndex: 'permission', dataIndex: 'permission',
key: 'permission', key: 'permission',
ellipsis: true, ellipsis: true,
width: 300,
scopedSlots: true, scopedSlots: true,
}, },
{ {

View File

@ -326,7 +326,7 @@ const form = reactive({
init: () => { init: () => {
// //
routeParams.id && routeParams.id ?
getMenuInfo_api(routeParams.id).then((resp: any) => { getMenuInfo_api(routeParams.id).then((resp: any) => {
form.data = { form.data = {
...(resp.result as formType), ...(resp.result as formType),
@ -338,7 +338,7 @@ const form = reactive({
}; };
form.sourceCode = resp.result.code; form.sourceCode = resp.result.code;
showPermissionChoose.value = true showPermissionChoose.value = true
}); }) : showPermissionChoose.value = true
if (isNoCommunity) { if (isNoCommunity) {
// //
@ -350,8 +350,8 @@ const form = reactive({
{ {
terms: [ terms: [
{ {
value: '%show":true%', value: '%show":false%',
termType: 'like', termType: 'nlike',
column: 'options', column: 'options',
}, },
], ],

View File

@ -43,6 +43,17 @@
style="margin-left: 10%" style="margin-left: 10%"
>保存</j-button >保存</j-button
> >
<PermissionButton
type="primary"
:popConfirm="{
title: '确认同步系统菜单权限?',
okText: ' 确定',
cancelText: '取消',
onConfirm: synchronization,
}"
style="margin-left: 20px"
>同步系统菜单权限
</PermissionButton>
</j-card> </j-card>
<j-modal <j-modal
modalType="message" modalType="message"
@ -72,20 +83,18 @@ import {
mergeArr, mergeArr,
findAllParentsAndChildren, findAllParentsAndChildren,
handleSorts, handleSorts,
handleSortsArr handleSortsArr,
} from './utils'; } from './utils';
import BaseMenu from '@/views/init-home/data/baseMenu'; import BaseMenu from '@/views/init-home/data/baseMenu';
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree'; import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { import { USER_CENTER_MENU_CODE, messageSubscribe } from '@/utils/consts';
USER_CENTER_MENU_CODE,
messageSubscribe
} from '@/utils/consts';
import { protocolList } from '@/utils/consts'; import { protocolList } from '@/utils/consts';
import { getProviders } from '@/api/data-collect/channel'; import { getProviders } from '@/api/data-collect/channel';
import { isNoCommunity } from '@/utils/utils'; 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 selectedKeys: any = ref([]);
const treeData = ref<any>([]); const treeData = ref<any>([]);
@ -121,15 +130,15 @@ const params = {
*/ */
let filterProtocolList: any[] = []; let filterProtocolList: any[] = [];
const getProvidersFn = async () => { const getProvidersFn = async () => {
if(!isNoCommunity){ if (!isNoCommunity) {
return return;
}else{ } else {
const res: any = await getProviders(); const res: any = await getProviders();
filterProtocolList = protocolList.filter((item) => { 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(); getProvidersFn();
/** /**
* 作用过滤掉非选中菜单重新组成新的数组 * 作用过滤掉非选中菜单重新组成新的数组
@ -162,46 +171,52 @@ getProvidersFn();
* @param selectedKeys 选中的菜单 * @param selectedKeys 选中的菜单
* 选中和非选中改变show的值 * 选中和非选中改变show的值
*/ */
const dealTree = (nodes: Array<any>, selectedKeys: Array<any>,parentId?:string) =>{ const dealTree = (
nodes: Array<any>,
selectedKeys: Array<any>,
parentId?: string,
) => {
const filtered = []; const filtered = [];
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]; const node = nodes[i];
if (!node.code) { if (!node.code) {
continue; continue;
} }
node.parentId = parentId ? undefined : parentId node.parentId = parentId ? undefined : parentId;
node?.options ? node.options.show = false : node.options = { show : false } node?.options
? (node.options.show = false)
: (node.options = { show: false });
if (selectedKeys.indexOf(node.code) !== -1) { if (selectedKeys.indexOf(node.code) !== -1) {
node.options.show = true node.options.show = true;
if (node.children) { if (node.children) {
node.children = dealTree(node.children, selectedKeys,node.id); node.children = dealTree(node.children, selectedKeys, node.id);
} }
} else if (node.children) { } else if (node.children) {
node.children = dealTree(node.children, selectedKeys,node.id); node.children = dealTree(node.children, selectedKeys, node.id);
const children =node.children.filter((item:any)=>{ const children = node.children.filter((item: any) => {
item.options.show === true item.options.show === true;
}) });
if (children.length > 0) { if (children.length > 0) {
node.options.show = true node.options.show = true;
} }
}else{ } else {
node.options.show = false node.options.show = false;
} }
filtered.push(node) filtered.push(node);
} }
return filtered; return filtered;
} };
const handleOk = async () => { const handleOk = async () => {
// const _dataArr = filterTree(cloneDeep(treeData.value), selectedKeys.value); // const _dataArr = filterTree(cloneDeep(treeData.value), selectedKeys.value);
const _dataArr = dealTree(cloneDeep(treeData.value),selectedKeys.value) const _dataArr = dealTree(cloneDeep(treeData.value), selectedKeys.value);
const _dataSorts = handleSorts(_dataArr) const _dataSorts = handleSorts(_dataArr);
loading.value = true; loading.value = true;
_dataSorts.push(USER_CENTER_MENU_DATA) _dataSorts.push(USER_CENTER_MENU_DATA);
const res = await updateMenus(_dataSorts).catch(() => {}); const res = await updateMenus(_dataSorts).catch(() => {});
if (res?.status === 200) { if (res?.status === 200) {
onlyMessage('操作成功', 'success'); onlyMessage('操作成功', 'success');
location.reload() location.reload();
} }
loading.value = false; loading.value = false;
visible.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(() => { onMounted(() => {
getSystemPermission_api().then((resp: any) => { getSystemPermission_api().then((resp: any) => {
// const filterBaseMenu = BaseMenu.filter(item => ![ // const filterBaseMenu = BaseMenu.filter(item => ![
@ -258,9 +303,9 @@ onMounted(() => {
if (resp.status == 200) { if (resp.status == 200) {
systemMenu.value = resp.result?.filter( systemMenu.value = resp.result?.filter(
(item: { code: string }) => (item: { code: string }) =>
![ ![USER_CENTER_MENU_CODE, messageSubscribe].includes(
USER_CENTER_MENU_CODE,messageSubscribe item.code,
].includes(item.code), ),
); );
// //
// initData(baseMenu.value); // keyname // initData(baseMenu.value); // keyname
@ -285,7 +330,7 @@ const filterMenus = (menus: any[]) => {
if (!filterProtocolList.length && item.code == 'link/DataCollect') { if (!filterProtocolList.length && item.code == 'link/DataCollect') {
return false; return false;
} }
return item return item;
}); });
}; };
</script> </script>

View File

@ -132,7 +132,7 @@ export const inItSelected = (Menu:any) =>{
arr.forEach((item: any) => { arr.forEach((item: any) => {
item.title = item.code; item.title = item.code;
item.key = item.code; // treeData需要唯一key item.key = item.code; // treeData需要唯一key
item?.options?.show ? checkedKeys.push(item.code) : ''; item?.options?.show === false ? '' : checkedKeys.push(item.code);
if (item?.children) { if (item?.children) {
getMap(item?.children); getMap(item?.children);
} }

View File

@ -211,8 +211,8 @@ const table = reactive({
type: 'or', type: 'or',
terms: [ terms: [
{ {
value: '%show":true%', value: '%show":false%',
termType: 'like', termType: 'nlike',
column: 'options', column: 'options',
}, },
], ],

View File

@ -72,7 +72,7 @@ const systemNotice = [
}, },
{ {
provider: 'alarm-org', provider: 'alarm-org',
name: '部门告警', name: '组织告警',
}, },
{ {
provider: 'alarm-other', provider: 'alarm-other',

View File

@ -5,5 +5,5 @@
"moduleResolution": "Node", "moduleResolution": "Node",
"allowSyntheticDefaultImports": true "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"]
} }

View File

@ -96,8 +96,8 @@ export default defineConfig(({ mode}) => {
// target: 'http://192.168.32.244:8881', // target: 'http://192.168.32.244:8881',
// target: 'http://192.168.32.217:8844', //张本地 // target: 'http://192.168.32.217:8844', //张本地
// target: 'http://120.77.179.54:8844', // 120测试 // target: 'http://120.77.179.54:8844', // 120测试
target: 'http://192.168.33.46:8844', // 本地开发环境 // target: 'http://192.168.33.46:8844', // 本地开发环境
// target: 'http://192.168.32.167:8844', // 本地开发环境1 target: 'http://192.168.33.97:8844', // 本地开发环境1
// target: 'http://192.168.33.6:38848', // 社区版开发环境 // target: 'http://192.168.33.6:38848', // 社区版开发环境
// target: 'http://192.168.32.207:8844', // 刘本地 // target: 'http://192.168.32.207:8844', // 刘本地
// target: 'http://192.168.32.187:8844', // 谭本地 // target: 'http://192.168.32.187:8844', // 谭本地
@ -114,7 +114,6 @@ export default defineConfig(({ mode}) => {
less: { less: {
modifyVars: { modifyVars: {
'root-entry-name': 'variable', 'root-entry-name': 'variable',
'primary-color': '#1677FF',
hack: `true; @import (reference) "${path.resolve('src/style/variable.less')}";`, hack: `true; @import (reference) "${path.resolve('src/style/variable.less')}";`,
}, },
javascriptEnabled: true, javascriptEnabled: true,