fix: bug#19215、19214、19213、19183、19060、19090、19167、19090
* fix: 优化物模型配置按钮样式 * fix: bug#18263 * fix: 优化iframe中hash地址 * fix: bug#19132 * fix: bug#19071 * Dev bug (#217) * fix: bug#19215、19214、19213、19183 * fix: bug#19060、19090 * fix: bug#19167 * fix: bug#19080 * fix: bug#19181 * fix: bug#19060、19090 * fix: bug#19181 * fix: iframe组件优化没有参数时,url格式
This commit is contained in:
parent
2c891e7f49
commit
f473124ce8
2
.npmrc
2
.npmrc
|
@ -1,2 +1,2 @@
|
|||
always-auth=true
|
||||
registry=http://registry.jetlinks.cn/
|
||||
registry=https://registry.npmjs.org/
|
||||
|
|
12
README.md
12
README.md
|
@ -48,6 +48,18 @@ yarn dev:force
|
|||
|
||||
此处可以更改系统名称、主题色、系统logo、浏览器页签等
|
||||
|
||||
#### 主题色
|
||||
|
||||
```javascript
|
||||
// src/App.vue
|
||||
|
||||
ConfigProvider.config({
|
||||
theme: {
|
||||
primaryColor: "#315efb"
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### 2.默认配置
|
||||
|
||||
在代码根目录找到`config\config.ts`文件
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"event-source-polyfill": "^1.0.31",
|
||||
"global": "^4.4.0",
|
||||
"jetlinks-store": "^0.0.3",
|
||||
"jetlinks-ui-components": "^1.0.33",
|
||||
"jetlinks-ui-components": "^1.0.34-4",
|
||||
"js-cookie": "^3.0.1",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"less": "^4.1.3",
|
||||
|
|
|
@ -15,7 +15,11 @@ const system = useSystem();
|
|||
const {configInfo} = storeToRefs(system);
|
||||
|
||||
system.setDocumentTitle()
|
||||
|
||||
ConfigProvider.config({
|
||||
theme: {
|
||||
primaryColor: "#315efb"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<j-monaco-editor v-if="loading" v-model:model-value="_value" theme="vs" ref="editor" language="javascript" :registrationTypescript="typescriptTip"
|
||||
<j-monaco-editor v-if="loading" v-model:model-value="_value" theme="vs" ref="editor" language="javascript" :registrationTypescript="typescriptTip" :registrationTips="registrationTips"
|
||||
:init="editorInit"/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,11 +41,13 @@ import {
|
|||
} from '@/api/device/instance';
|
||||
import { useInstanceStore } from '@/store/instance';
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { inject } from 'vue'
|
||||
interface Props {
|
||||
mode?: 'advance' | 'simple';
|
||||
id?: string;
|
||||
value?: string;
|
||||
tips?: Array<any>
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const target = inject('target')
|
||||
|
@ -71,28 +73,9 @@ type SymbolType = {
|
|||
const typescriptTip = reactive({
|
||||
typescript: ''
|
||||
})
|
||||
|
||||
const queryCode = () => {
|
||||
let id = ''
|
||||
if(target==='device'){
|
||||
id = instanceStore.current.id
|
||||
queryTypescript(id).then(res => {
|
||||
if (res.status===200) {
|
||||
typescriptTip.typescript = res.result
|
||||
}
|
||||
})
|
||||
}else if(target ==='product'){
|
||||
id = productStore.current.id
|
||||
queryProductTs(id).then(res => {
|
||||
if (res.status===200) {
|
||||
typescriptTip.typescript = res.result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
queryCode()
|
||||
|
||||
const registrationTips = ref<any>({
|
||||
name: 'javascript'
|
||||
})
|
||||
const editorInit = (editor: any, monaco: any) => {
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
|
@ -200,11 +183,27 @@ const _value = computed({
|
|||
})
|
||||
|
||||
const loading = ref(false)
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
loading.value = true;
|
||||
}, 100);
|
||||
})
|
||||
const queryCode = () => {
|
||||
registrationTips.value.suggestions = cloneDeep(props.tips)
|
||||
let id = ''
|
||||
if(target==='device'){
|
||||
id = instanceStore.current.id
|
||||
queryTypescript(id).then(res => {
|
||||
if (res.status===200) {
|
||||
typescriptTip.typescript = res.result
|
||||
}
|
||||
})
|
||||
}else if(target ==='product'){
|
||||
id = productStore.current.id
|
||||
queryProductTs(id).then(res => {
|
||||
if (res.status===200) {
|
||||
typescriptTip.typescript = res.result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const addOperatorValue = (val: string) => {
|
||||
editor.value?.insert(val)
|
||||
|
@ -220,6 +219,13 @@ defineExpose({
|
|||
addOperatorValue
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
loading.value = true;
|
||||
}, 100);
|
||||
})
|
||||
|
||||
queryCode()
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.editor-box {
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
mode="advance"
|
||||
key="advance"
|
||||
v-model:value="_value"
|
||||
:tips="tips"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -49,7 +50,7 @@
|
|||
<template #footer>
|
||||
<j-space>
|
||||
<j-button @click="handleCancel">取消</j-button>
|
||||
<j-button :disabled="_disabled" @click="handleOk" type="primary">确定</j-button>
|
||||
<j-button @click="handleOk" type="primary">确定</j-button>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-modal>
|
||||
|
@ -59,7 +60,8 @@ import Editor from './Editor/index.vue';
|
|||
import Debug from './Debug/index.vue';
|
||||
import Operator from './Operator/index.vue';
|
||||
import { FULL_CODE } from 'jetlinks-ui-components/es/DataTable'
|
||||
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { PropertyMetadata } from '@/views/device/Product/typings';
|
||||
interface Emits {
|
||||
(e: 'save', data: string | undefined): void;
|
||||
(e: 'close'): void;
|
||||
|
@ -77,7 +79,7 @@ const props = defineProps({
|
|||
const _value = ref<string | undefined>(props.value);
|
||||
const _disabled = ref<boolean>(true);
|
||||
const fullRef = inject(FULL_CODE);
|
||||
|
||||
const tips = ref<any[]>([])
|
||||
const handleCancel = () => {
|
||||
emit('close');
|
||||
};
|
||||
|
@ -98,13 +100,38 @@ const addOperatorValue = (val: string) => {
|
|||
editor.value.addOperatorValue(val);
|
||||
};
|
||||
|
||||
watch(() => _value.value, () => {
|
||||
_disabled.value = true
|
||||
})
|
||||
|
||||
const onSuccess = (bool: boolean) => {
|
||||
_disabled.value = bool;
|
||||
const getAllCrud = () => {
|
||||
const list = cloneDeep(props.propertiesOptions)?.filter((i:any)=>
|
||||
props?.id !== i.id
|
||||
)
|
||||
console.log(list,'list')
|
||||
// 转化为语法提示
|
||||
list.forEach(item => {
|
||||
console.log(item)
|
||||
const config = item
|
||||
tips.value.push({
|
||||
label: `${config.name}$recent实时值`,
|
||||
insertText:`$recent ("${config.id}")`,
|
||||
kind: 18,
|
||||
})
|
||||
tips.value.push({
|
||||
label: `${config.name}上一值`,
|
||||
insertText: `$lastState("${config.id}"))`,
|
||||
kind: 18
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// watch(() => _value.value, () => {
|
||||
// console.log(_value.value)
|
||||
// _disabled.value = true
|
||||
// })
|
||||
|
||||
// const onSuccess = (bool: boolean) => {
|
||||
// _disabled.value = bool;
|
||||
// }
|
||||
getAllCrud()
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.header {
|
||||
|
|
|
@ -25,9 +25,11 @@
|
|||
<UserInfo />
|
||||
</div>
|
||||
</template>
|
||||
<router-view v-slot="{ Component }">
|
||||
<component :is="components || Component" />
|
||||
</router-view>
|
||||
<slot>
|
||||
<router-view v-slot="{ Component }">
|
||||
<component :is="components || Component" />
|
||||
</router-view>
|
||||
</slot>
|
||||
</j-pro-layout>
|
||||
</template>
|
||||
|
||||
|
@ -40,6 +42,7 @@ import { clearMenuItem } from 'jetlinks-ui-components/es/ProLayout/util';
|
|||
import { AccountMenu } from '@/router/menu'
|
||||
import { useSystem } from '@/store/system';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSlots } from 'vue'
|
||||
|
||||
type StateType = {
|
||||
collapsed: boolean;
|
||||
|
@ -55,7 +58,7 @@ const menu = useMenuStore();
|
|||
|
||||
const system = useSystem();
|
||||
const {configInfo,layout, basicLayout} = storeToRefs(system);
|
||||
|
||||
const slots = useSlots()
|
||||
const layoutConf = reactive({
|
||||
theme: DefaultSetting.layout.theme,
|
||||
siderWidth: layout.value.siderWidth,
|
||||
|
@ -107,8 +110,6 @@ const jump = (item: any) => {
|
|||
router.push(item.path)
|
||||
}
|
||||
|
||||
|
||||
|
||||
watchEffect(() => {
|
||||
if (router.currentRoute) {
|
||||
const paths = router.currentRoute.value.matched
|
||||
|
@ -116,6 +117,10 @@ watchEffect(() => {
|
|||
basicLayout.value.openKeys = paths.map(item => item.path)
|
||||
console.log(paths) //
|
||||
}
|
||||
|
||||
if (route.query?.layout === 'false') {
|
||||
basicLayout.value.pure = true
|
||||
}
|
||||
})
|
||||
|
||||
const toDoc = () => window.open('http://doc.v2.jetlinks.cn/');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<template v-if="isPermission">
|
||||
<template v-if="popConfirm">
|
||||
<j-popconfirm :overlayStyle='{width: "220px"}' v-bind="popConfirm" :disabled="!isPermission || props.disabled">
|
||||
<j-popconfirm :disabled="!isPermission || props.disabled" :overlayStyle='{width: "220px", zIndex: 1075 }' v-bind="popConfirm">
|
||||
<j-tooltip v-if="tooltip" v-bind="tooltip">
|
||||
<slot v-if="noButton"></slot>
|
||||
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
|
||||
|
@ -120,4 +120,4 @@ const _isPermission = computed(() =>
|
|||
</script>
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './useRequest'
|
|
@ -0,0 +1,92 @@
|
|||
import {onUnmounted, ref} from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import {isFunction, get, isArray} from 'lodash-es'
|
||||
import type { AxiosResponseRewrite } from '@/utils/request'
|
||||
|
||||
interface RequestOptions<T, S> {
|
||||
immediate: boolean
|
||||
/**
|
||||
* 成功回调
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
onSuccess: (data: AxiosResponseRewrite<S>) => S | void
|
||||
/**
|
||||
* 返回参数处理
|
||||
* @returns
|
||||
*/
|
||||
formatName: string | [string]
|
||||
onError: (e: any) => void
|
||||
|
||||
defaultParams: S | any | any[]
|
||||
|
||||
handleResponse: (data: any) => any
|
||||
}
|
||||
|
||||
const defaultOptions: any = {
|
||||
immediate: true,
|
||||
formatName: 'result'
|
||||
}
|
||||
|
||||
type Run = (...args: any[]) => void
|
||||
|
||||
export const useRequest = <T = any, S = any>(
|
||||
request: (...args: any[]) => Promise<AxiosResponseRewrite<T>>,
|
||||
options: Partial<RequestOptions<T, S>> = defaultOptions,
|
||||
): {
|
||||
data: Ref<S | undefined>,
|
||||
loading: Ref<boolean>,
|
||||
run: Run
|
||||
} => {
|
||||
const data = ref<S>()
|
||||
const loading = ref(false)
|
||||
const _options = {
|
||||
...defaultOptions,
|
||||
...options
|
||||
}
|
||||
|
||||
async function run(...arg: any[]) {
|
||||
if (request && isFunction(request)) {
|
||||
loading.value = true
|
||||
try {
|
||||
// @ts-ignore
|
||||
const resp = await request.apply(this, arg)
|
||||
|
||||
loading.value = false
|
||||
|
||||
if (resp?.success) {
|
||||
const successData = await _options.onSuccess?.(resp)
|
||||
data.value = successData || get(resp, _options.formatName!)
|
||||
// console.log(data.value)
|
||||
} else {
|
||||
_options.onError?.(resp)
|
||||
}
|
||||
} catch (e) {
|
||||
loading.value = false
|
||||
_options.onError?.(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.immediate) { // 主动触发
|
||||
if (_options.defaultParams) {
|
||||
isArray(_options.defaultParams) ? run(..._options.defaultParams) : run(_options.defaultParams)
|
||||
} else {
|
||||
run()
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
// 销毁时,撤销该请求
|
||||
if (request && isFunction(request)) {
|
||||
|
||||
}
|
||||
// request()
|
||||
})
|
||||
|
||||
return {
|
||||
data,
|
||||
loading,
|
||||
run
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import store from './store'
|
|||
import components from './components'
|
||||
import router from './router'
|
||||
import './style.less'
|
||||
|
||||
import 'ant-design-vue/dist/antd.variable.min.css'
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
dayjs.locale('zh-cn');
|
||||
|
|
|
@ -24,12 +24,12 @@ const defaultOwnParams = [
|
|||
termType: 'eq',
|
||||
value: 'iot'
|
||||
},
|
||||
{
|
||||
column: 'owner',
|
||||
termType: 'isnull',
|
||||
value: '1',
|
||||
type: 'or'
|
||||
}
|
||||
// {
|
||||
// column: 'owner',
|
||||
// termType: 'isnull',
|
||||
// value: '1',
|
||||
// type: 'or'
|
||||
// }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -129,4 +129,4 @@ export const useMenuStore = defineStore({
|
|||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -89,4 +89,4 @@ export const useSystem = defineStore('system', {
|
|||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -30,9 +30,9 @@ body {
|
|||
|
||||
.ant-pro-top-nav-header {
|
||||
.ant-menu-item {
|
||||
padding: 0 10px !important;
|
||||
&:not(:first-child) {
|
||||
margin-left: 8px !important;
|
||||
padding: 0 14px !important;
|
||||
&:first-child {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { BlankLayoutPage, BasicLayoutPage } from 'components/Layout'
|
||||
import { isNoCommunity } from '@/utils/utils'
|
||||
import Iframe from '../views/iframe/index.vue'
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
|
||||
const pagesComponent = import.meta.glob('../views/**/*.vue');
|
||||
|
||||
|
@ -155,192 +156,6 @@ const extraRouteObj = {
|
|||
}
|
||||
};
|
||||
|
||||
//
|
||||
// const resolveComponent = (name: any) => {
|
||||
// const importPage = pagesComponent[`../views/${name}/index.vue`];
|
||||
// console.log(importPage)
|
||||
// if (!importPage) {
|
||||
// return undefined
|
||||
// } else {
|
||||
// const res = () => importPage()
|
||||
// return res
|
||||
// }
|
||||
// //@ts-ignore
|
||||
// }
|
||||
//
|
||||
// const findChildrenRoute = (code: string, url: string, routes: any[] = []): MenuItem[] => {
|
||||
// if (extraRouteObj[code]) {
|
||||
// const extraRoutes = extraRouteObj[code].children.map((route: MenuItem) => {
|
||||
// return {
|
||||
// url: `${url}/${route.code}`,
|
||||
// code: `${code}/${route.code}`,
|
||||
// name: route.name,
|
||||
// isShow: false
|
||||
// }
|
||||
// })
|
||||
// return [...routes, ...extraRoutes]
|
||||
// }
|
||||
// return routes
|
||||
// }
|
||||
//
|
||||
// const findDetailRouteItem = (code: string, url: string): Partial<MenuItem> | null => {
|
||||
// const detailComponent = resolveComponent(`${code}/Detail`)
|
||||
// if (detailComponent) {
|
||||
// return {
|
||||
// url: `${url}/detail/:id`,
|
||||
// code: `${code}/Detail`,
|
||||
// component: detailComponent,
|
||||
// name: '详情信息',
|
||||
// isShow: false
|
||||
// }
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// const findDetailRoutes = (routes: any[]): any[] => {
|
||||
// const newRoutes: any[] = []
|
||||
// routes.forEach((route: any) => {
|
||||
// newRoutes.push(route)
|
||||
// const detail = findDetailRouteItem(route.code, route.url)
|
||||
// if (detail) {
|
||||
// newRoutes.push(detail)
|
||||
// }
|
||||
// })
|
||||
// return newRoutes
|
||||
// }
|
||||
//
|
||||
// const filterMenus = ['device/DashBoard']
|
||||
// export const filterCommunityMenus = (menuData: any[]) => {
|
||||
// return menuData.filter(item => {
|
||||
// if (item.children) {
|
||||
// item.children = filterCommunityMenus(item.children)
|
||||
// }
|
||||
// return !filterMenus.includes(item.code)
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// export const findCodeRoute = (asyncRouterMap: any[]) => {
|
||||
// const routeMeta = {}
|
||||
//
|
||||
// function getDetail(code: string, url: string) {
|
||||
// const detail = findDetailRouteItem(code, url)
|
||||
// if (!detail) return
|
||||
//
|
||||
// routeMeta[(detail as MenuItem).code] = {
|
||||
// path: detail.url,
|
||||
// title: detail.name,
|
||||
// parentName: code,
|
||||
// buttons: detail.buttons?.map((b: any) => b.id) || []
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// function findChildren(data: any[], code: string = '') {
|
||||
// data.forEach(route => {
|
||||
// routeMeta[route.code] = {
|
||||
// path: route.url || route.path,
|
||||
// title: route.meta?.title || route.name,
|
||||
// parentName: code,
|
||||
// buttons: route.buttons?.map((b: any) => b.id) || []
|
||||
// }
|
||||
// const otherRoutes = extraRouteObj[route.code]
|
||||
//
|
||||
// if (otherRoutes) {
|
||||
// otherRoutes.children.map((item: any) => {
|
||||
// const _code = `${route.code}/${item.code}`
|
||||
// const url = `${route.url}/${item.code}`
|
||||
// routeMeta[_code] = {
|
||||
// path: `${route.url}/${item.code}`,
|
||||
// title: item.name,
|
||||
// parentName: route.code,
|
||||
// buttons: item.buttons?.map((b: any) => b.id) || []
|
||||
// }
|
||||
// getDetail(_code, url)
|
||||
// })
|
||||
// }
|
||||
// const _code = route.appId ? `/${route.appId}${route.url}` : route.code
|
||||
// if (!route.appId) {
|
||||
// getDetail(_code, route.url)
|
||||
// } else {
|
||||
// routeMeta[_code] = {
|
||||
// path: `/${route.appId}${route.url}`,
|
||||
// title: route.name,
|
||||
// parentName: code,
|
||||
// buttons: []
|
||||
// }
|
||||
// }
|
||||
// if (route.children) {
|
||||
// findChildren(route.children, _code)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// findChildren(asyncRouterMap)
|
||||
//
|
||||
// return routeMeta
|
||||
// }
|
||||
//
|
||||
// export function filterAsyncRouter(asyncRouterMap: any, parentCode = '', level = 1): { menusData: any, silderMenus: any } {
|
||||
// const _asyncRouterMap = cloneDeep(asyncRouterMap)
|
||||
// const menusData: any[] = []
|
||||
// const silderMenus: any[] = []
|
||||
// _asyncRouterMap.forEach((route: any) => {
|
||||
// const hasAppId = route.appId
|
||||
// const _route: any = {
|
||||
// path: hasAppId ? `/${route.appId}${route.url}` : `${route.url}`,
|
||||
// name: hasAppId ? `/${route.appId}${route.url}` : route.code,
|
||||
// url: hasAppId ? `/${route.appId}${route.url}` : route.url,
|
||||
// meta: {
|
||||
// icon: route.icon,
|
||||
// title: route.name,
|
||||
// hideInMenu: route.isShow === false,
|
||||
// buttons: route.buttons?.map((b: any) => b.id) || [],
|
||||
// isApp: hasAppId,
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// const silder = { ..._route }
|
||||
// // 查看是否有隐藏子路由
|
||||
// route.children = findChildrenRoute(route.code, route.url, route.children)
|
||||
// route.children = findDetailRoutes(route.children)
|
||||
// if (route.children && route.children.length) {
|
||||
// // TODO 查看是否具有详情页
|
||||
// const { menusData: _menusData, silderMenus: _silderMenus } = filterAsyncRouter(route.children, `${parentCode}/${route.code}`, level + 1)
|
||||
// _route.children = _menusData
|
||||
// silder.children = _silderMenus
|
||||
// const showChildren = _route.children.some((r: any) => !r.meta.hideInMenu)
|
||||
//
|
||||
// if (showChildren && _route.children.length) {
|
||||
// _route.component = level === 1 ? BasicLayoutPage : BlankLayoutPage
|
||||
// _route.redirect = _route.children[0].url
|
||||
// } else {
|
||||
// const myComponent = resolveComponent(route.code)
|
||||
// // _route.component = myComponent ? myComponent : BlankLayoutPage;
|
||||
// if (!!myComponent) {
|
||||
// _route.component = myComponent;
|
||||
// _route.children.map((r: any) => menusData.push(r))
|
||||
// delete _route.children
|
||||
// } else {
|
||||
// _route.component = BlankLayoutPage
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// if (hasAppId) {
|
||||
// _route.component = route.component || resolveComponent('iframe')
|
||||
// } else {
|
||||
// _route.component = route.component || resolveComponent(route.code) || BlankLayoutPage
|
||||
// }
|
||||
// }
|
||||
// menusData.push(_route)
|
||||
// silderMenus.push(silder)
|
||||
// })
|
||||
// return {
|
||||
// menusData,
|
||||
// silderMenus,
|
||||
// }
|
||||
// }
|
||||
|
||||
import { shallowRef } from 'vue'
|
||||
|
||||
type Buttons = Array<{ id: string }>
|
||||
|
||||
const hasAppID = (item: { appId?: string, url?: string }): { isApp: boolean, appUrl: string } => {
|
||||
|
@ -367,6 +182,12 @@ const handleMeta = (item: MenuItem, isApp: boolean) => {
|
|||
const findComponents = (code: string, level: number, isApp: boolean, components: any) => {
|
||||
const myComponents = components[code]
|
||||
if (level === 1) { // BasicLayoutPage
|
||||
if (myComponents) {
|
||||
return h(BasicLayoutPage, {}, () => [h(defineAsyncComponent(() => myComponents()), {})])
|
||||
}
|
||||
if (isApp) {
|
||||
return h(BasicLayoutPage, {}, () => [h(Iframe, {})])
|
||||
}
|
||||
return myComponents ? () => myComponents() : BasicLayoutPage
|
||||
} else if (isApp){ // iframe
|
||||
return Iframe
|
||||
|
@ -529,4 +350,4 @@ export const handleAuthMenu = (menuData: any[], cb: (code: any, buttons: any[])
|
|||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { LoginPath } from '@/router/menu'
|
|||
import { cleanToken, getToken, LocalStore } from '@/utils/comm'
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios'
|
||||
|
||||
interface AxiosResponseRewrite<T = any[]> extends AxiosResponse<T, any> {
|
||||
export interface AxiosResponseRewrite<T = any[]> extends AxiosResponse<T, any> {
|
||||
result: T
|
||||
success: boolean
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ const showNotification = (message: string, description: string, key?: string, sh
|
|||
* @returns {Promise<never>}
|
||||
*/
|
||||
const errorHandler = (error: any) => {
|
||||
|
||||
|
||||
if (error.response) {
|
||||
const data = error.response.data
|
||||
const status = error.response.status
|
||||
|
@ -257,4 +257,4 @@ export default {
|
|||
remove,
|
||||
getStream,
|
||||
postStream
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ export const isNoCommunity = !(localStorage.getItem(SystemConst.VERSION_CODE) ==
|
|||
|
||||
/**
|
||||
* 生成随机数
|
||||
* @param length
|
||||
* @returns
|
||||
* @param length
|
||||
* @returns
|
||||
*/
|
||||
export const randomString = (length?: number) => {
|
||||
const tempLength = length || 32;
|
||||
|
@ -87,8 +87,8 @@ export const randomString = (length?: number) => {
|
|||
|
||||
/**
|
||||
* 时间戳转时分秒文本
|
||||
* @param time
|
||||
* @returns
|
||||
* @param time
|
||||
* @returns
|
||||
*/
|
||||
export const timestampFormat = (time: number) => {
|
||||
let hour = 0;
|
||||
|
@ -182,4 +182,4 @@ export const EventEmitter = {
|
|||
})
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
:dataSource="modelRef.dataSource"
|
||||
:columns="FormTableColumns"
|
||||
:scroll="{ y: 580 }"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #headerCell="{ column }">
|
||||
<template
|
||||
|
@ -308,7 +309,6 @@ watch(
|
|||
() => props.data,
|
||||
(value, preValue) => {
|
||||
modelRef.dataSource = value;
|
||||
|
||||
// 有新增时同上数据
|
||||
const vlength = value.length,
|
||||
plength = preValue.length;
|
||||
|
|
|
@ -133,13 +133,13 @@
|
|||
</p>
|
||||
</div>
|
||||
<j-form-item
|
||||
:name="['configuration', 'requsetTimeout']"
|
||||
:rules="LeftTreeRules.requsetTimeout"
|
||||
:name="['configuration', 'requestTimeout']"
|
||||
:rules="LeftTreeRules.requestTimeout"
|
||||
>
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入请求超时时间配置"
|
||||
v-model:value="formData.configuration.requsetTimeout"
|
||||
v-model:value="formData.configuration.requestTimeout"
|
||||
addon-after="ms"
|
||||
:max="60000"
|
||||
:min="2000"
|
||||
|
@ -257,7 +257,7 @@ const formData = ref({
|
|||
type: 'LowerFrequency',
|
||||
endian: 'BIG',
|
||||
endianIn: 'BIG',
|
||||
requsetTimeout: 2000,
|
||||
requestTimeout: 2000,
|
||||
inheritBreakerSpec: {
|
||||
type: 'LowerFrequency',
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ export const LeftTreeRules = {
|
|||
endianIn: [
|
||||
{ required: true, message: '请选择单字高低位切换', trigger: 'blur' },
|
||||
],
|
||||
requsetTimeout:[
|
||||
requestTimeout:[
|
||||
{ pattern: /^\d+$/, message:'请输入2000-60000的正整数',trigger: 'change'}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -90,6 +90,7 @@ import {
|
|||
} from '@/utils/consts';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
import RoleShow from './components/RoleShow/index.vue';
|
||||
import {isNoCommunity} from "@/utils/utils";
|
||||
|
||||
const imageTypes = reactive([
|
||||
'image/jpeg',
|
||||
|
@ -103,7 +104,8 @@ const imageTypes = reactive([
|
|||
const user = useUserInfo();
|
||||
|
||||
type KeyType = 'HomeView' | 'BindThirdAccount' | 'Subscribe' | 'StationMessage';
|
||||
const list: { key: KeyType; title: string }[] = [
|
||||
console.log(isNoCommunity)
|
||||
const list: { key: KeyType; title: string }[] = isNoCommunity ? [
|
||||
{
|
||||
key: 'HomeView',
|
||||
title: '首页视图',
|
||||
|
@ -120,6 +122,19 @@ const list: { key: KeyType; title: string }[] = [
|
|||
key: 'StationMessage',
|
||||
title: '站内信',
|
||||
},
|
||||
] : [
|
||||
{
|
||||
key: 'HomeView',
|
||||
title: '首页视图',
|
||||
},
|
||||
{
|
||||
key: 'Subscribe',
|
||||
title: '我的订阅',
|
||||
},
|
||||
{
|
||||
key: 'StationMessage',
|
||||
title: '站内信',
|
||||
},
|
||||
];
|
||||
|
||||
const tabs = {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
></j-col>
|
||||
<j-col :span="6"
|
||||
><TopCard
|
||||
title="今日设备信息量"
|
||||
title="今日设备消息量"
|
||||
:footer="messageFooter"
|
||||
:value="dayMessage"
|
||||
>
|
||||
|
@ -395,6 +395,7 @@ const setDevMesChartOption = (
|
|||
y: Array<number>,
|
||||
maxY: number,
|
||||
): void => {
|
||||
const yLen = String(Math.ceil(maxY)).length
|
||||
devMegOptions.value = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
|
@ -412,7 +413,7 @@ const setDevMesChartOption = (
|
|||
grid: {
|
||||
top: '2%',
|
||||
bottom: '5%',
|
||||
left: maxY > 100000 ? '50px' : '70px',
|
||||
left: maxY < 900000 ? '60px' : (yLen * 7.5 + Math.floor(yLen/3) * 1.2 + 10) + 'px',
|
||||
right: '50px',
|
||||
},
|
||||
series: [
|
||||
|
@ -596,8 +597,9 @@ const getEcharts = (data: any) => {
|
|||
const y = res.result.map((item: any) => item.data.value).reverse();
|
||||
const maxY = Math.max.apply(
|
||||
null,
|
||||
messageChartYData.value.length ? messageChartYData.value : [0],
|
||||
y.length ? y : [0],
|
||||
);
|
||||
|
||||
setDevMesChartOption(x, y, maxY);
|
||||
}
|
||||
});
|
||||
|
@ -623,4 +625,4 @@ getDevice();
|
|||
height: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -1,106 +1,60 @@
|
|||
<template>
|
||||
<SaveChild
|
||||
v-if="childVisible"
|
||||
@close-child-save="closeChildSave"
|
||||
:childData="_current"
|
||||
/>
|
||||
<SaveChild v-if="childVisible" @close-child-save="closeChildSave" :childData="_current" />
|
||||
<div v-else>
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="child-device"
|
||||
@search="handleSearch"
|
||||
class="device-child-device-search"
|
||||
/>
|
||||
<pro-search :columns="columns" target="child-device" @search="handleSearch" class="device-child-device-search" />
|
||||
<!-- <j-divider /> -->
|
||||
<JProTable
|
||||
ref="childDeviceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:bodyStyle="{
|
||||
padding: 0
|
||||
}"
|
||||
:defaultParams="{
|
||||
terms: [
|
||||
{
|
||||
column: 'parentId',
|
||||
value: detail?.id || '',
|
||||
termType: 'eq',
|
||||
},
|
||||
],
|
||||
}"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
:params="params"
|
||||
:model="'TABLE'"
|
||||
>
|
||||
<JProTable ref="childDeviceRef" :columns="columns" :request="query" :bodyStyle="{
|
||||
padding: 0
|
||||
}" :defaultParams="{
|
||||
terms: [
|
||||
{
|
||||
column: 'parentId',
|
||||
value: detail?.id || '',
|
||||
termType: 'eq',
|
||||
},
|
||||
],
|
||||
}" :rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}" :params="params" :model="'TABLE'">
|
||||
<template #rightExtraRender>
|
||||
<j-space>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
v-if="
|
||||
detail?.accessProvider === 'official-edge-gateway'
|
||||
"
|
||||
hasPermission="device/Instance:update"
|
||||
@click="
|
||||
_current = {};
|
||||
childVisible = true;
|
||||
"
|
||||
>新增并绑定</PermissionButton
|
||||
>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
@click="visible = true"
|
||||
hasPermission="device/Instance:update"
|
||||
>
|
||||
绑定</PermissionButton
|
||||
>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
hasPermission="device/Instance:update"
|
||||
:popConfirm="{
|
||||
title: '确定解绑吗?',
|
||||
onConfirm: handleUnBind,
|
||||
}"
|
||||
>批量解除</PermissionButton
|
||||
>
|
||||
<PermissionButton type="primary" v-if="detail?.accessProvider === 'official-edge-gateway'
|
||||
" hasPermission="device/Instance:update" @click="
|
||||
_current = {};
|
||||
childVisible = true;
|
||||
">新增并绑定</PermissionButton>
|
||||
<PermissionButton type="primary" @click="visible = true" hasPermission="device/Instance:update">
|
||||
绑定</PermissionButton>
|
||||
<PermissionButton type="primary" hasPermission="device/Instance:update" :popConfirm="{
|
||||
title: '确定解绑吗?',
|
||||
onConfirm: handleUnBind,
|
||||
}">批量解除</PermissionButton>
|
||||
</j-space>
|
||||
</template>
|
||||
<template #registryTime="slotProps">
|
||||
{{
|
||||
slotProps.registryTime
|
||||
? moment(slotProps.registryTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
? moment(slotProps.registryTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<j-badge
|
||||
:text="slotProps.state.text"
|
||||
:status="statusMap.get(slotProps.state.value)"
|
||||
/>
|
||||
<j-badge :text="slotProps.state.text" :status="statusMap.get(slotProps.state.value)" />
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
>
|
||||
<PermissionButton
|
||||
v-if="i.key !== 'update' || detail.accessProvider === 'official-edge-gateway'"
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
<template v-for="i in getActions(slotProps, 'table')" :key="i.key">
|
||||
<PermissionButton v-if="i.key !== 'update' || detail.accessProvider === 'official-edge-gateway'"
|
||||
:disabled="i.disabled" :popConfirm="i.popConfirm" :tooltip="{
|
||||
...i.tooltip,
|
||||
}"
|
||||
@click="i.onClick"
|
||||
type="link"
|
||||
style="padding: 0px"
|
||||
:hasPermission="'device/Instance:' + i.key"
|
||||
>
|
||||
<template #icon><AIcon :type="i.icon" /></template>
|
||||
}" @click="i.onClick" type="link" style="padding: 0px"
|
||||
:hasPermission="'device/Instance:' + i.key">
|
||||
<template #icon>
|
||||
<AIcon :type="i.icon" />
|
||||
</template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</j-space>
|
||||
|
@ -113,7 +67,7 @@
|
|||
<script setup lang="ts">
|
||||
import moment from 'moment';
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import {query, unbindDevice, unbindBatchDevice, queryByParent , deleteDeviceMapping} from '@/api/device/instance';
|
||||
import { query, unbindDevice, unbindBatchDevice, queryByParent, deleteDeviceMapping } from '@/api/device/instance';
|
||||
import { useInstanceStore } from '@/store/instance';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import BindChildDevice from './BindChildDevice/index.vue';
|
||||
|
@ -241,10 +195,12 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
|||
data.id,
|
||||
{},
|
||||
);
|
||||
const res = await deleteDeviceMapping(
|
||||
detail.value.id,
|
||||
{ids:[data.id]}
|
||||
)
|
||||
if (instanceStore.current.accessProvider === 'official-edge-gateway') {
|
||||
const res = await deleteDeviceMapping(
|
||||
detail.value.id,
|
||||
{ ids: [data.id] }
|
||||
)
|
||||
}
|
||||
if (resp.status === 200) {
|
||||
childDeviceRef.value?.reload();
|
||||
onlyMessage('操作成功!');
|
||||
|
@ -285,11 +241,13 @@ const handleUnBind = async () => {
|
|||
detail.value.id,
|
||||
_selectedRowKeys.value,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
if (instanceStore.current.accessProvider === 'official-edge-gateway') {
|
||||
const res = await deleteDeviceMapping(
|
||||
detail.value.id,
|
||||
{ids:[_selectedRowKeys.value]}
|
||||
{ ids: [_selectedRowKeys.value] }
|
||||
)
|
||||
}
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
cancelSelect();
|
||||
childDeviceRef.value?.reload();
|
||||
|
@ -316,7 +274,7 @@ const closeBindDevice = (val: boolean) => {
|
|||
const closeChildSave = () => {
|
||||
childVisible.value = false;
|
||||
};
|
||||
onMounted(()=>{
|
||||
onMounted(() => {
|
||||
console.log(detail.value.accessProvider)
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1380,7 +1380,7 @@ const Status = defineComponent({
|
|||
>
|
||||
设备接入配置
|
||||
</Button>
|
||||
中${urlMap.get(unref(device)?.accessProvider) || ''}信息,任意上报一条数据
|
||||
中{urlMap.get(unref(device)?.accessProvider) || ''}信息,任意上报一条数据
|
||||
</span>
|
||||
}
|
||||
/>,
|
||||
|
@ -1391,8 +1391,8 @@ const Status = defineComponent({
|
|||
status="default"
|
||||
text={
|
||||
<span>
|
||||
请联系管理员提供${urlMap.get(unref(device)?.accessProvider) || ''}
|
||||
信息,并根据URL信息任意上报一条数据
|
||||
请联系管理员提供{urlMap.get(unref(device)?.accessProvider) || ''}
|
||||
信息,并根据URL信息任意上报一条数据
|
||||
</span>
|
||||
}
|
||||
/>,
|
||||
|
|
|
@ -177,7 +177,7 @@ const newFunctions = computed(() => {
|
|||
required: tableItem.expands?.required
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
result.push({
|
||||
...func,
|
||||
table: array,
|
||||
|
@ -197,7 +197,7 @@ const handleExecute = async (func: any) => {
|
|||
.then(async () => {
|
||||
const obj = {};
|
||||
func.table.forEach((item: any) => {
|
||||
if (item.type === 'object') {
|
||||
if (item.type === 'object' && item.value) {
|
||||
obj[item.id] = JSON.parse(item.value);
|
||||
} else {
|
||||
obj[item.id] = item.value;
|
||||
|
|
|
@ -185,7 +185,8 @@ const getOptions = (arr: any[]) => {
|
|||
tooltip: {
|
||||
trigger: 'axis',
|
||||
position: function (pt: any) {
|
||||
return [pt[0], '10%'];
|
||||
const left = pt[0] - 80
|
||||
return [left, '10%'];
|
||||
},
|
||||
},
|
||||
series: [
|
||||
|
|
|
@ -155,7 +155,7 @@ const handleOk = () => {
|
|||
return;
|
||||
}
|
||||
btnLoading.value = true;
|
||||
bindDevice(_selectedRowKeys.value[0], props.data.id, )
|
||||
bindDevice(_selectedRowKeys.value[0], [props.data.id] )
|
||||
.then((resp) => {
|
||||
if(resp.status === 200){
|
||||
emit('ok', _selectedRowKeys.value[0]);
|
||||
|
|
|
@ -135,7 +135,7 @@ const _delete = (_key: string) => {
|
|||
};
|
||||
|
||||
const handleClick = async () => {
|
||||
|
||||
|
||||
if (!rightList.value.length) {
|
||||
onlyMessage('请选择采集器', 'warning');
|
||||
} else {
|
||||
|
@ -152,7 +152,7 @@ const handleClick = async () => {
|
|||
}));
|
||||
params.push(...array);
|
||||
});
|
||||
|
||||
|
||||
const filterParms = params.filter((item) => !!item.metadataId);
|
||||
if (filterParms && filterParms.length !== 0) {
|
||||
const res = await saveMapping(_props.deviceId, _props.type, filterParms);
|
||||
|
@ -192,4 +192,4 @@ watchEffect(() => {
|
|||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
|
@ -8,7 +8,7 @@
|
|||
</j-space>
|
||||
</template>
|
||||
<j-form ref="formRef" :model="modelRef">
|
||||
<j-table :dataSource="modelRef.dataSource" :columns="columns">
|
||||
<j-table :columns="columns" :dataSource="modelRef.dataSource" @change="tableChange">
|
||||
<template #headerCell="{ column }">
|
||||
<template v-if="column.key === 'collectorId'">
|
||||
采集器
|
||||
|
@ -20,13 +20,14 @@
|
|||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.dataIndex === 'channelId'">
|
||||
<j-form-item
|
||||
:name="['dataSource', index, 'channelId']"
|
||||
:name="['dataSource', myCurrent * 10 + index, 'channelId']"
|
||||
>
|
||||
<j-select
|
||||
style="width: 100%"
|
||||
v-model:value="record[column.dataIndex]"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
:options="channelList"
|
||||
@select="(_, option) => { record.provider = option.provider }"
|
||||
|
@ -36,7 +37,7 @@
|
|||
</template>
|
||||
<template v-if="column.dataIndex === 'collectorId'">
|
||||
<j-form-item
|
||||
:name="['dataSource', index, 'collectorId']"
|
||||
:name="['dataSource', myCurrent * 10 + index, 'collectorId']"
|
||||
:rules="[
|
||||
{
|
||||
required: !!record.channelId,
|
||||
|
@ -53,7 +54,7 @@
|
|||
</template>
|
||||
<template v-if="column.dataIndex === 'pointId'">
|
||||
<j-form-item
|
||||
:name="['dataSource', index, 'pointId']"
|
||||
:name="['dataSource', myCurrent * 10 + index, 'pointId']"
|
||||
:rules="[
|
||||
{
|
||||
required: !!record.channelId,
|
||||
|
@ -157,6 +158,8 @@ const columns = [
|
|||
},
|
||||
];
|
||||
|
||||
const myCurrent = ref(0)
|
||||
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
|
@ -235,6 +238,10 @@ const handleSearch = async () => {
|
|||
loading.value = false;
|
||||
};
|
||||
|
||||
const tableChange = (pagination: { current: number }) => {
|
||||
myCurrent.value = pagination.current - 1
|
||||
}
|
||||
|
||||
const unbind = async (id: string) => {
|
||||
if (id) {
|
||||
const resp = await removeMapping('device', instanceStore.current.id, [
|
||||
|
@ -286,4 +293,4 @@ const onSave = () => {
|
|||
:deep(.ant-form-item) {
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<template>
|
||||
<j-select allowClear v-model:value="_value" @change="onChange" placeholder="请选择" style="width: 100%">
|
||||
<j-select allowClear v-model:value="_value" @change="onChange" placeholder="请选择" style="width: 100%" show-search :filter-option="filterOption">
|
||||
<j-select-option
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:value="item.id"
|
||||
:label="item.name"
|
||||
:filter-option="filterOption"
|
||||
>{{ item.name }}</j-select-option
|
||||
>
|
||||
</j-select>
|
||||
|
|
|
@ -243,11 +243,11 @@ const columns = [
|
|||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 'started',
|
||||
value: 'enabled',
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 'disable',
|
||||
value: 'disabled',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -313,8 +313,9 @@ const submitData = () => {
|
|||
if (form.id === '') {
|
||||
form.id = undefined;
|
||||
}
|
||||
const res = await addProduct(form);
|
||||
loading.value = false
|
||||
const res = await addProduct(form).finally(()=>{
|
||||
loading.value = false
|
||||
});
|
||||
if (res.status === 200) {
|
||||
onlyMessage('保存成功!');
|
||||
visible.value = false;
|
||||
|
|
|
@ -389,8 +389,7 @@ const beforeUpload = (file: any) => {
|
|||
reader.readAsText(file);
|
||||
reader.onload = async (result) => {
|
||||
const text = result.target?.result;
|
||||
// console.log('text: ', text);
|
||||
// console.log(file);
|
||||
console.log(text);
|
||||
if (!file.type.includes('json')) {
|
||||
onlyMessage('请上传json格式文件', 'error');
|
||||
return false;
|
||||
|
@ -410,6 +409,10 @@ const beforeUpload = (file: any) => {
|
|||
if(!data?.name){
|
||||
data.name = "产品" + Date.now();
|
||||
}
|
||||
if(!data?.deviceType || JSON.stringify(data?.deviceType) === '{}' ){
|
||||
onlyMessage('缺少deviceType字段或对应的值','error')
|
||||
return false
|
||||
}
|
||||
const res = await updateDevice(data);
|
||||
if (res.status === 200) {
|
||||
onlyMessage('操作成功');
|
||||
|
|
|
@ -61,19 +61,17 @@
|
|||
title="继承自产品物模型的数据不支持修改"
|
||||
>
|
||||
<!-- <ModelButton :disabled="true"/>-->
|
||||
<j-button :disabled="true" type="link" style="padding-left: 0;">
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</j-button>
|
||||
<j-button :disabled="true" type="link" >
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</j-button>
|
||||
|
||||
</j-tooltip>
|
||||
<PermissionButton
|
||||
v-else
|
||||
:has-permission="`${permission}:update`"
|
||||
type="link"
|
||||
key="inputs"
|
||||
>
|
||||
<InputParams v-model:value="data.record.inputs" />
|
||||
</PermissionButton>
|
||||
<InputParams
|
||||
v-else
|
||||
v-model:value="data.record.inputs"
|
||||
:has-permission="`${permission}:update`"
|
||||
/>
|
||||
</template>
|
||||
<template #output="{ data }">
|
||||
{{ data.record.output?.type }}
|
||||
|
@ -93,19 +91,16 @@
|
|||
title="继承自产品物模型的数据不支持修改"
|
||||
>
|
||||
<!-- <ModelButton :disabled="true"/>-->
|
||||
<j-button :disabled="true" type="link" style="padding-left: 0;">
|
||||
<j-button :disabled="true" type="link">
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
<PermissionButton
|
||||
v-else
|
||||
:has-permission="`${permission}:update`"
|
||||
type="link"
|
||||
key="properties"
|
||||
>
|
||||
<ConfigParams v-model:value="data.record.valueType" />
|
||||
</PermissionButton>
|
||||
<ConfigParams
|
||||
v-else
|
||||
v-model:value="data.record.valueType"
|
||||
:has-permission="`${permission}:update`"
|
||||
/>
|
||||
</template>
|
||||
<template #outInput>
|
||||
object
|
||||
|
@ -116,33 +111,27 @@
|
|||
</j-tag>
|
||||
</template>
|
||||
<template #other="{ data }">
|
||||
<j-tooltip
|
||||
<!-- <j-tooltip
|
||||
v-if="target === 'device' && productNoEdit.id?.includes?.(data.record.id)"
|
||||
title="继承自产品物模型的数据不支持修改"
|
||||
>
|
||||
> -->
|
||||
<!-- <ModelButton :disabled="true"/>-->
|
||||
<j-button :disabled="true" type="link" style="padding-left: 0;">
|
||||
<!-- <j-button :disabled="true" type="link" style="padding-left: 0;">
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
<PermissionButton
|
||||
v-else
|
||||
:has-permission="`${permission}:update`"
|
||||
type="link"
|
||||
key="setting"
|
||||
>
|
||||
<OtherSetting
|
||||
</j-button> -->
|
||||
<!-- </j-tooltip> -->
|
||||
<OtherSetting
|
||||
v-model:value="data.record.expands"
|
||||
:id="data.record.id"
|
||||
:disabled="target === 'device' && productNoEdit.id?.includes?.(data.record.id)"
|
||||
:record="data.record"
|
||||
:type="data.record.valueType.type"
|
||||
:has-permission="`${permission}:update`"
|
||||
:tooltip="target === 'device' && productNoEdit.id?.includes?.(data.record.id) ? {
|
||||
title: '继承自产品物模型的数据不支持删除',
|
||||
} : undefined"
|
||||
:type="data.record.valueType.type"
|
||||
/>
|
||||
</PermissionButton>
|
||||
|
||||
</template>
|
||||
<template #action="{data}">
|
||||
|
@ -563,4 +552,4 @@ onBeforeRouteLeave((to, from, next) => { // 设备管理外路由跳转
|
|||
justify-content: space-between;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -6,10 +6,9 @@ import { EventLevel } from "@/views/device/data";
|
|||
import {MetadataType} from "@/views/device/Product/typings";
|
||||
import { getUnit } from '@/api/device/instance';
|
||||
import {Ref} from "vue";
|
||||
import {omit, pick} from "lodash-es";
|
||||
import {omit, pick, isObject, cloneDeep} from "lodash-es";
|
||||
import { message } from 'jetlinks-ui-components'
|
||||
import { onlyMessage } from "@/utils/comm";
|
||||
import {cloneDeep} from "lodash";
|
||||
interface DataTableColumnProps extends ColumnProps {
|
||||
type?: string,
|
||||
components?: {
|
||||
|
@ -37,9 +36,7 @@ const type = {
|
|||
report: '上报',
|
||||
};
|
||||
|
||||
export const validatorConfig = (value: any, isObject: boolean = false) => {
|
||||
|
||||
console.log(value)
|
||||
export const validatorConfig = (value: any, _isObject: boolean = false) => {
|
||||
|
||||
if (!value) {
|
||||
return Promise.resolve()
|
||||
|
@ -52,11 +49,11 @@ export const validatorConfig = (value: any, isObject: boolean = false) => {
|
|||
return Promise.reject('请选择元素类型')
|
||||
}
|
||||
|
||||
if (isObject && value.type === 'object' && !value.properties?.length) {
|
||||
if (_isObject && value.type === 'object' && !value.properties?.length) {
|
||||
return Promise.reject('请添加参数')
|
||||
}
|
||||
|
||||
if (value.type === 'file' && (!value.fileType || !Object.keys(value.fileType).length)) {
|
||||
if (value.type === 'file' && (!value.fileType || (isObject(value.fileType) && !Object.keys(value.fileType).length))) {
|
||||
return Promise.reject('请选择文件类型')
|
||||
}
|
||||
|
||||
|
@ -665,4 +662,4 @@ export const TypeStringMap = {
|
|||
// MetadataMapping.set('tags', TagColumns);
|
||||
// MetadataMapping.set('functions', FunctionColumns);
|
||||
//
|
||||
// export default MetadataMapping;
|
||||
// export default MetadataMapping;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
{{ TypeStringMap[data.record.valueType?.type] }}
|
||||
</template>
|
||||
<template #config="{ data }">
|
||||
<!-- <OtherConfigInfo :value="data.record.valueType"></OtherConfigInfo>-->
|
||||
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
|
||||
</template>
|
||||
</DataTableObject>
|
||||
|
@ -54,7 +53,7 @@
|
|||
|
||||
<script setup lang="ts" name="MetadataDataType">
|
||||
import { getUnit } from '@/api/device/instance';
|
||||
import { ValueObject } from '../components'
|
||||
import {DataType, ValueObject} from '../components'
|
||||
import {
|
||||
DataTableTypeSelect,
|
||||
DataTableArray,
|
||||
|
@ -68,7 +67,7 @@ import {
|
|||
DataTableObject,
|
||||
} from 'jetlinks-ui-components';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import {handleTypeValue, typeSelectChange, TypeStringMap, useUnit} from '../columns'
|
||||
import {handleTypeValue, typeSelectChange, TypeStringMap, useUnit, validatorConfig} from '../columns'
|
||||
import ConfigModal from './ConfigModal.vue'
|
||||
import { Form } from 'jetlinks-ui-components'
|
||||
|
||||
|
@ -137,7 +136,6 @@ const columns = [{
|
|||
required: true,
|
||||
rules: [{
|
||||
validator(_: any, value: any) {
|
||||
console.log('validator',value)
|
||||
if (!value?.type) {
|
||||
return Promise.reject('请选择数据类型')
|
||||
}
|
||||
|
@ -150,7 +148,23 @@ const columns = [{
|
|||
{
|
||||
title: '其他配置',
|
||||
dataIndex: 'config',
|
||||
width: 100
|
||||
width: 100,
|
||||
// components: {
|
||||
// name: ConfigModal,
|
||||
// props: {
|
||||
// showOther: false
|
||||
// }
|
||||
// },
|
||||
form: {
|
||||
rules: [{
|
||||
callback(rule: any, value: any, dataSource: any[]) {
|
||||
const field = rule.field.split('.')
|
||||
const fieldIndex = Number(field[1])
|
||||
const values = dataSource.find((item, index) => index === fieldIndex)
|
||||
return validatorConfig(values?.valueType)
|
||||
}
|
||||
}]
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
|
|
@ -6,7 +6,15 @@
|
|||
<template #config="{ data }">
|
||||
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
|
||||
</template>
|
||||
<ModelButton />
|
||||
<PermissionButton
|
||||
key="properties"
|
||||
:has-permission="hasPermission"
|
||||
style="padding-left: 0;"
|
||||
type="link"
|
||||
>
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</PermissionButton>
|
||||
</DataTableObject>
|
||||
</template>
|
||||
|
||||
|
@ -23,7 +31,7 @@ import {omit} from "lodash-es";
|
|||
import {TypeStringMap, validatorConfig} from "../../columns";
|
||||
|
||||
const columns = [
|
||||
{
|
||||
{
|
||||
title: '参数标识',
|
||||
dataIndex: 'id',
|
||||
type: 'text',
|
||||
|
@ -52,7 +60,7 @@ const columns = [
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
title: '参数名称',
|
||||
dataIndex: 'name',
|
||||
type: 'text',
|
||||
|
@ -139,6 +147,7 @@ const props = defineProps({
|
|||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
hasPermission: String,
|
||||
});
|
||||
|
||||
const value = ref(props.value.properties);
|
||||
|
@ -151,7 +160,7 @@ const confirm = (data: any) => {
|
|||
})
|
||||
|
||||
console.log('ConfigParams',newObject)
|
||||
|
||||
|
||||
emit('update:value', {
|
||||
properties: newObject,
|
||||
type: 'object',
|
||||
|
|
|
@ -9,7 +9,14 @@
|
|||
<template #config="{ data }">
|
||||
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
|
||||
</template>
|
||||
<ModelButton />
|
||||
<PermissionButton
|
||||
key="properties"
|
||||
:has-permission="hasPermission"
|
||||
type="link"
|
||||
>
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</PermissionButton>
|
||||
</DataTableObject>
|
||||
</template>
|
||||
|
||||
|
@ -43,6 +50,7 @@ const props = defineProps({
|
|||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
hasPermission: String,
|
||||
});
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
|
||||
|
|
|
@ -55,15 +55,15 @@
|
|||
import { getUnit } from '@/api/device/instance';
|
||||
import {
|
||||
DataTableTypeSelect,
|
||||
DataTableArray,
|
||||
DataTableString,
|
||||
DataTableInteger,
|
||||
DataTableDouble,
|
||||
DataTableBoolean,
|
||||
DataTableEnum,
|
||||
DataTableFile,
|
||||
DataTableDate,
|
||||
DataTableObject,
|
||||
DataTableArray,
|
||||
DataTableString,
|
||||
DataTableInteger,
|
||||
DataTableDouble,
|
||||
DataTableBoolean,
|
||||
DataTableEnum,
|
||||
DataTableFile,
|
||||
DataTableDate,
|
||||
DataTableObject, Form,
|
||||
} from 'jetlinks-ui-components';
|
||||
|
||||
import ConfigModal from '@/views/device/components/Metadata/Base/components/ConfigModal.vue'
|
||||
|
@ -83,7 +83,7 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
const options = ref<{ label: string; value: string }[]>([]);
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
|
@ -235,6 +235,7 @@ const valueChange = () => {
|
|||
...props.value,
|
||||
output: {...data.value, type: type.value},
|
||||
});
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -17,4 +17,4 @@ const props = defineProps({
|
|||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -120,7 +120,7 @@ const validator = (_: any, value: any) => {
|
|||
}
|
||||
|
||||
const typeValidator = (_: any, value: any) => {
|
||||
if (value === undefined) {
|
||||
if (value === undefined || value === null) {
|
||||
return Promise.reject(validatorTip())
|
||||
}
|
||||
if (type === 'string' && value?.length > 64) {
|
||||
|
@ -146,7 +146,7 @@ const handleValueByType = (value: any, isRange: boolean = false) => {
|
|||
|
||||
const confirm = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
formRef.value.validate().then(() => {
|
||||
formRef.value.validate().then((res) => {
|
||||
let value = props.value.range === true ? formData.rangeValue : formData.value
|
||||
|
||||
if (['int', 'long'].includes(type)) {
|
||||
|
|
|
@ -51,8 +51,17 @@
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ModelButton :disabled="disabled"/>
|
||||
<PermissionButton
|
||||
key="setting"
|
||||
:disabled="disabled"
|
||||
:has-permission="hasPermission"
|
||||
:tooltip="tooltip"
|
||||
style="padding-left: 0;"
|
||||
type="link"
|
||||
>
|
||||
<AIcon type="SettingOutlined" />
|
||||
配置
|
||||
</PermissionButton>
|
||||
</j-popconfirm-modal>
|
||||
</template>
|
||||
|
||||
|
@ -88,6 +97,8 @@ const props = defineProps({
|
|||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
hasPermission: String,
|
||||
tooltip: Object
|
||||
})
|
||||
|
||||
const fullRef = inject(FULL_CODE);
|
||||
|
@ -225,4 +236,4 @@ watch(() => props.value, () => {
|
|||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
v-if="myValue != 'manual' && !showReset"
|
||||
:bodyStyle="{
|
||||
width: '450px',
|
||||
height: myValue === 'rule' ? '300px' : '80px',
|
||||
height: myValue === 'rule' ? '300px' : '90px',
|
||||
}"
|
||||
:get-popup-container="(node) => fullRef || node"
|
||||
placement="bottomRight"
|
||||
|
@ -294,7 +294,9 @@ onMounted(()=>{
|
|||
item === props.value?.id ? showReset.value = true : ''
|
||||
})
|
||||
}
|
||||
handleSearch()
|
||||
if(isNoCommunity && myValue.value === 'rule'){
|
||||
handleSearch()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ const codecs = ref<{ id: string; name: string }[]>()
|
|||
const routeChange = async (id: string) => {
|
||||
const res = await getCodecs()
|
||||
if (res.status === 200) {
|
||||
codecs.value = [{ id: 'jetlinks', name: 'jetlinks' }].concat(res.result)
|
||||
codecs.value = [{ id: 'jetlinks', name: '标准物模型' }].concat(res.result)
|
||||
}
|
||||
if (props.type === 'device' && id) {
|
||||
detail(id as string).then((resp) => {
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
<template #label>
|
||||
<j-space>
|
||||
物模型
|
||||
<j-tooltip title="在线编辑器中编写物模型脚本">
|
||||
<j-tooltip title="在编辑器中编写物模型脚本">
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="color: rgb(136, 136, 136)"
|
||||
|
@ -267,17 +267,17 @@ loadData();
|
|||
// }
|
||||
// if(!item?.name){
|
||||
// onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
// return
|
||||
// return
|
||||
// }
|
||||
// if(!item?.expands?.source){
|
||||
// onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error');
|
||||
// return
|
||||
// return
|
||||
// }
|
||||
|
||||
|
||||
// if((item?.expands?.source === 'device' || item?.expands?.source === 'rule') && !item?.expands?.type){
|
||||
// onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error');
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }) || false
|
||||
// }
|
||||
const requiredCheck = (data:any) =>{
|
||||
|
@ -287,12 +287,12 @@ const requiredCheck = (data:any) =>{
|
|||
if(!item?.id){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失id属性`,'error');
|
||||
check = true
|
||||
return
|
||||
return
|
||||
}
|
||||
if(!item?.name){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
check = true
|
||||
return
|
||||
return
|
||||
}
|
||||
if(!item?.valueType?.type){
|
||||
onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
|
||||
|
@ -302,14 +302,14 @@ const requiredCheck = (data:any) =>{
|
|||
if(!item?.expands?.source){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error');
|
||||
check = true
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if((item?.expands?.source === 'device' || item?.expands?.source === 'rule') && !item?.expands?.type){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if(data?.functions && !check){
|
||||
|
@ -323,7 +323,7 @@ const requiredCheck = (data:any) =>{
|
|||
onlyMessage(`方法定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
if(!item?.async && item?.async !== false){
|
||||
onlyMessage(`方法定义第${index + 1}个数组中缺失async属性`,'error');
|
||||
check = true
|
||||
|
@ -375,13 +375,13 @@ const requiredCheck = (data:any) =>{
|
|||
onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组第${number+1}项的valueType.type属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}else{
|
||||
onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ const requiredCheck = (data:any) =>{
|
|||
onlyMessage(`标签定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
if(!item?.valueType?.type){
|
||||
onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
|
||||
check = true
|
||||
|
@ -419,18 +419,18 @@ const aliCheck = (data:any) => {
|
|||
if(!item?.identifier){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失identifier属性`,'error');
|
||||
check = true
|
||||
return
|
||||
return
|
||||
}
|
||||
if(!item?.name){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
check = true
|
||||
return
|
||||
return
|
||||
}
|
||||
if(!item?.dataType?.type){
|
||||
onlyMessage(`属性定义第${index + 1}个数组中缺失dataType.type属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
if(data?.functions && !check){
|
||||
|
@ -444,7 +444,7 @@ const aliCheck = (data:any) => {
|
|||
onlyMessage(`方法定义第${index + 1}个数组中缺失name属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
if(!item?.callType){
|
||||
onlyMessage(`方法定义第${index + 1}个数组中缺失callType属性`,'error');
|
||||
check = true
|
||||
|
@ -486,23 +486,23 @@ const aliCheck = (data:any) => {
|
|||
onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的dataType.type属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
if(!i?.dataType?.specs){
|
||||
onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的dataType.specs属性`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}else{
|
||||
onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组`,'error');
|
||||
check = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return check
|
||||
}
|
||||
}
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||
if(file.type === 'application/json') {
|
||||
const reader = new FileReader();
|
||||
|
@ -510,7 +510,7 @@ const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
|||
reader.onload = (json) => {
|
||||
if(json.target?.result){
|
||||
const data = JSON.parse(json.target?.result);
|
||||
let check = formModel.metadata === 'jetlinks' ? requiredCheck(data) : aliCheck(data)
|
||||
let check = formModel.metadata === 'jetlinks' ? requiredCheck(data) : aliCheck(data)
|
||||
if(!check){
|
||||
onlyMessage('操作成功!')
|
||||
formModel.import = json.target?.result;
|
||||
|
@ -637,7 +637,7 @@ const handleImport = async () => {
|
|||
data[data?.type === 'copy' ? 'copy' : 'import'] ||
|
||||
'{}',
|
||||
);
|
||||
if(data?.type === 'import'){
|
||||
if(data?.type !== 'copy'){
|
||||
Object.keys(_object).forEach((i:any)=>{
|
||||
const map = new Map()
|
||||
_object[i].forEach((item:any)=>(
|
||||
|
@ -724,4 +724,4 @@ const handleImport = async () => {
|
|||
line-height: 30px;
|
||||
margin: 0 -11px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
|
@ -20,19 +20,34 @@ const handle = async (appId: string, url: string) => {
|
|||
const res = await getAppInfo_api(appId);
|
||||
let menuUrl: any = url;
|
||||
if (res.status === 200) {
|
||||
if (res.result.page.routeType === 'hash') {
|
||||
menuUrl = `${url}`;
|
||||
const result = res.result
|
||||
if (result.page.routeType === 'hash') {
|
||||
menuUrl = url.startsWith('/') ? `#${url}` : `#/${url}`;
|
||||
}
|
||||
if (res.result.provider === 'internal-standalone') {
|
||||
const urlStandalone = `${res.result.page.baseUrl}/api/application/sso/${appId}/login?redirect=${menuUrl}?layout=false`;
|
||||
|
||||
if (result.page.parameters) {
|
||||
const params = new URLSearchParams()
|
||||
result.page.parameters.forEach((item: any) => {
|
||||
if (item?.key) {
|
||||
params.set(item.key,item.value)
|
||||
}
|
||||
})
|
||||
const urlParams = params.toString()
|
||||
if (urlParams) {
|
||||
menuUrl += `?${urlParams}`
|
||||
}
|
||||
}
|
||||
|
||||
if (result.provider === 'internal-standalone') {
|
||||
const urlStandalone = `${result.page.baseUrl}/api/application/sso/${appId}/login?redirect=${menuUrl}?layout=false`;
|
||||
iframeUrl.value = urlStandalone;
|
||||
} else if (res.result.provider === 'internal-integrated') {
|
||||
} else if (result.provider === 'internal-integrated') {
|
||||
const tokenUrl = `${
|
||||
res.result.page.baseUrl
|
||||
}?X-Access-Token=${LocalStore.get(TOKEN_KEY)}`;
|
||||
result.page.baseUrl
|
||||
}/${menuUrl}?layout=false&X-Access-Token=${LocalStore.get(TOKEN_KEY)}`;
|
||||
iframeUrl.value = tokenUrl;
|
||||
} else {
|
||||
const urlOther = `${res.result.page.baseUrl}/${menuUrl}`;
|
||||
const urlOther = `${result.page.baseUrl}/${menuUrl}`;
|
||||
iframeUrl.value = urlOther;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,10 @@ const visible = ref<boolean>(false);
|
|||
const modalForm = reactive<modalState>({
|
||||
host: '0.0.0.0',
|
||||
});
|
||||
|
||||
const regDomain = new RegExp(
|
||||
// /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i,
|
||||
/^[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$/
|
||||
)
|
||||
/**
|
||||
* 校验官网地址
|
||||
*/
|
||||
|
@ -153,7 +156,7 @@ const validateUrl = async (_rule: Rule, value: string) => {
|
|||
if (!value) {
|
||||
return Promise.reject('请输入公网地址');
|
||||
} else {
|
||||
if (!testIpv4_6(value)) {
|
||||
if (!testIpv4_6(value) && !regDomain.test(value)) {
|
||||
return Promise.reject('请输入正确的公网地址');
|
||||
}
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -4,91 +4,56 @@
|
|||
<j-card>
|
||||
<j-row :gutter="[24, 24]" style="padding: 24px">
|
||||
<j-col :span="12">
|
||||
<j-form
|
||||
class="form"
|
||||
layout="vertical"
|
||||
:model="formData"
|
||||
name="basic"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 24 }"
|
||||
autocomplete="off"
|
||||
>
|
||||
<j-form-item
|
||||
label="证书标准"
|
||||
v-bind="validateInfos.type"
|
||||
>
|
||||
<j-form class="form" layout="vertical" :model="formData" name="basic" :label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 24 }" autocomplete="off" ref="formRef">
|
||||
<j-form-item label="证书标准" name="type"
|
||||
:rules="[{ required: true, message: '请选择证书标准', trigger: 'blur' }]">
|
||||
<j-radio-group v-model:value="formData.type">
|
||||
<j-radio-button
|
||||
class="form-radio-button"
|
||||
value="common"
|
||||
>
|
||||
<img
|
||||
:src="getImage('/certificate.png')"
|
||||
/>
|
||||
<j-radio-button class="form-radio-button" value="common">
|
||||
<img :src="getImage('/certificate.png')" />
|
||||
</j-radio-button>
|
||||
</j-radio-group>
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
label="证书名称"
|
||||
v-bind="validateInfos.name"
|
||||
>
|
||||
<j-input
|
||||
placeholder="请输入证书名称"
|
||||
v-model:value="formData.name"
|
||||
/>
|
||||
<j-form-item label="证书名称" name="name" :rules="[
|
||||
{ required: true, message: '请输入证书名称', trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input placeholder="请输入证书名称" v-model:value="formData.name" />
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
label="证书文件"
|
||||
v-bind="validateInfos['configs.cert']"
|
||||
>
|
||||
<CertificateFile
|
||||
name="cert"
|
||||
v-model:modelValue="formData.configs.cert"
|
||||
placeholder="请输入证书文件"
|
||||
/>
|
||||
<j-form-item label="证书文件" :name="['configs','cert']" :rules="[
|
||||
{ required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
]">
|
||||
<CertificateFile name="cert" v-model:modelValue="formData.configs.cert"
|
||||
placeholder="请输入证书文件" />
|
||||
</j-form-item>
|
||||
<j-form-item label="证书类型" v-bind="validateInfos.mode">
|
||||
<j-form-item label="证书类型" name="mode"
|
||||
:rules="[{ required: true, message: '请选择证书类型', trigger: 'blur' }]">
|
||||
<j-radio-group v-model:value="formData.mode" button-style="solid">
|
||||
<j-radio-button value="client" style="margin-right: 30px;" size="large">客户端</j-radio-button>
|
||||
<j-radio-button value="client" style="margin-right: 30px;"
|
||||
size="large">客户端</j-radio-button>
|
||||
<j-radio-button value="server" size="large">服务端</j-radio-button>
|
||||
</j-radio-group>
|
||||
</j-form-item>
|
||||
<j-form-item label="认证方式" v-if="formData.mode === 'client'" v-bind="validateInfos.authenticationMethod">
|
||||
<!-- <j-form-item label="认证方式" v-if="formData.mode === 'client'" v-bind="validateInfos.authenticationMethod">
|
||||
<j-radio-group button-style="solid" v-model:value="formData.authenticationMethod">
|
||||
<j-radio-button value="single" style="margin-right: 30px;" size="large">单向认证</j-radio-button>
|
||||
<j-radio-button value="binomial" size="large">双向认证</j-radio-button>
|
||||
</j-radio-group>
|
||||
</j-form-item> -->
|
||||
<j-form-item label="证书私钥" v-if="formData.mode !== 'client'" :name="['configs','key']" :rules="[
|
||||
{ required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
]">
|
||||
<CertificateFile name="key" v-model:modelValue="formData.configs.key"
|
||||
placeholder="请输入证书私钥" />
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
label="证书私钥"
|
||||
v-bind="validateInfos['configs.key']"
|
||||
>
|
||||
<CertificateFile
|
||||
name="key"
|
||||
v-model:modelValue="formData.configs.key"
|
||||
placeholder="请输入证书私钥"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item label="说明" name="description">
|
||||
<j-textarea
|
||||
placeholder="请输入说明"
|
||||
v-model:value="formData.description"
|
||||
:maxlength="200"
|
||||
:rows="3"
|
||||
showCount
|
||||
/>
|
||||
<j-form-item label="说明" name="description" :rules="[{ max: 200, message: '最多可输入200个字符' }]">
|
||||
<j-textarea placeholder="请输入说明" v-model:value="formData.description" :maxlength="200"
|
||||
:rows="3" showCount />
|
||||
</j-form-item>
|
||||
|
||||
<j-form-item>
|
||||
<j-button
|
||||
v-if="view === 'false'"
|
||||
class="form-submit"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
@click.prevent="onSubmit"
|
||||
:loading="loading"
|
||||
>保存</j-button
|
||||
>
|
||||
<j-button v-if="view === 'false'" class="form-submit" html-type="submit" type="primary"
|
||||
@click.prevent="onSubmit" :loading="loading">保存</j-button>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-col>
|
||||
|
@ -131,8 +96,9 @@ const route = useRoute();
|
|||
const view = route.query.view as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const useForm = Form.useForm;
|
||||
// const useForm = Form.useForm;
|
||||
|
||||
const formRef = ref()
|
||||
const fileLoading = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
|
@ -144,49 +110,46 @@ const formData = ref<FormDataType>({
|
|||
key: '',
|
||||
},
|
||||
description: '',
|
||||
mode:'server',
|
||||
authenticationMethod:'single'
|
||||
mode: 'server',
|
||||
authenticationMethod: 'single'
|
||||
});
|
||||
|
||||
const { resetFields, validate, validateInfos } = useForm(
|
||||
formData,
|
||||
reactive({
|
||||
type: [{ required: true, message: '请选择证书标准', trigger: 'blur' }],
|
||||
name: [
|
||||
{ required: true, message: '请输入证书名称', trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
'configs.cert': [
|
||||
{ required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
],
|
||||
'configs.key': [
|
||||
{ required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
],
|
||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
mode:[{ required: true, message: '请选择证书类型', trigger: 'blur' }],
|
||||
authenticationMethod:[{ required: true, message: '请选择认证方式', trigger: 'blur' }]
|
||||
}),
|
||||
);
|
||||
// const rules = {
|
||||
// type: [{ required: true, message: '请选择证书标准', trigger: 'blur' }],
|
||||
// name: [
|
||||
// { required: true, message: '请输入证书名称', trigger: 'blur' },
|
||||
// { max: 64, message: '最多可输入64个字符' },
|
||||
// ],
|
||||
// 'configs.cert': [
|
||||
// { required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
// ],
|
||||
// 'configs.key': [
|
||||
// { required: true, message: '请输入或上传文件', trigger: 'blur' },
|
||||
// ],
|
||||
// description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
// mode:[{ required: true, message: '请选择证书类型', trigger: 'blur' }],
|
||||
// authenticationMethod:[{ required: true, message: '请选择认证方式', trigger: 'blur' }]
|
||||
// );
|
||||
|
||||
const onSubmit = () => {
|
||||
validate()
|
||||
formRef.value.validate()
|
||||
.then(async (res) => {
|
||||
let params:any = toRaw(formData.value);
|
||||
if(formData.value.mode === 'client'){
|
||||
if(formData.value.authenticationMethod === 'binomial'){
|
||||
let params: any = toRaw(formData.value);
|
||||
if (formData.value.mode === 'client') {
|
||||
if (formData.value.authenticationMethod === 'binomial') {
|
||||
params.configs.trust = params.configs.cert
|
||||
}else{
|
||||
} else {
|
||||
params.configs = {
|
||||
key:formData.value.configs.key,
|
||||
trust:formData.value.configs.cert
|
||||
// key:formData.value.configs.key,
|
||||
trust: formData.value.configs.cert
|
||||
}
|
||||
}
|
||||
}
|
||||
loading.value = true;
|
||||
const response =
|
||||
id === ':id'
|
||||
? await save(params).catch(() => {})
|
||||
: await update({ ...params, id }).catch(() => {});
|
||||
? await save(params).catch(() => { })
|
||||
: await update({ ...params, id }).catch(() => { });
|
||||
if (response?.status === 200) {
|
||||
onlyMessage('操作成功', 'success');
|
||||
router.push('/iot/link/certificate');
|
||||
|
@ -217,9 +180,9 @@ const detail = async (id: string) => {
|
|||
const type = result.type.value as TypeObjType;
|
||||
formData.value = {
|
||||
...result,
|
||||
configs:{
|
||||
key:result.configs.key,
|
||||
cert:result.configs?.cert ? result.configs?.cert : result.configs?.trust
|
||||
configs: {
|
||||
key: result.configs.key,
|
||||
cert: result.configs?.cert ? result.configs?.cert : result.configs?.trust
|
||||
},
|
||||
mode: result.mode.value,
|
||||
authenticationMethod: result.authenticationMethod.value,
|
||||
|
@ -239,6 +202,7 @@ detail(id);
|
|||
width: 148px;
|
||||
height: 80px;
|
||||
padding: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -111,7 +111,7 @@ const pickerTimeChange = (value: any) => {
|
|||
};
|
||||
const changeType = (value:any) =>{
|
||||
getNetworkEcharts(data.value);
|
||||
}
|
||||
}
|
||||
const getNetworkEcharts = async (val: any) => {
|
||||
loading.value = true;
|
||||
const resp: any = await dashboard(networkParams(val));
|
||||
|
@ -149,10 +149,16 @@ const getNetworkEcharts = async (val: any) => {
|
|||
|
||||
const formatterData = (value: any) => {
|
||||
let _data = '';
|
||||
if (value >= 1024 && value < 1024 * 1024) {
|
||||
_data = `${Number((value / 1024).toFixed(2))}KB`;
|
||||
} else if (value >= 1024 * 1024) {
|
||||
_data = `${Number((value / 1024 / 1024).toFixed(2))}M`;
|
||||
const kb = 1024
|
||||
const mb = kb**2
|
||||
const gb = kb**3
|
||||
|
||||
if (value >= kb && value < mb) {
|
||||
_data = `${Number((value / kb).toFixed(2))}KB`;
|
||||
} else if (value >= mb && value < gb) {
|
||||
_data = `${Number((value / mb).toFixed(2))}M`;
|
||||
} else if (value >= gb) {
|
||||
_data = `${Number((value / gb).toFixed(2))}G`;
|
||||
} else {
|
||||
_data = `${value}B`;
|
||||
}
|
||||
|
|
|
@ -1285,7 +1285,7 @@ const changeType = (value: string) => {
|
|||
if (value !== 'MQTT_CLIENT') {
|
||||
const { configuration } = dynamicValidateForm.cluster[0];
|
||||
value && (configuration.host = '0.0.0.0');
|
||||
}else{
|
||||
}else if(isNoCommunity){
|
||||
formData.value.shareCluster = false
|
||||
changeShareCluster(formData.value.shareCluster)
|
||||
}
|
||||
|
|
|
@ -32,4 +32,4 @@ watchEffect(() => {
|
|||
LocalStore.set(TOKEN_KEY, obj?.[TOKEN_KEY]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
|
@ -5,12 +5,12 @@ const Webhook = () => {
|
|||
<div class={'doc'}>
|
||||
<h1>1. 概述</h1>
|
||||
<div>
|
||||
webhook是一个接收HTTP请求的URL(本平台默认只支持HTTP
|
||||
POST请求),实现了Webhook的第三方系统可以基于该URL订阅本平台系统信息,本平台按配置把特定的事件结果推送到指定的地址,便于系统做后续处理。
|
||||
WebHook是一个接收HTTP请求的URL(本平台默认只支持HTTP
|
||||
POST请求),实现了WebHook的第三方系统可以基于该URL订阅本平台系统信息,本平台按配置把特定的事件结果推送到指定的地址,便于系统做后续处理。
|
||||
</div>
|
||||
<h1>2.通知配置说明</h1>
|
||||
<h2>1、Webhook</h2>
|
||||
<div>Webhook地址。</div>
|
||||
<h2>1、WebHook</h2>
|
||||
<div>WebHook地址。</div>
|
||||
|
||||
<h2>2、请求头</h2>
|
||||
<div>
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
"
|
||||
>
|
||||
<j-form-item
|
||||
label="webHook"
|
||||
label="WebHook"
|
||||
v-bind="validateInfos['configuration.url']"
|
||||
:rules='[{ max: 64, message: "最多可输入64个字符" }]'
|
||||
>
|
||||
|
@ -88,7 +88,7 @@
|
|||
v-model:value="
|
||||
formData.configuration.url
|
||||
"
|
||||
placeholder="请输入webHook"
|
||||
placeholder="请输入WebHook"
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
|
@ -278,12 +278,12 @@
|
|||
<!-- webhook -->
|
||||
<template v-if="formData.type === 'webhook'">
|
||||
<j-form-item
|
||||
label="Webhook"
|
||||
label="WebHook"
|
||||
v-bind="validateInfos['configuration.url']"
|
||||
>
|
||||
<j-input
|
||||
v-model:value="formData.configuration.url"
|
||||
placeholder="请输入Webhook"
|
||||
placeholder="请输入WebHook"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item label="请求头">
|
||||
|
@ -447,7 +447,7 @@ const formRules = ref({
|
|||
],
|
||||
// webhook
|
||||
'configuration.url': [
|
||||
{ required: true, message: '请输入Webhook', trigger: 'blur' },
|
||||
{ required: true, message: '请输入WebHook', trigger: 'blur' },
|
||||
// {
|
||||
// pattern:
|
||||
// /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[j-z]{2,6}\/?/,
|
||||
|
|
|
@ -28,7 +28,7 @@ export const NOTICE_METHOD: INoticeMethod[] = [
|
|||
value: 'sms',
|
||||
},
|
||||
{
|
||||
label: 'webhook',
|
||||
label: 'WebHook',
|
||||
value: 'webhook',
|
||||
},
|
||||
];
|
||||
|
@ -75,7 +75,7 @@ export const MSG_TYPE = {
|
|||
],
|
||||
webhook: [
|
||||
{
|
||||
label: 'webhook',
|
||||
label: 'WebHook',
|
||||
value: 'http',
|
||||
logo: getImage('/notice/webhook.png'),
|
||||
},
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
<div>
|
||||
1、平台支持将告警数据输出到kafka,第三方系统可订阅kafka中的告警数据,进行业务处理。
|
||||
</div>
|
||||
<h2>输出参数</h2>
|
||||
<h2>推送参数</h2>
|
||||
<div>
|
||||
<j-table
|
||||
:dataSource="outputData"
|
||||
|
|
|
@ -192,6 +192,12 @@ const columns = [
|
|||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'value',
|
||||
},
|
||||
},
|
||||
options: () => new Promise((resolve) => {
|
||||
getTreeData_api({ paging: false }).then((resp: any) => {
|
||||
const formatValue = (list: any[]) => {
|
||||
|
@ -260,4 +266,4 @@ const handleClick = (detail: any) => {
|
|||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -208,10 +208,17 @@ const columns = [
|
|||
},
|
||||
{
|
||||
dataIndex: 'id$dim-assets',
|
||||
key: 'id$dim-assets',
|
||||
title: '所属组织',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'value',
|
||||
},
|
||||
},
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
getTreeData_api({ paging: false }).then((resp: any) => {
|
||||
|
@ -289,4 +296,4 @@ onMounted(() => {
|
|||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -109,13 +109,17 @@ const upperOptions = computed(() => {
|
|||
});
|
||||
|
||||
const onChange = () => {
|
||||
const objValue: any = { source: _source.value, value: _value.value }
|
||||
if (_source.value === 'upper') {
|
||||
objValue.upperKey = _value.value
|
||||
}
|
||||
emit('update:value', _value.value);
|
||||
emit('update:source', _source.value);
|
||||
emit('change', { source: _source.value, value: _value.value });
|
||||
emit('change', objValue);
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
_value.value = props.value;
|
||||
_source.value = props.source || 'fixed';
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -173,11 +173,18 @@ const onChange = () => {
|
|||
|
||||
const onValueChange = (val: any, label: string) => {
|
||||
const optionColumn = isObject(val) && (val as any).metadata ? [(val as any).column] : []
|
||||
|
||||
const objectValue: any = {
|
||||
value: propertyModelRef?.propertiesValue,
|
||||
source: propertyModelRef?.source,
|
||||
}
|
||||
|
||||
if (propertyModelRef?.source === 'upper') {
|
||||
objectValue.upperKey = propertyModelRef?.propertiesValue
|
||||
}
|
||||
|
||||
const obj = {
|
||||
[`${propertyModelRef.properties}`]: {
|
||||
value: propertyModelRef?.propertiesValue,
|
||||
source: propertyModelRef?.source,
|
||||
},
|
||||
[`${propertyModelRef.properties}`]: objectValue
|
||||
};
|
||||
emit('update:value', obj);
|
||||
emit('change', label || val, optionColumn)
|
||||
|
@ -212,4 +219,4 @@ const onSave = () => {
|
|||
};
|
||||
|
||||
defineExpose({ onSave });
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
)
|
||||
"
|
||||
/>
|
||||
webhook
|
||||
WebHook
|
||||
</span>
|
||||
发送
|
||||
<span>{{
|
||||
|
|
|
@ -144,12 +144,7 @@
|
|||
|
||||
<RequestTable
|
||||
v-model:value="form.data.page.parameters"
|
||||
value-type="select"
|
||||
:value-options="[
|
||||
{ label: '用户ID', value: '用户ID' },
|
||||
{ label: '用户名', value: '用户名' },
|
||||
{ label: 'token', value: 'token' },
|
||||
]"
|
||||
value-type="input"
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
|
@ -1397,12 +1392,20 @@
|
|||
|
||||
<div class="dialog">
|
||||
<MenuDialog
|
||||
v-if="dialog.visible"
|
||||
v-if="dialog.visible && dialog.current.provider !== 'third-party'"
|
||||
v-model:visible="dialog.visible"
|
||||
:data="dialog.current"
|
||||
:mode="routeQuery.id ? 'edit' : 'add'"
|
||||
@refresh="menuStory.jumpPage('system/Apply')"
|
||||
/>
|
||||
<ThirdMenu
|
||||
v-if="dialog.visible && dialog.current.provider === 'third-party'"
|
||||
:data="dialog.current"
|
||||
:mode="routeQuery.id ? 'edit' : 'add'"
|
||||
mode="add"
|
||||
@cancel="dialog.visible = false"
|
||||
@ok="menuStory.jumpPage('system/Apply')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1420,6 +1423,7 @@ import {
|
|||
import FormLabel from './FormLabel.vue';
|
||||
import RequestTable from './RequestTable.vue';
|
||||
import MenuDialog from '../../componenets/MenuDialog.vue';
|
||||
import ThirdMenu from '../../componenets/ThirdMenu.vue';
|
||||
import { getImage, onlyMessage } from '@/utils/comm';
|
||||
import type { formType, dictType, optionsType, applyType } from '../typing';
|
||||
import { getRoleList_api } from '@/api/system/user';
|
||||
|
@ -1573,7 +1577,7 @@ const getType = async () => {
|
|||
typeOptions.value = arr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
await getType();
|
||||
getRoleIdList();
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<j-modal
|
||||
:confirmLoading="loading"
|
||||
class="edit-dialog-container"
|
||||
title="集成菜单"
|
||||
visible
|
||||
width="600px"
|
||||
@cancel="cancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<p>
|
||||
当前集成菜单
|
||||
</p>
|
||||
<j-tree
|
||||
v-if="menuTree.length"
|
||||
v-model:checkedKeys="menuState.checkedMenu"
|
||||
v-model:expandedKeys="menuState.expandedKeys"
|
||||
:fieldNames="{ key: 'code', title: 'name' }"
|
||||
:height="300"
|
||||
:tree-data="menuTree"
|
||||
checkable
|
||||
/>
|
||||
<j-empty
|
||||
v-else
|
||||
/>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script name="ThirdMenu" setup>
|
||||
import {getMenuTree_api, queryOwnThree} from '@/api/system/menu';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import { useRequest } from '@/hook'
|
||||
import {filterTree, getCheckByTree} from "@/views/system/Apply/componenets/util";
|
||||
import {
|
||||
saveOwnerMenu_api,
|
||||
updateApp_api,
|
||||
} from '@/api/system/apply';
|
||||
|
||||
const props = defineProps({
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'add'
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const menuStory = useMenuStore();
|
||||
const loading = ref(false)
|
||||
const emit = defineEmits(['ok', 'cancel']);
|
||||
const menuState = reactive({
|
||||
checkedMenu: [],
|
||||
expandedKeys: [],
|
||||
menuTree: ''
|
||||
})
|
||||
|
||||
const menuTree = computed(() => {
|
||||
try {
|
||||
return JSON.parse(menuState.menuTree || '[]')
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
useRequest(queryOwnThree,
|
||||
{
|
||||
defaultParams: { terms: [{ column: 'owner', termType: 'isnull', value: 0 }]},
|
||||
onSuccess(res) {
|
||||
menuState.menuTree = JSON.stringify(res.result)
|
||||
return res
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const { run } = useRequest(getMenuTree_api, {
|
||||
immediate: false,
|
||||
onSuccess(res) {
|
||||
menuState.checkedMenu = getCheckByTree(res.result)
|
||||
return res
|
||||
}
|
||||
}) // 获取应用绑定的菜单
|
||||
|
||||
const cancel = () => {
|
||||
if (props.mode === 'add') {
|
||||
menuStory.jumpPage('system/Apply/Save', {}, { id: props.data?.id })
|
||||
}
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
const handleOk = async () => {
|
||||
if (!menuState.checkedMenu.length) {
|
||||
onlyMessage('请勾选配置菜单', 'warning')
|
||||
return
|
||||
}
|
||||
const id = props.data.id
|
||||
const cloneData = JSON.parse(menuState.menuTree)
|
||||
const filterData = filterTree(cloneData, menuState.checkedMenu)
|
||||
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const resp = await saveOwnerMenu_api('iot', id, filterData)
|
||||
await updateApp_api(id, {
|
||||
...props.data,
|
||||
integrationModes: props.data?.integrationModes?.map((item) => item?.value || item),
|
||||
page: {
|
||||
...props.data?.page,
|
||||
configuration: {
|
||||
checkedSystem: props.data?.page?.configuration?.checkedSystem
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (resp.success) {
|
||||
// 保存集成菜单
|
||||
onlyMessage('操作成功');
|
||||
emit('ok')
|
||||
}
|
||||
loading.value = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getBindMenuData = () => {
|
||||
const id = props.data.id
|
||||
|
||||
run({
|
||||
terms: [
|
||||
{
|
||||
column: 'appId',
|
||||
value: id,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
if (props.data?.id) {
|
||||
getBindMenuData()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,27 @@
|
|||
export const getCheckByTree = (data: any[]): string[] => {
|
||||
let keys: string[] = []
|
||||
if (data.length) {
|
||||
data.forEach(item => {
|
||||
if (item.children) {
|
||||
keys = [...getCheckByTree(item.children), ...keys]
|
||||
} else {
|
||||
keys.push(item.code)
|
||||
}
|
||||
})
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
export const filterTree = (data: any[], ids: string[]) => {
|
||||
return data?.filter(item => {
|
||||
delete item.id
|
||||
item.options = {show: true}
|
||||
if (ids.includes(item.code)) {
|
||||
return true
|
||||
} else if (item.children) {
|
||||
item.children = filterTree(item.children, ids)
|
||||
return item.children.length >0
|
||||
}
|
||||
return false
|
||||
}) || []
|
||||
}
|
|
@ -183,12 +183,19 @@
|
|||
</div>
|
||||
<div class="dialogs">
|
||||
<MenuDialog
|
||||
v-if="dialogVisible"
|
||||
v-if="dialogVisible && current.provider !== 'third-party'"
|
||||
v-model:visible="dialogVisible"
|
||||
mode="edit"
|
||||
:data="current"
|
||||
@refresh="table.refresh"
|
||||
/>
|
||||
<ThirdMenu
|
||||
v-if="dialogVisible && current.provider === 'third-party'"
|
||||
:data="current"
|
||||
mode="edit"
|
||||
@cancel="dialogVisible = false"
|
||||
@ok="() => { dialogVisible = false; table.refresh}"
|
||||
/>
|
||||
</div>
|
||||
<Add v-if="visible" @close="visible = false" />
|
||||
</page-container>
|
||||
|
@ -197,6 +204,7 @@
|
|||
<script setup lang="ts" name="Apply">
|
||||
import PermissionButton from '@/components/PermissionButton/index.vue';
|
||||
import MenuDialog from './componenets/MenuDialog.vue';
|
||||
import ThirdMenu from './componenets/ThirdMenu.vue'
|
||||
import {
|
||||
getApplyList_api,
|
||||
changeApplyStatus_api,
|
||||
|
|
|
@ -129,6 +129,20 @@
|
|||
/>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<j-form-item
|
||||
label="所属应用"
|
||||
name="owner"
|
||||
>
|
||||
<j-select
|
||||
v-model:value="form.data.owner"
|
||||
:options="[{ label: 'Iot', value: 'iot' }]"
|
||||
allowClear
|
||||
placeholder="请选择所属应用"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</div>
|
||||
|
||||
|
@ -362,6 +376,8 @@ const form = reactive({
|
|||
const accessSupportValue = form.data.accessSupport;
|
||||
const params = {
|
||||
...form.data,
|
||||
owner: form.data?.owner ?? null,
|
||||
options: { show: true },
|
||||
accessSupport: {
|
||||
value: accessSupportValue,
|
||||
label:
|
||||
|
@ -371,7 +387,6 @@ const form = reactive({
|
|||
? '支持'
|
||||
: '间接控制',
|
||||
},
|
||||
owner: 'iot',
|
||||
};
|
||||
api(params)
|
||||
.then((resp: any) => {
|
||||
|
@ -442,7 +457,7 @@ type assetType = {
|
|||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 5px px;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
width: 4px;
|
||||
height: calc(100% - 10px);
|
||||
|
|
|
@ -119,7 +119,7 @@ const params = {
|
|||
let filterProtocolList: any[] = [];
|
||||
const getProvidersFn = async () => {
|
||||
if(!isNoCommunity){
|
||||
return
|
||||
return
|
||||
}else{
|
||||
const res: any = await getProviders();
|
||||
filterProtocolList = protocolList.filter((item) => {
|
||||
|
@ -229,7 +229,7 @@ onMounted(() => {
|
|||
))
|
||||
console.log(AllMenu);
|
||||
// 处理排序
|
||||
treeData.value = handleSortsArr(systemMenu.value);
|
||||
treeData.value = handleSortsArr(AllMenu);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -179,21 +179,17 @@ const table = reactive({
|
|||
//过滤非集成的菜单
|
||||
const item = {
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'owner',
|
||||
termType: 'eq',
|
||||
value: 'iot',
|
||||
},
|
||||
{
|
||||
column: 'owner',
|
||||
termType: 'isnull',
|
||||
value: '1',
|
||||
type: 'or',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
column: 'owner',
|
||||
termType: 'eq',
|
||||
value: 'iot',
|
||||
},
|
||||
{
|
||||
column: 'owner',
|
||||
termType: 'isnull',
|
||||
value: '1',
|
||||
type: 'or',
|
||||
},
|
||||
],
|
||||
};
|
||||
const params = {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<div
|
||||
class="child-item-left-auth"
|
||||
:class="{ disabled: !checked }"
|
||||
v-if="isNoCommunity"
|
||||
>
|
||||
<j-tooltip>
|
||||
<template #title>
|
||||
|
@ -163,6 +164,7 @@ import { Modal, Checkbox } from 'jetlinks-ui-components';
|
|||
import { usePermissionStore } from '@/store/permission';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
|
|
|
@ -191,7 +191,7 @@ const form = reactive({
|
|||
else {
|
||||
const resp: any = await checkId_api({ id });
|
||||
if (resp.result.passed) return Promise.resolve();
|
||||
else return Promise.reject(resp.result.reason);
|
||||
else return Promise.reject("标识重复");
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
v-if="refStr"
|
||||
ref="editorRef"
|
||||
language="json"
|
||||
style="height: 100%"
|
||||
style="height: 100% ; min-height: 200px;"
|
||||
theme="vs"
|
||||
v-model:modelValue="requestBody.code"
|
||||
/>
|
||||
|
|
|
@ -96,7 +96,7 @@ export default defineConfig(({ mode}) => {
|
|||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://192.168.32.163:8844', //张季本地
|
||||
// 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.5:8848', // 刘本地
|
||||
ws: 'ws://192.168.33.46:8844',
|
||||
changeOrigin: true,
|
||||
|
|
|
@ -3738,10 +3738,10 @@ jetlinks-store@^0.0.3:
|
|||
resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz"
|
||||
integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q==
|
||||
|
||||
jetlinks-ui-components@^1.0.33:
|
||||
version "1.0.33"
|
||||
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.33.tgz#49ce2b8c1e7be66272864728d5df82f834ec4490"
|
||||
integrity sha512-vYUP4MhzO6r0golmKqO8lHk8w5ldhAkgXWZfFII1Zoa7JtUwveqpSywTU23iSmCN+4muPaSLvHw713k6OdzLmg==
|
||||
jetlinks-ui-components@^1.0.34-4:
|
||||
version "1.0.34-4"
|
||||
resolved "https://registry.npmjs.org/jetlinks-ui-components/-/jetlinks-ui-components-1.0.34-4.tgz#92cfc6be685988385a489f3e924383c4831f3ed5"
|
||||
integrity sha512-td+RgaBC5lQxRuDsHkCg9UEzCcSy4XikufnabVGz5IxU+UmXu+PJUjz2wo9vDe8sPSctyk/5jQU+N6GBPlp8JA==
|
||||
dependencies:
|
||||
"@vueuse/core" "^9.12.0"
|
||||
"@vueuse/router" "^9.13.0"
|
||||
|
|
Loading…
Reference in New Issue