Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
bd1c5e5a8d
|
@ -25,7 +25,7 @@
|
|||
"event-source-polyfill": "^1.0.31",
|
||||
"global": "^4.4.0",
|
||||
"jetlinks-store": "^0.0.3",
|
||||
"jetlinks-ui-components": "^1.0.4",
|
||||
"jetlinks-ui-components": "^1.0.5",
|
||||
"js-cookie": "^3.0.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
|
|
|
@ -24,3 +24,5 @@ export const _execute = (id: string) => server.post(`/scene/${id}/_execute`);
|
|||
export const queryBuiltInParams = (data: any, params?: any) => server.post(`/scene/parse-variables`, data, params);
|
||||
|
||||
export const getParseTerm = (data: Record<string, any>) => server.post(`/scene/parse-term-column`, data)
|
||||
|
||||
export const queryAlarmList = (data: Record<string, any>) => server.post(`/alarm/config/_query/`, data)
|
|
@ -45,7 +45,6 @@ const handleCancel = () => {
|
|||
emit('change', 'simple')
|
||||
}
|
||||
const handleOk = () => {
|
||||
console.log(_value.value)
|
||||
emit('update:value', _value.value)
|
||||
emit('change', 'simple')
|
||||
}
|
||||
|
|
|
@ -185,7 +185,6 @@ const getProperty = () => {
|
|||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
console.log(options.value)
|
||||
}
|
||||
getProperty()
|
||||
</script>
|
||||
|
|
|
@ -87,7 +87,6 @@ const productStore = useProductStore()
|
|||
|
||||
const getData = async (id?: string) => {
|
||||
const metadata = productStore.current.metadata || '{}';
|
||||
console.log('metadata', metadata)
|
||||
const _properties = JSON.parse(metadata).properties || [] as PropertyMetadata[]
|
||||
const properties = {
|
||||
id: 'property',
|
||||
|
|
|
@ -96,7 +96,6 @@ const handleDelete = (index: number) => {
|
|||
_value.value.splice(index, 1)
|
||||
}
|
||||
const handleClose = () => {
|
||||
console.log(editIndex.value)
|
||||
editIndex.value = -1
|
||||
}
|
||||
const handleAdd = () => {
|
||||
|
|
|
@ -7,28 +7,36 @@
|
|||
@mousedown="emit('onMouseDown', 'UP')"
|
||||
@mouseup="emit('onMouseUp', 'UP')"
|
||||
>
|
||||
<AIcon class="direction-icon" type="CaretUpOutlined" />
|
||||
<div class="direction-icon">
|
||||
<AIcon type="CaretUpOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="direction-item right"
|
||||
@mousedown="emit('onMouseDown', 'RIGHT')"
|
||||
@mouseup="emit('onMouseUp', 'RIGHT')"
|
||||
>
|
||||
<AIcon class="direction-icon" type="CaretRightOutlined" />
|
||||
<div class="direction-icon">
|
||||
<AIcon type="CaretRightOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="direction-item left"
|
||||
@mousedown="emit('onMouseDown', 'LEFT')"
|
||||
@mouseup="emit('onMouseUp', 'LEFT')"
|
||||
>
|
||||
<AIcon class="direction-icon" type="CaretLeftOutlined" />
|
||||
<div class="direction-icon">
|
||||
<AIcon type="CaretLeftOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="direction-item down"
|
||||
@mousedown="emit('onMouseDown', 'DOWN')"
|
||||
@mouseup="emit('onMouseUp', 'DOWN')"
|
||||
>
|
||||
<AIcon class="direction-icon" type="CaretDownOutlined" />
|
||||
<div class="direction-icon">
|
||||
<AIcon type="CaretDownOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="direction-audio">
|
||||
<!-- <AIcon type="AudioOutlined" /> -->
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
<template>
|
||||
<a-dropdown-button
|
||||
type='primary'
|
||||
@click='click'
|
||||
placement='bottomLeft'
|
||||
:visible='historyVisible'
|
||||
@visibleChange='visibleChange'
|
||||
>
|
||||
搜索
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<template v-if='!showEmpty'>
|
||||
<a-menu-item v-for='item in historyList' :key='item.id'>
|
||||
<div class='history-item'>
|
||||
<span @click.stop='itemClick(item.content)'>{{ item.name }}</span>
|
||||
<a-popconfirm
|
||||
title='确认删除吗?'
|
||||
placement='top'
|
||||
@confirm.stop='deleteHistory(item.id)'
|
||||
:okButtonProps='{
|
||||
loading: deleteLoading
|
||||
}'
|
||||
>
|
||||
<span class='delete'>
|
||||
<DeleteOutlined />
|
||||
</span>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class='history-empty'>
|
||||
<a-empty />
|
||||
</div>
|
||||
</template>
|
||||
</a-menu>
|
||||
</template>
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
</a-dropdown-button>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='SearchHistory'>
|
||||
import { SearchOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
import { deleteSearchHistory, getSearchHistory } from '@/api/comm'
|
||||
import type { SearchHistoryList } from 'components/Search/types'
|
||||
|
||||
type Emit = {
|
||||
(event: 'click'): void
|
||||
(event: 'itemClick', data: string): void
|
||||
}
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const props = defineProps({
|
||||
target: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const historyList = ref<SearchHistoryList[]>([])
|
||||
const historyVisible = ref(false)
|
||||
const deleteLoading = ref(false)
|
||||
const showEmpty = ref(false)
|
||||
|
||||
const visibleChange = async (visible: boolean) => {
|
||||
historyVisible.value = visible
|
||||
if (visible) {
|
||||
const resp = await getSearchHistory(props.target)
|
||||
if (resp.success && resp.result.length) {
|
||||
historyList.value = resp.result.filter(item => item.content)
|
||||
showEmpty.value = false
|
||||
} else {
|
||||
showEmpty.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const click = () => {
|
||||
emit('click')
|
||||
}
|
||||
|
||||
const itemClick = (content: string) => {
|
||||
historyVisible.value = false
|
||||
emit('itemClick', content)
|
||||
}
|
||||
|
||||
const deleteHistory = async (id: string) => {
|
||||
deleteLoading.value = true
|
||||
const resp = await deleteSearchHistory(props.target, id)
|
||||
deleteLoading.value = false
|
||||
if (resp.success) {
|
||||
historyVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.history-empty {
|
||||
width: 200px;
|
||||
background-color: #fff;
|
||||
box-shadow: @box-shadow-base;
|
||||
border-radius: 2px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
|
||||
> span {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.delete {
|
||||
padding: 0 6px;
|
||||
flex: 0 0 28px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,349 +0,0 @@
|
|||
<template>
|
||||
<div class='JSearch-item'>
|
||||
<div class='JSearch-item--type' v-if='expand'>
|
||||
<a-select
|
||||
v-if='index !== 1 && index !== 4'
|
||||
:options='typeOptions'
|
||||
v-model:value='termsModel.type'
|
||||
style='width: 100%;'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<span v-else>
|
||||
{{
|
||||
index === 1 ? '第一组' : '第二组'
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<a-select
|
||||
class='JSearch-item--column'
|
||||
:options='columnOptions'
|
||||
v-model:value='termsModel.column'
|
||||
@change='columnChange'
|
||||
/>
|
||||
<a-select
|
||||
class='JSearch-item--termType'
|
||||
:options='termTypeOptions.option'
|
||||
v-model:value='termsModel.termType'
|
||||
@change='termTypeChange'
|
||||
/>
|
||||
<div class='JSearch-item--value'>
|
||||
<a-input
|
||||
v-if='component === componentType.input'
|
||||
v-model:value='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-select
|
||||
v-else-if='component === componentType.select'
|
||||
showSearch
|
||||
:loading='optionLoading'
|
||||
v-model:value='termsModel.value'
|
||||
:options='options'
|
||||
style='width: 100%'
|
||||
:filterOption='(v, option) => filterTreeSelectNode(v, option, "label")'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-input-number
|
||||
v-else-if='component === componentType.inputNumber'
|
||||
v-model:value='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-input-password
|
||||
v-else-if='component === componentType.password'
|
||||
v-model:value='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if='component === componentType.switch'
|
||||
v-model:checked='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-radio-group
|
||||
v-else-if='component === componentType.radio'
|
||||
v-model:value='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-checkbox-group
|
||||
v-else-if='component === componentType.checkbox'
|
||||
v-model:value='termsModel.value'
|
||||
:options='options'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-time-picker
|
||||
v-else-if='component === componentType.time'
|
||||
valueFormat='HH:mm:ss'
|
||||
v-model:value='termsModel.value'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-date-picker
|
||||
v-else-if='component === componentType.date'
|
||||
showTime
|
||||
v-model:value='termsModel.value'
|
||||
valueFormat='YYYY-MM-DD HH:mm:ss'
|
||||
style='width: 100%'
|
||||
@change='valueChange'
|
||||
/>
|
||||
<a-tree-select
|
||||
v-else-if='component === componentType.treeSelect'
|
||||
showSearch
|
||||
v-model:value='termsModel.value'
|
||||
:tree-data='options'
|
||||
style='width: 100%'
|
||||
:fieldNames='{ label: "name", value: "id" }'
|
||||
@change='valueChange'
|
||||
:filterTreeNode='(v, option) => filterSelectNode(v, option)'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='SearchItem'>
|
||||
import { componentType } from 'components/Form'
|
||||
import { typeOptions, termType } from './util'
|
||||
import { PropType } from 'vue'
|
||||
import type { SearchItemData, SearchProps, Terms } from './types'
|
||||
import { cloneDeep, get, isArray, isFunction } from 'lodash-es'
|
||||
import { filterTreeSelectNode, filterSelectNode } from '@/utils/comm'
|
||||
import { useUrlSearchParams } from '@vueuse/core'
|
||||
|
||||
type ItemType = SearchProps['type']
|
||||
|
||||
interface Emit {
|
||||
(e: 'change', data: SearchItemData): void
|
||||
}
|
||||
type UrlParam = {
|
||||
q: string | null
|
||||
target: string | null
|
||||
}
|
||||
|
||||
const urlParams = useUrlSearchParams<UrlParam>('hash')
|
||||
|
||||
const props = defineProps({
|
||||
columns: {
|
||||
type: Array as PropType<SearchProps[]>,
|
||||
default: () => [],
|
||||
required: true
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
expand: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
termsItem: {
|
||||
type: Object as PropType<Terms>,
|
||||
default: {}
|
||||
},
|
||||
reset: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const termsModel = reactive<SearchItemData>({
|
||||
type: 'or',
|
||||
value: '',
|
||||
termType: 'like',
|
||||
column: ''
|
||||
})
|
||||
|
||||
const component = ref(componentType.input)
|
||||
|
||||
const options = ref<any[]>([])
|
||||
|
||||
const columnOptions = ref<({ label: string, value: string})[]>([])
|
||||
const columnOptionMap = new Map()
|
||||
|
||||
const termTypeOptions = reactive({option: termType})
|
||||
|
||||
const optionLoading = ref(false)
|
||||
|
||||
/**
|
||||
* 根据类型切换默termType值
|
||||
* @param type
|
||||
*/
|
||||
const getTermType = (type?: ItemType) => {
|
||||
termTypeOptions.option = termType
|
||||
switch (type) {
|
||||
case 'select':
|
||||
case 'treeSelect':
|
||||
case 'number':
|
||||
return 'eq'
|
||||
case 'date':
|
||||
case 'time':
|
||||
// 时间只有大于或小于两个值
|
||||
termTypeOptions.option = termType.filter(item => ['gt','lt'].includes(item.value))
|
||||
return 'gt'
|
||||
default:
|
||||
return 'like'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型返回组件
|
||||
* @param type
|
||||
*/
|
||||
const getComponent = (type?: ItemType) => {
|
||||
switch (type) {
|
||||
case 'select':
|
||||
component.value = componentType.select
|
||||
break;
|
||||
case 'treeSelect':
|
||||
component.value = componentType.treeSelect
|
||||
break;
|
||||
case 'date':
|
||||
component.value = componentType.date
|
||||
break;
|
||||
case 'time':
|
||||
component.value = componentType.time
|
||||
break;
|
||||
case 'number':
|
||||
component.value = componentType.inputNumber
|
||||
break;
|
||||
default:
|
||||
component.value = componentType.input
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const handleItemOptions = (option?: any[] | Function) => {
|
||||
options.value = []
|
||||
if (isArray(option)) {
|
||||
options.value = option
|
||||
} else if (isFunction(option)) {
|
||||
optionLoading.value = true
|
||||
option().then((res: any[]) => {
|
||||
optionLoading.value = false
|
||||
options.value = res
|
||||
}).catch((_: any) => {
|
||||
optionLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const columnChange = (value: string, isChange: boolean) => {
|
||||
const item = columnOptionMap.get(value)
|
||||
optionLoading.value = false
|
||||
// 设置value为undefined
|
||||
termsModel.column = value
|
||||
termsModel.termType = item.defaultTermType || getTermType(item.type)
|
||||
|
||||
getComponent(item.type) // 处理Item的组件类型
|
||||
|
||||
// 处理options 以及 request
|
||||
if ('options' in item) {
|
||||
handleItemOptions(item.options)
|
||||
}
|
||||
|
||||
termsModel.value = undefined
|
||||
|
||||
if (isChange) {
|
||||
valueChange()
|
||||
}
|
||||
}
|
||||
|
||||
const handleItem = () => {
|
||||
columnOptionMap.clear()
|
||||
columnOptions.value = []
|
||||
if (!props.columns.length) return
|
||||
|
||||
columnOptions.value = props.columns.map(item => { // 对columns进行Map处理以及值处理
|
||||
columnOptionMap.set(item.column, item)
|
||||
return {
|
||||
label: item.title,
|
||||
value: item.column
|
||||
}
|
||||
})
|
||||
|
||||
// 获取第一个值
|
||||
const sortColumn = cloneDeep(props.columns)
|
||||
sortColumn?.sort((a, b) => a.sortIndex! - b.sortIndex!)
|
||||
|
||||
const _index = props.index > sortColumn.length ? sortColumn.length - 1 : props.index
|
||||
const _itemColumn = sortColumn[_index - 1]
|
||||
|
||||
columnChange(_itemColumn.column, false)
|
||||
}
|
||||
|
||||
const termTypeChange = () => {
|
||||
valueChange()
|
||||
}
|
||||
|
||||
const valueChange = () => {
|
||||
|
||||
emit('change', {
|
||||
type: termsModel.type,
|
||||
value: termsModel.value,
|
||||
termType: termsModel.termType,
|
||||
column: termsModel.column,
|
||||
})
|
||||
}
|
||||
|
||||
const handleQuery = (_params: UrlParam) => {
|
||||
if (_params.q) {
|
||||
const path = props.index < 4 ? [0, 'terms', props.index - 1] : [1, 'terms', props.index - 4]
|
||||
const itemData: SearchItemData = get(props.termsItem.terms, path)
|
||||
if (itemData) {
|
||||
termsModel.type = itemData.type
|
||||
termsModel.column = itemData.column
|
||||
termsModel.termType = itemData.termType
|
||||
termsModel.value = itemData.value
|
||||
const item = columnOptionMap.get(itemData.column)
|
||||
getComponent(item.type) // 处理Item的组件类型
|
||||
|
||||
// 处理options 以及 request
|
||||
if ('options' in item) {
|
||||
handleItemOptions(item.options)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleItem()
|
||||
|
||||
nextTick(() => {
|
||||
handleQuery(urlParams)
|
||||
})
|
||||
|
||||
watch(() => props.reset, () => {
|
||||
handleItem()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.JSearch-item {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
.JSearch-item--type {
|
||||
min-width: 80px;
|
||||
> span {
|
||||
line-height: 34px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.JSearch-item--column {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.JSearch-item--termType {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.JSearch-item--value {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,100 +0,0 @@
|
|||
<template>
|
||||
<a-popover
|
||||
title='搜索名称'
|
||||
trigger='click'
|
||||
v-model:visible='visible'
|
||||
@visibleChange='visibleChange'
|
||||
>
|
||||
<template #content>
|
||||
<div style='width: 240px'>
|
||||
<a-form ref='formRef' :model='modelRef'>
|
||||
<a-form-item
|
||||
name='name'
|
||||
:rules='[
|
||||
{ required: true, message: "请输入名称"}
|
||||
]'
|
||||
>
|
||||
<a-textarea
|
||||
v-model:value='modelRef.name'
|
||||
:rows='3'
|
||||
:maxlength='200'
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button
|
||||
:loading='saveHistoryLoading'
|
||||
type='primary'
|
||||
class='save-btn'
|
||||
@click='saveHistory'
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<a-button>
|
||||
<template #icon>
|
||||
<SaveOutlined />
|
||||
</template>
|
||||
保存
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='SaveHistory'>
|
||||
import type { Terms } from './types'
|
||||
import { PropType } from 'vue'
|
||||
import { saveSearchHistory } from '@/api/comm'
|
||||
import { SaveOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
terms: {
|
||||
type: Object as PropType<Terms>,
|
||||
default: () => ({})
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const searchName = ref('')
|
||||
|
||||
const saveHistoryLoading = ref(false)
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const formRef = ref()
|
||||
|
||||
const modelRef = reactive({
|
||||
name: undefined
|
||||
})
|
||||
|
||||
/**
|
||||
* 保存当前查询条件
|
||||
*/
|
||||
const saveHistory = async () => {
|
||||
// 获取当前查询条件并转化为字符串
|
||||
const formData = await formRef.value.validate()
|
||||
if (formData) {
|
||||
formData.content = JSON.stringify(props.terms)
|
||||
saveHistoryLoading.value = true
|
||||
const resp = await saveSearchHistory(formData, props.target)
|
||||
saveHistoryLoading.value = false
|
||||
if (resp.success) {
|
||||
visible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const visibleChange = (e: boolean) => {
|
||||
visible.value = e
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.save-btn {
|
||||
width: 100%
|
||||
}
|
||||
</style>
|
|
@ -1,83 +1,21 @@
|
|||
<template>
|
||||
<div :class="['JSearch-warp', props.class]" ref='searchRef'>
|
||||
<!-- 高级模式 -->
|
||||
<div v-if='props.type === "advanced"' :class='["JSearch-content senior", expand ? "senior-expand" : "", screenSize ? "big" : "small"]'>
|
||||
<div :class='["JSearch-items", expand ? "items-expand" : "", layout]'>
|
||||
<div class='left'>
|
||||
<SearchItem :expand='expand' :index='1' :columns='searchItems' @change='(v) => itemValueChange(v, 1)' :termsItem='terms' :reset='resetNumber'/>
|
||||
<SearchItem v-if='expand' :expand='expand' :index='2' :columns='searchItems' @change='(v) => itemValueChange(v, 2)' :termsItem='terms' :reset='resetNumber'/>
|
||||
<SearchItem v-if='expand' :expand='expand' :index='3' :columns='searchItems' @change='(v) => itemValueChange(v, 3)' :termsItem='terms' :reset='resetNumber'/>
|
||||
</div>
|
||||
<div class='center' v-if='expand'>
|
||||
<a-select
|
||||
v-model:value='termType'
|
||||
class='center-select'
|
||||
:options='typeOptions'
|
||||
/>
|
||||
</div>
|
||||
<div class='right' v-if='expand'>
|
||||
<SearchItem :expand='expand' :index='4' :columns='searchItems' @change='(v) => itemValueChange(v, 4)' :termsItem='terms' :reset='resetNumber'/>
|
||||
<SearchItem :expand='expand' :index='5' :columns='searchItems' @change='(v) => itemValueChange(v, 5)' :termsItem='terms' :reset='resetNumber'/>
|
||||
<SearchItem :expand='expand' :index='6' :columns='searchItems' @change='(v) => itemValueChange(v, 6)' :termsItem='terms' :reset='resetNumber'/>
|
||||
</div>
|
||||
</div>
|
||||
<div :class='["JSearch-footer", expand ? "expand" : ""]'>
|
||||
<div class='JSearch-footer--btns'>
|
||||
<History :target='target' @click='searchSubmit' @itemClick='historyItemClick' />
|
||||
<SaveHistory :terms='terms' :target='target'/>
|
||||
<a-button @click='reset'>
|
||||
<template #icon><RedoOutlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</div>
|
||||
<a-button type='link' class='more-btn' @click='expandChange'>
|
||||
更多筛选
|
||||
<DownOutlined :class='["more-icon",expand ? "more-up" : "more-down"]' />
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 简单模式 -->
|
||||
<div v-else class='JSearch-content simple big'>
|
||||
<div class='JSearch-items'>
|
||||
<div class='left'>
|
||||
<SearchItem :expand='false' :index='1' :columns='searchItems' @change='(v) => itemValueChange(v, 1)' :termsItem='terms' :reset='resetNumber'/>
|
||||
</div>
|
||||
</div>
|
||||
<div class='JSearch-footer'>
|
||||
<div class='JSearch-footer--btns'>
|
||||
<a-button type="primary" @click='searchSubmit'>
|
||||
<template #icon><SearchOutlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click='reset'>
|
||||
<template #icon><RedoOutlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<j-advanced-search
|
||||
:target='target'
|
||||
:type='type'
|
||||
:request='saveSearchHistory'
|
||||
:historyRequest='getSearchHistory'
|
||||
:columns='columns'
|
||||
@search='searchSubmit'
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Search'>
|
||||
import SearchItem from './Item.vue'
|
||||
import { typeOptions } from './util'
|
||||
import { useElementSize, useUrlSearchParams } from '@vueuse/core'
|
||||
import { cloneDeep, isFunction, isString, set } from 'lodash-es'
|
||||
import { SearchOutlined, DownOutlined, RedoOutlined } from '@ant-design/icons-vue';
|
||||
<script setup lang='ts' name='ProSearch'>
|
||||
import { PropType } from 'vue'
|
||||
import { JColumnsProps } from 'components/Table/types'
|
||||
import SaveHistory from './SaveHistory.vue'
|
||||
import History from './History.vue'
|
||||
import type { SearchItemData, SearchProps, Terms } from './types'
|
||||
|
||||
type UrlParam = {
|
||||
q: string | null
|
||||
target: string | null
|
||||
}
|
||||
import { saveSearchHistory, getSearchHistory } from '@/api/comm'
|
||||
|
||||
interface Emit {
|
||||
(e: 'search', data: Terms): void
|
||||
(e: 'search', data: any): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -98,299 +36,20 @@ const props = defineProps({
|
|||
class: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// defaultTerms: {
|
||||
// type: Object,
|
||||
// default: () => ({})
|
||||
// }
|
||||
}
|
||||
})
|
||||
|
||||
const searchRef = ref(null)
|
||||
const { width } = useElementSize(searchRef)
|
||||
|
||||
const urlParams = useUrlSearchParams<UrlParam>('hash')
|
||||
|
||||
// 是否展开更多筛选
|
||||
const expand = ref(false)
|
||||
|
||||
// 第一组,第二组的关系
|
||||
const termType = ref('and')
|
||||
// 搜索历史记录
|
||||
const historyList = ref([])
|
||||
|
||||
// 组件方向
|
||||
const layout = ref('horizontal')
|
||||
// 当前组件宽度 true 大于1000
|
||||
const screenSize = ref(true)
|
||||
const resetNumber = ref(1)
|
||||
|
||||
const searchItems = ref<SearchProps[]>([])
|
||||
|
||||
// 当前查询条件
|
||||
const terms = reactive<Terms>({ terms: [] })
|
||||
|
||||
const columnOptionMap = new Map()
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const expandChange = () => {
|
||||
expand.value = !expand.value
|
||||
}
|
||||
|
||||
const searchParams = reactive({
|
||||
data: {}
|
||||
})
|
||||
|
||||
const handleItems = () => {
|
||||
searchItems.value = []
|
||||
columnOptionMap.clear()
|
||||
const cloneColumns = cloneDeep(props.columns)
|
||||
cloneColumns!.forEach((item, index) => {
|
||||
if (item.search && Object.keys(item.search).length) {
|
||||
columnOptionMap.set(item.dataIndex, item.search)
|
||||
searchItems.value.push({
|
||||
...item.search,
|
||||
sortIndex: item.search.first ? 0 : index + 1,
|
||||
title: item.title,
|
||||
column: item.dataIndex,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const itemValueChange = (value: SearchItemData, index: number) => {
|
||||
if (index < 4) { // 第一组数据
|
||||
set(terms.terms, [0, 'terms', index - 1], value)
|
||||
} else { // 第二组数据
|
||||
set(terms.terms, [1, 'terms', index - 4], value)
|
||||
}
|
||||
}
|
||||
|
||||
const addUrlParams = () => {
|
||||
urlParams.q = JSON.stringify(terms)
|
||||
urlParams.target = props.target
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理termType为like,nlike的值
|
||||
* @param v
|
||||
*/
|
||||
const handleLikeValue = (v: string) => {
|
||||
if (isString(v)) {
|
||||
return v.split('').reduce((pre: string, next: string) => {
|
||||
let _next = next
|
||||
if (next === '\\') {
|
||||
_next = '\\\\'
|
||||
} else if (next === '%') {
|
||||
_next = '\\%'
|
||||
}
|
||||
return pre + _next
|
||||
}, '')
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理为外部使用
|
||||
*/
|
||||
const handleParamsFormat = () => {
|
||||
// 过滤掉terms中value无效的item
|
||||
const cloneParams = cloneDeep(terms)
|
||||
return {
|
||||
terms: cloneParams.terms.map(item => {
|
||||
if (item.terms) {
|
||||
item.terms = item.terms.filter(iItem => iItem && iItem.value)
|
||||
.map(iItem => {
|
||||
// 处理handleValue和rename
|
||||
const _item = columnOptionMap.get(iItem.column)
|
||||
if (_item.rename) {
|
||||
iItem.column = _item.rename
|
||||
}
|
||||
|
||||
if (_item.handleValue && isFunction(_item.handleValue)) {
|
||||
iItem.value = _item.handleValue(iItem.value)
|
||||
}
|
||||
|
||||
if (['like','nlike'].includes(iItem.termType) && !!iItem.value) {
|
||||
iItem.value = `%${handleLikeValue(iItem.value)}%`
|
||||
}
|
||||
return iItem
|
||||
})
|
||||
}
|
||||
return item
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交
|
||||
*/
|
||||
const searchSubmit = () => {
|
||||
emit('search', handleParamsFormat())
|
||||
console.log('searchSubmit')
|
||||
if (props.type === 'advanced') {
|
||||
addUrlParams()
|
||||
}
|
||||
const searchSubmit = (data: any) => {
|
||||
emit('search', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询
|
||||
*/
|
||||
const reset = () => {
|
||||
terms.terms = []
|
||||
expand.value = false
|
||||
if (props.type === 'advanced') {
|
||||
urlParams.q = null
|
||||
urlParams.target = null
|
||||
}
|
||||
resetNumber.value += 1
|
||||
emit('search', { terms: []})
|
||||
}
|
||||
|
||||
watch(width, (value) => {
|
||||
if (value < 1000) {
|
||||
layout.value = 'vertical'
|
||||
screenSize.value = false
|
||||
} else {
|
||||
layout.value = 'horizontal'
|
||||
screenSize.value = true
|
||||
}
|
||||
})
|
||||
|
||||
const historyItemClick = (content: string) => {
|
||||
try {
|
||||
terms.terms = JSON.parse(content)?.terms || []
|
||||
if (terms.terms.length === 2) {
|
||||
expand.value = true
|
||||
}
|
||||
addUrlParams()
|
||||
} catch (e) {
|
||||
console.warn(`Search组件中handleUrlParams处理JSON时异常:【${e}】`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理URL中的查询参数
|
||||
* @param _params
|
||||
*/
|
||||
const handleUrlParams = (_params: UrlParam) => {
|
||||
// URL中的target和props的一致,则还原查询参数
|
||||
if (_params.target === props.target && _params.q) {
|
||||
try {
|
||||
terms.terms = JSON.parse(_params.q)?.terms || []
|
||||
if (terms.terms.length === 2) {
|
||||
expand.value = true
|
||||
}
|
||||
emit('search', handleParamsFormat())
|
||||
} catch (e) {
|
||||
console.warn(`Search组件中handleUrlParams处理JSON时异常:【${e}】`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
handleUrlParams(urlParams)
|
||||
})
|
||||
|
||||
handleItems()
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.JSearch-warp {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.JSearch-content {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.JSearch-items,& .JSearch-footer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.JSearch-items {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
.left, & .right {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
width: 0;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
.left,& .right,& .center {
|
||||
width: 100%;
|
||||
}
|
||||
.center {
|
||||
flex-direction: row;
|
||||
}
|
||||
.center-select {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.JSearch-footer {
|
||||
display: flex;
|
||||
gap: 64px;
|
||||
position: relative;
|
||||
|
||||
&.expand {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
|
||||
.more-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.JSearch-footer--btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&.senior-expand {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.more-up {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
|
||||
&.big {
|
||||
gap: 64px;
|
||||
}
|
||||
|
||||
&.small {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.simple {
|
||||
.JSearch-items {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.JSearch-footer {
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -62,7 +62,7 @@
|
|||
:showUploadList="false"
|
||||
@change="handleFileChange"
|
||||
>
|
||||
<AIcon type="CloudUploadOutlined" />
|
||||
<AIcon type="UploadOutlined" />
|
||||
</j-upload>
|
||||
</template>
|
||||
</j-input>
|
||||
|
|
|
@ -5,7 +5,7 @@ import JTable from './Table/index'
|
|||
import TitleComponent from "./TitleComponent/index.vue";
|
||||
import Form from './Form';
|
||||
import CardBox from './CardBox/index.vue';
|
||||
// import Search from './Search'
|
||||
import Search from './Search'
|
||||
import NormalUpload from './NormalUpload/index.vue'
|
||||
import FileFormat from './FileFormat/index.vue'
|
||||
import JProUpload from './JUpload/index.vue'
|
||||
|
@ -25,7 +25,7 @@ export default {
|
|||
.component('TitleComponent', TitleComponent)
|
||||
.component('Form', Form)
|
||||
.component('CardBox', CardBox)
|
||||
// .component('Search', Search)
|
||||
.component('ProSearch', Search)
|
||||
.component('NormalUpload', NormalUpload)
|
||||
.component('FileFormat', FileFormat)
|
||||
.component('JProUpload', JProUpload)
|
||||
|
|
|
@ -8,7 +8,7 @@ export const AccountMenu = {
|
|||
meta: {
|
||||
title: '个人中心',
|
||||
icon: '',
|
||||
hideInMenu: false
|
||||
hideInMenu: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
|
|
@ -37,6 +37,10 @@ type MenuStateType = {
|
|||
}
|
||||
}
|
||||
siderMenus: MenuItem[]
|
||||
params: {
|
||||
key: string
|
||||
params: Record<string, any>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -44,6 +48,10 @@ export const useMenuStore = defineStore({
|
|||
id: 'menu',
|
||||
state: (): MenuStateType => ({
|
||||
menus: {},
|
||||
params: {
|
||||
key: '',
|
||||
params: {}
|
||||
},
|
||||
siderMenus: []
|
||||
}),
|
||||
getters: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="northbound-aliyun"
|
||||
@search="handleSearch"
|
||||
|
@ -50,13 +50,17 @@
|
|||
<div class="card-item-content-text">
|
||||
网桥产品
|
||||
</div>
|
||||
<div>{{ slotProps?.bridgeProductName }}</div>
|
||||
<Ellipsis>
|
||||
<div>{{ slotProps?.bridgeProductName }}</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
<label>说明</label>
|
||||
</div>
|
||||
<div>{{ slotProps?.description }}</div>
|
||||
<Ellipsis>
|
||||
<div>{{ slotProps?.description }}</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="northbound-dueros"
|
||||
@search="handleSearch"
|
||||
|
@ -48,13 +48,17 @@
|
|||
<j-row>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">产品</div>
|
||||
<div>{{ slotProps?.productName }}</div>
|
||||
<Ellipsis>
|
||||
<div>{{ slotProps?.productName }}</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>{{ slotProps?.applianceType?.text }}</div>
|
||||
<Ellipsis>
|
||||
<div>{{ slotProps?.applianceType?.text }}</div>
|
||||
</Ellipsis>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 新增编辑弹窗 -->
|
||||
<template>
|
||||
<a-modal
|
||||
<j-modal
|
||||
:title="props.title"
|
||||
:maskClosable="false"
|
||||
destroy-on-close
|
||||
|
@ -11,38 +11,38 @@
|
|||
cancelText="取消"
|
||||
v-bind="layout"
|
||||
>
|
||||
<a-form
|
||||
<j-form
|
||||
layout="vertical"
|
||||
ref="formRef"
|
||||
:rules="rules"
|
||||
:model="formModel"
|
||||
>
|
||||
<a-form-item label="名称" name="name">
|
||||
<a-input
|
||||
<j-form-item label="名称" name="name">
|
||||
<j-input
|
||||
v-model:value="formModel.name"
|
||||
:maxlength="64"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" name="sortIndex">
|
||||
<a-input-number
|
||||
</j-form-item>
|
||||
<j-form-item label="排序" name="sortIndex">
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
id="inputNumber"
|
||||
v-model:value="formModel.sortIndex"
|
||||
:min="1"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="说明">
|
||||
<a-textarea
|
||||
</j-form-item>
|
||||
<j-form-item label="说明">
|
||||
<j-textarea
|
||||
v-model:value="formModel.description"
|
||||
show-count
|
||||
:maxlength="200"
|
||||
placeholder="请输入说明"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-modal>
|
||||
</template>
|
||||
<script setup lang="ts" name="modifyModal">
|
||||
import { PropType } from 'vue';
|
||||
|
@ -111,20 +111,20 @@ const submitData = async () => {
|
|||
if (props.isChild === 1) {
|
||||
addParams.value = {
|
||||
...formModel.value,
|
||||
sortIndex:
|
||||
childArr.value[childArr.value.length - 1].sortIndex + 1,
|
||||
// sortIndex:
|
||||
// childArr.value[childArr.value.length - 1].sortIndex + 1,
|
||||
parentId: addObj.value.id,
|
||||
};
|
||||
} else if (props.isChild === 2) {
|
||||
addParams.value = {
|
||||
parentId: addObj.value.id,
|
||||
...formModel.value,
|
||||
sortIndex: 1,
|
||||
// sortIndex: 1,
|
||||
};
|
||||
} else if (props.isChild === 3) {
|
||||
addParams.value = {
|
||||
...formModel.value,
|
||||
sortIndex: arr.value[arr.value.length - 1].sortIndex + 1,
|
||||
// sortIndex: arr.value[arr.value.length - 1].sortIndex + 1,
|
||||
};
|
||||
}
|
||||
const res = await saveTree(addParams.value);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!--产品分类 -->
|
||||
<template>
|
||||
<a-card class="product-category">
|
||||
<Search
|
||||
<page-container>
|
||||
<pro-search
|
||||
:columns="query.columns"
|
||||
target="category"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<JTable
|
||||
<JProTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:dataSource="dataSource"
|
||||
|
@ -25,46 +25,38 @@
|
|||
:loading="tableLoading"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-button type="primary" @click="add"
|
||||
><plus-outlined />新增</a-button
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
@click="add"
|
||||
hasPermission="device/Category:add"
|
||||
>
|
||||
<template #icon><AIcon type="PlusOutlined" /></template>
|
||||
新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="i.popConfirm"
|
||||
v-bind="i.popConfirm"
|
||||
<PermissionButton
|
||||
:disabled="i.disabled"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
:popConfirm="i.popConfirm"
|
||||
:hasPermission="'device/Category:' + i.key"
|
||||
:tooltip="{
|
||||
...i.tooltip,
|
||||
}"
|
||||
@click="i.onClick"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
style="padding: 0px"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
<template #icon><AIcon :type="i.icon" /></template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</j-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</JProTable>
|
||||
<!-- 新增和编辑弹窗 -->
|
||||
<ModifyModal
|
||||
ref="modifyRef"
|
||||
|
@ -74,7 +66,7 @@
|
|||
:isChild="isChild"
|
||||
@refresh="refresh"
|
||||
/>
|
||||
</a-card>
|
||||
</page-container>
|
||||
</template>
|
||||
<script lang="ts" name="Category" setup>
|
||||
import { queryTree, deleteTree } from '@/api/device/category';
|
||||
|
@ -146,6 +138,7 @@ const getTableData = async () => {
|
|||
if (res.status === 200) {
|
||||
dataSource.value = res.result;
|
||||
}
|
||||
tableLoading.value = false;
|
||||
};
|
||||
getTableData();
|
||||
/**
|
||||
|
@ -168,7 +161,7 @@ const getActions = (
|
|||
if (!data) return [];
|
||||
const actions = [
|
||||
{
|
||||
key: 'edit',
|
||||
key: 'update',
|
||||
text: '编辑',
|
||||
tooltip: {
|
||||
title: '编辑',
|
||||
|
@ -238,8 +231,8 @@ const table = reactive({
|
|||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'describe',
|
||||
key: 'describe',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
|
|
@ -336,7 +336,7 @@ const setDevMesChartOption = (
|
|||
grid: {
|
||||
top: '2%',
|
||||
bottom: '5%',
|
||||
left: maxY > 100000 ? '90px' : '50px',
|
||||
left: maxY > 100000 ? '90px' : '60px',
|
||||
right: '50px',
|
||||
},
|
||||
series: [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<j-card>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="device-instance-log"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<j-advanced-search class="search" type="simple" :columns="columns" target="device-instance-running-events" @search="handleSearch" />
|
||||
<pro-search class="search" type="simple" :columns="columns" target="device-instance-running-events" @search="handleSearch" />
|
||||
<JProTable
|
||||
ref="eventsRef"
|
||||
:columns="columns"
|
||||
|
|
|
@ -191,15 +191,17 @@ watch(
|
|||
() => route.params.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
instanceStore.tabActiveKey = 'Info';
|
||||
instanceStore.refresh(newId as string);
|
||||
|
||||
instanceStore.refresh(String(newId));
|
||||
getStatus(String(newId));
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
instanceStore.tabActiveKey = history.state?.params?.tab || 'Info'
|
||||
})
|
||||
|
||||
const onBack = () => {
|
||||
menuStory.jumpPage('device/Instance');
|
||||
};
|
||||
|
@ -282,7 +284,7 @@ watchEffect(() => {
|
|||
tab: 'OPC UA',
|
||||
});
|
||||
}
|
||||
if (instanceStore.current.deviceType?.value === 'gateway') {
|
||||
if (instanceStore.current.deviceType?.value === 'gateway' && !keys.includes('ChildDevice')) {
|
||||
// 产品类型为网关的情况下才显示此模块
|
||||
list.value.push({
|
||||
key: 'ChildDevice',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="device-instance"
|
||||
@search="handleSearch"
|
||||
|
@ -289,6 +289,7 @@ import { queryTree } from '@/api/device/category';
|
|||
import { useMenuStore } from '@/store/menu';
|
||||
import type { ActionsType } from './typings';
|
||||
import dayjs from 'dayjs';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
const instanceRef = ref<Record<string, any>>({});
|
||||
const params = ref<Record<string, any>>({});
|
||||
|
@ -315,7 +316,7 @@ const columns = [
|
|||
key: 'id',
|
||||
search: {
|
||||
type: 'string',
|
||||
defaultTermType: 'eq'
|
||||
defaultTermType: 'eq',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -324,7 +325,7 @@ const columns = [
|
|||
key: 'name',
|
||||
search: {
|
||||
type: 'string',
|
||||
first: true
|
||||
first: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -524,6 +525,12 @@ const paramsFormat = (
|
|||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if(history.state?.params?.type === 'add'){
|
||||
handleAdd()
|
||||
}
|
||||
})
|
||||
|
||||
const handleParams = (config: Record<string, any>) => {
|
||||
const _terms: Record<string, any> = {};
|
||||
paramsFormat(config, _terms);
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
<a-descriptions-item label="接入方式">
|
||||
<a-button type="link" @click="changeTables">{{
|
||||
productStore.current.transportProtocol
|
||||
? productStore.current.transportProtocol
|
||||
productStore.current.accessName
|
||||
? productStore.current.accessName
|
||||
: '配置接入方式'
|
||||
}}</a-button>
|
||||
</a-descriptions-item>
|
||||
|
|
|
@ -1,24 +1,30 @@
|
|||
<!-- 设备接入 -->
|
||||
<template>
|
||||
<a-card style="min-height: 100%">
|
||||
<j-card style="min-height: 100%">
|
||||
<div v-if="productStore.current.accessId === undefined || null">
|
||||
<a-empty :image="simpleImage">
|
||||
<j-empty :image="simpleImage">
|
||||
<template #description>
|
||||
<span v-if="permissionStore.hasPermission('device/Product:update')">
|
||||
请先<a-button type="link" @click="showModal"
|
||||
>选择</a-button
|
||||
<span
|
||||
v-if="
|
||||
permissionStore.hasPermission(
|
||||
'device/Product:update',
|
||||
)
|
||||
"
|
||||
>
|
||||
请先<j-button type="link" @click="showModal"
|
||||
>选择</j-button
|
||||
>设备接入网关,用以提供设备接入能力
|
||||
</span>
|
||||
<span v-else>暂无权限,请联系管理员</span>
|
||||
</template>
|
||||
</a-empty>
|
||||
</j-empty>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<j-row :gutter="24">
|
||||
<j-col :span="12">
|
||||
<Title data="接入方式">
|
||||
<template #extra>
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
:title="
|
||||
productStore.current?.count &&
|
||||
productStore.current?.count > 0
|
||||
|
@ -26,7 +32,7 @@
|
|||
: ''
|
||||
"
|
||||
>
|
||||
<a-button
|
||||
<j-button
|
||||
style="margin: 0 0 0 20px"
|
||||
size="small"
|
||||
:disabled="
|
||||
|
@ -35,9 +41,9 @@
|
|||
"
|
||||
type="primary"
|
||||
@click="showDevice"
|
||||
>更换</a-button
|
||||
>更换</j-button
|
||||
>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</Title>
|
||||
<div>
|
||||
|
@ -71,13 +77,13 @@
|
|||
v-for="item in access?.channelInfo?.addresses"
|
||||
:key="item.address"
|
||||
>
|
||||
<a-badge
|
||||
<j-badge
|
||||
:color="
|
||||
item.health === -1 ? 'red' : 'green'
|
||||
"
|
||||
:text="item.address"
|
||||
>
|
||||
</a-badge>
|
||||
</j-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>{{ '暂无连接信息' }}</div>
|
||||
|
@ -88,95 +94,100 @@
|
|||
class="config"
|
||||
>
|
||||
<template #extra>
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
title="此配置来自于产品接入方式所选择的协议"
|
||||
>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</Title>
|
||||
<a-form
|
||||
<j-form
|
||||
ref="formRef"
|
||||
:model="formData.data"
|
||||
layout="vertical"
|
||||
>
|
||||
<div v-for="item in metadata.properties" :key="item">
|
||||
<a-form-item
|
||||
:label="item.name"
|
||||
:rules="[
|
||||
{
|
||||
required:
|
||||
!!item?.type?.expands?.required,
|
||||
message: `${
|
||||
item.type.type === 'enum'
|
||||
? '请选择'
|
||||
: '请输入'
|
||||
}${item.name}`,
|
||||
},
|
||||
]"
|
||||
<j-form-item
|
||||
:name="item.property"
|
||||
v-for="item in metadata.properties"
|
||||
:key="item"
|
||||
:label="item.name"
|
||||
:rules="[
|
||||
{
|
||||
required: !!item?.type?.expands?.required,
|
||||
message: `${
|
||||
item.type.type === 'enum'
|
||||
? '请选择'
|
||||
: '请输入'
|
||||
}${item.name}`,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<j-input
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'string'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input>
|
||||
<j-input-password
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'password'"
|
||||
v-model:value="formData.data[item.property]"
|
||||
></j-input-password>
|
||||
<j-select
|
||||
placeholder="请选择"
|
||||
v-if="item.type.type === 'enum'"
|
||||
v-model:value="formData.data[item.name]"
|
||||
>
|
||||
<a-input
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'string'"
|
||||
v-model:value="formData.data[item.name]"
|
||||
></a-input>
|
||||
<a-input-password
|
||||
placeholder="请输入"
|
||||
v-if="item.type.type === 'password'"
|
||||
v-model:value="formData.data[item.name]"
|
||||
></a-input-password>
|
||||
<a-select
|
||||
placeholder="请选择"
|
||||
v-if="item.type.type === 'enum'"
|
||||
v-model:value="formData.data[item.name]"
|
||||
<j-select-option
|
||||
v-for="el in item?.type?.type === 'enum' &&
|
||||
item?.type?.elements
|
||||
? item?.type?.elements
|
||||
: []"
|
||||
:key="el"
|
||||
:value="el.value"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="el in item?.type?.type ===
|
||||
'enum' && item?.type?.elements
|
||||
? item?.type?.elements
|
||||
: []"
|
||||
:key="el"
|
||||
:value="el.value"
|
||||
>
|
||||
{{ el.text }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</a-form>
|
||||
{{ el.text }}
|
||||
</j-select-option>
|
||||
</j-select>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
<Title data="存储策略">
|
||||
<template #extra>
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
title="若修改存储策略,需要手动做数据迁移,平台只能搜索最新存储策略中的数据"
|
||||
>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</Title>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item>
|
||||
<a-select
|
||||
<j-form layout="vertical">
|
||||
<j-form-item>
|
||||
<j-select
|
||||
ref="select"
|
||||
v-model:value="form.storePolicy"
|
||||
>
|
||||
<a-select-option
|
||||
<j-select-option
|
||||
v-for="(item, index) in storageList"
|
||||
:key="index"
|
||||
:value="item.id"
|
||||
>{{ item.name }}</a-select-option
|
||||
>{{ item.name }}</j-select-option
|
||||
>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<PermissionButton type="primary" @click="submitDevice" hasPermission="device/Instance:update">保存</PermissionButton>
|
||||
</a-col>
|
||||
<a-col
|
||||
</j-select>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
@click="submitDevice"
|
||||
hasPermission="device/Instance:update"
|
||||
>保存</PermissionButton
|
||||
>
|
||||
</j-col>
|
||||
<j-col
|
||||
:span="12"
|
||||
v-if="config?.routes && config?.routes?.length > 0"
|
||||
>
|
||||
|
@ -191,7 +202,7 @@
|
|||
: 'URL信息'
|
||||
}}
|
||||
</div>
|
||||
<a-table
|
||||
<j-table
|
||||
:columns="
|
||||
config.id === 'MQTT'
|
||||
? columnsMQTT
|
||||
|
@ -203,14 +214,14 @@
|
|||
>
|
||||
<template #bodyCell="{ text, column, record }">
|
||||
<template v-if="column.key === 'topic'">
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
placement="topLeft"
|
||||
:title="text"
|
||||
>
|
||||
<div class="ellipsis-style">
|
||||
{{ text }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'stream'">
|
||||
<div>{{ getStream(record) }}</div>
|
||||
|
@ -218,45 +229,45 @@
|
|||
<template
|
||||
v-if="column.key === 'description'"
|
||||
>
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
placement="topLeft"
|
||||
:title="text"
|
||||
>
|
||||
<div class="ellipsis-style">
|
||||
{{ text }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'address'">
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
placement="topLeft"
|
||||
:title="text"
|
||||
>
|
||||
<div class="ellipsis-style">
|
||||
{{ text }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'example'">
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
placement="topLeft"
|
||||
:title="text"
|
||||
>
|
||||
<div class="ellipsis-style">
|
||||
{{ text }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</j-table>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</div>
|
||||
</a-card>
|
||||
</j-card>
|
||||
<!-- 选择设备 -->
|
||||
<a-modal
|
||||
<j-modal
|
||||
title="设备接入配置"
|
||||
:visible="visible"
|
||||
width="1200px"
|
||||
|
@ -265,16 +276,16 @@
|
|||
@ok="submitData"
|
||||
@cancel="cancel"
|
||||
>
|
||||
<Search
|
||||
<pro-search
|
||||
:columns="query.columns"
|
||||
target="deviceModal"
|
||||
@search="search"
|
||||
/>
|
||||
<JProTable
|
||||
:columns="columns"
|
||||
:columns="query.columns"
|
||||
:request="queryList"
|
||||
ref="tableRef"
|
||||
modal="card"
|
||||
model="CARD"
|
||||
:defaultParams="{
|
||||
...temp,
|
||||
sorts: [
|
||||
|
@ -288,8 +299,8 @@
|
|||
:gridColumns="[2]"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-button type="primary" @click="add"
|
||||
><plus-outlined />新增</a-button
|
||||
<j-button type="primary" @click="add"
|
||||
><plus-outlined />新增</j-button
|
||||
>
|
||||
</template>
|
||||
<template #deviceType="slotProps">
|
||||
|
@ -314,22 +325,35 @@
|
|||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3 style="font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<Ellipsis style="width: calc(100% - 100px)">
|
||||
<h3 style="font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
</Ellipsis>
|
||||
<j-row>
|
||||
<j-col :span="12" v-if="slotProps.channelInfo">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
{{ slotProps.channelInfo?.name }}
|
||||
</div>
|
||||
<div>直连设备</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<div>
|
||||
{{
|
||||
slotProps.channelInfo?.addresses
|
||||
? slotProps.channelInfo
|
||||
?.addresses[0].address
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">协议</div>
|
||||
<div>{{ slotProps.protocolDetail?.name }}</div>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<a-badge
|
||||
<j-badge
|
||||
:text="slotProps.state === 1 ? '正常' : '禁用'"
|
||||
:status="statusMap.get(slotProps.state)"
|
||||
/>
|
||||
|
@ -338,13 +362,13 @@
|
|||
<a>{{ slotProps.id }}</a>
|
||||
</template>
|
||||
</JProTable>
|
||||
</a-modal>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { ConfigMetadata } from '@/views/device/Product/typings';
|
||||
import { Empty, message } from 'ant-design-vue';
|
||||
import { Empty, FormItem, message } from 'ant-design-vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import Title from '../Title/index.vue';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
|
@ -370,6 +394,9 @@ import Driver from 'driver.js';
|
|||
import 'driver.js/dist/driver.min.css';
|
||||
import { marked } from 'marked';
|
||||
import type { FormInstance, TableColumnType } from 'ant-design-vue';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
const formRef = ref();
|
||||
const menuStore = useMenuStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const render = new marked.Renderer();
|
||||
marked.setOptions({
|
||||
|
@ -396,7 +423,6 @@ const current = ref({
|
|||
name: productStore.current?.protocolName,
|
||||
},
|
||||
});
|
||||
|
||||
//存储数据
|
||||
const form = reactive<Record<string, any>>({
|
||||
storePolicy: 'default-row' || productStore.current?.storePolicy || '',
|
||||
|
@ -442,15 +468,14 @@ const query = reactive({
|
|||
},
|
||||
{
|
||||
title: '网关类型',
|
||||
key: 'accessProvider',
|
||||
dataIndex: 'accessProvider',
|
||||
key: 'provider',
|
||||
dataIndex: 'provider',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: async () => {
|
||||
return new Promise((res) => {
|
||||
getProviders().then((resp: any) => {
|
||||
listData.value = [];
|
||||
// const list = () => {
|
||||
if (isNoCommunity) {
|
||||
listData.value = (resp?.result || []).map(
|
||||
(item: any) => ({
|
||||
|
@ -489,19 +514,19 @@ const query = reactive({
|
|||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 1,
|
||||
value: 'enabled',
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 0,
|
||||
value: 'disabled',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
key: 'describe',
|
||||
dataIndex: 'describe',
|
||||
key: 'description',
|
||||
dataIndex: 'description',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
|
@ -564,9 +589,9 @@ const search = (e: any) => {
|
|||
//引导页数据
|
||||
const steps = [
|
||||
{
|
||||
element: '.device-detail-metadata',
|
||||
element: '#rc-tabs-0-tab-Metadata',
|
||||
popover: {
|
||||
className: 'driver',
|
||||
id: 'driver',
|
||||
title: `<div id='title'>配置物模型</div><div id='guide'>1/3</div>`,
|
||||
description: `配置产品物模型,实现设备在云端的功能描述。`,
|
||||
position: 'bottom',
|
||||
|
@ -820,7 +845,6 @@ const getStream = (record: any) => {
|
|||
* 查询接入方式
|
||||
*/
|
||||
const queryAccessDetail = async (id: string) => {
|
||||
console.log(id, 'id');
|
||||
const res = await queryList({
|
||||
terms: [
|
||||
{
|
||||
|
@ -896,7 +920,6 @@ const getProviderList = async () => {
|
|||
* 提交设备数据
|
||||
*/
|
||||
const submitData = async () => {
|
||||
console.log(current.value, 'vvv');
|
||||
if (current.value) {
|
||||
const obj: any = {
|
||||
...productStore.current,
|
||||
|
@ -938,7 +961,6 @@ const submitData = async () => {
|
|||
? await updateDevice(obj)
|
||||
: await saveDevice(obj);
|
||||
if (resp.status === 200) {
|
||||
console.log(productStore.current?.id, 'productStore.current?.id');
|
||||
detail(productStore.current?.id || '').then((res) => {
|
||||
if (res.status === 200) {
|
||||
productStore.current = { ...res.result };
|
||||
|
@ -1015,10 +1037,12 @@ const getData = async () => {
|
|||
* 保存设备接入
|
||||
*/
|
||||
const submitDevice = async () => {
|
||||
const res = await formRef.value.validate();
|
||||
const values = { storePolicy: form.storePolicy, ...formData.data };
|
||||
const result: any = {};
|
||||
flatObj(values, result);
|
||||
const { storePolicy, ...extra } = result;
|
||||
console.log({ ...extra });
|
||||
const id = productStore.current?.id;
|
||||
const resp = await modify(id || '', {
|
||||
id: id,
|
||||
|
@ -1047,6 +1071,13 @@ const flatObj = (obj: any, result: any) => {
|
|||
});
|
||||
};
|
||||
const getDetailInfo = () => {};
|
||||
|
||||
const add = () => {
|
||||
const url = menuStore.hasMenu('link/AccessConfig/Detail');
|
||||
if (url) {
|
||||
window.open(`${origin}/#${url}`);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
|
|
|
@ -10,60 +10,79 @@
|
|||
<div style="display: flex; align-items: center">
|
||||
<div>{{ productStore.current.name }}</div>
|
||||
<div style="margin: -5px 0 0 20px">
|
||||
<a-popconfirm
|
||||
<j-popconfirm
|
||||
title="确认禁用"
|
||||
@confirm="handleUndeploy"
|
||||
v-if="productStore.current.state === 1"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-switch
|
||||
<j-switch
|
||||
:checked="productStore.current.state === 1"
|
||||
checked-children="正常"
|
||||
un-checked-children="禁用"
|
||||
/>
|
||||
</a-popconfirm>
|
||||
<a-popconfirm
|
||||
</j-popconfirm>
|
||||
<j-popconfirm
|
||||
title="确认启用"
|
||||
@confirm="handleDeploy"
|
||||
v-if="productStore.current.state === 0"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-switch
|
||||
<j-switch
|
||||
:unCheckedValue="
|
||||
productStore.current.state === 0
|
||||
"
|
||||
checked-children="正常"
|
||||
un-checked-children="禁用"
|
||||
/>
|
||||
</a-popconfirm>
|
||||
</j-popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-top: 10px">
|
||||
<a-descriptions size="small" :column="4">
|
||||
<a-descriptions-item label="设备数量">{{
|
||||
productStore.current?.count
|
||||
? productStore.current?.count
|
||||
: 0
|
||||
}}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<j-descriptions size="small" :column="4">
|
||||
<j-descriptions-item
|
||||
label="设备数量"
|
||||
style="cursor: pointer"
|
||||
><span @click="jumpDevice">{{
|
||||
productStore.current?.count
|
||||
? productStore.current?.count
|
||||
: 0
|
||||
}}</span></j-descriptions-item
|
||||
>
|
||||
</j-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-popconfirm
|
||||
title="确认应用配置"
|
||||
@confirm="handleCofig"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-button
|
||||
:disabled="productStore.current.state === 0"
|
||||
type="primary"
|
||||
>应用配置</a-button
|
||||
<!-- <j-popconfirm
|
||||
title="确认应用配置"
|
||||
@confirm="handleCofig"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
</a-popconfirm>
|
||||
<j-button
|
||||
:disabled="productStore.current.state === 0"
|
||||
type="primary"
|
||||
>应用配置</j-button
|
||||
>
|
||||
</j-popconfirm> -->
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:popConfirm="{
|
||||
title: `确定应用配置?`,
|
||||
onConfirm: handleConfig,
|
||||
}"
|
||||
:disabled="productStore.current?.state === 0"
|
||||
:tooltip="
|
||||
productStore.current?.state === 0
|
||||
? { title: '请先启用产品' }
|
||||
: undefined
|
||||
"
|
||||
hasPermission="device/Product:update"
|
||||
>应用配置</PermissionButton
|
||||
>
|
||||
</template>
|
||||
<component
|
||||
:is="tabs[productStore.tabActiveKey]"
|
||||
|
@ -88,6 +107,8 @@ import {
|
|||
import { message } from 'ant-design-vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import encodeQuery from '@/utils/encodeQuery';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
const menuStory = useMenuStore();
|
||||
|
||||
const route = useRoute();
|
||||
const checked = ref<boolean>(true);
|
||||
|
@ -123,7 +144,7 @@ const tabs = {
|
|||
Info,
|
||||
Metadata,
|
||||
Device,
|
||||
DataAnalysis
|
||||
DataAnalysis,
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -189,7 +210,7 @@ const handleUndeploy = async () => {
|
|||
*/
|
||||
const getProtocol = async () => {
|
||||
if (productStore.current?.messageProtocol) {
|
||||
const res:any = await getProtocolDetail(
|
||||
const res: any = await getProtocolDetail(
|
||||
productStore.current?.messageProtocol,
|
||||
);
|
||||
if (res.status === 200) {
|
||||
|
@ -205,9 +226,27 @@ const getProtocol = async () => {
|
|||
}
|
||||
}
|
||||
};
|
||||
onMounted(()=>{
|
||||
/**
|
||||
* 详情页跳转到设备页
|
||||
*/
|
||||
const jumpDevice = () => {
|
||||
console.log(productStore.current?.id);
|
||||
const searchParams = {
|
||||
column: 'productId',
|
||||
termType: 'eq',
|
||||
value: productStore.current?.id,
|
||||
};
|
||||
menuStory.jumpPage('device/Instance',{},{
|
||||
target: 'device-instance',
|
||||
q: JSON.stringify({ terms: [{ terms: [{searchParams}] }] }),
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
getProtocol();
|
||||
})
|
||||
if(history.state?.params?.tab){
|
||||
productStore.tabActiveKey = history.state?.params?.tab
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.ant-switch-loading,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 新增、编辑产品 -->
|
||||
<template>
|
||||
<a-modal
|
||||
<j-modal
|
||||
:title="props.title"
|
||||
:maskClosable="false"
|
||||
destroy-on-close
|
||||
|
@ -14,18 +14,18 @@
|
|||
:confirmLoading="loading"
|
||||
>
|
||||
<div style="margin-top: 10px">
|
||||
<a-form
|
||||
<j-form
|
||||
:layout="'vertical'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
>
|
||||
<a-row type="flex">
|
||||
<a-col flex="180px">
|
||||
<a-form-item name="photoUrl">
|
||||
<j-row type="flex">
|
||||
<j-col flex="180px">
|
||||
<j-form-item name="photoUrl">
|
||||
<JUpload v-model="form.photoUrl" />
|
||||
</a-form-item>
|
||||
<!-- <a-form-item>
|
||||
</j-form-item>
|
||||
<!-- <j-form-item>
|
||||
<div class="upload-image-warp-logo">
|
||||
<div class="upload-image-border-logo">
|
||||
<a-upload
|
||||
|
@ -89,37 +89,37 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-form-item> -->
|
||||
</a-col>
|
||||
<a-col flex="auto">
|
||||
<a-form-item name="id">
|
||||
</j-form-item> -->
|
||||
</j-col>
|
||||
<j-col flex="auto">
|
||||
<j-form-item name="id">
|
||||
<template #label>
|
||||
<span>ID</span>
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
title="若不填写,系统将自动生成唯一ID"
|
||||
>
|
||||
<span>ID</span>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
<a-input
|
||||
<j-input
|
||||
v-model:value="form.id"
|
||||
placeholder="请输入ID"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="名称" name="name">
|
||||
<a-input
|
||||
</j-form-item>
|
||||
<j-form-item label="名称" name="name">
|
||||
<j-input
|
||||
v-model:value="form.name"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-form-item label="产品分类" name="classifiedId">
|
||||
<a-tree-select
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-form-item label="产品分类" name="classifiedId">
|
||||
<j-tree-select
|
||||
showSearch
|
||||
v-model:value="form.classifiedId"
|
||||
placeholder="请选择产品分类"
|
||||
|
@ -131,40 +131,40 @@
|
|||
"
|
||||
>
|
||||
<template> </template>
|
||||
</a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="设备类型" name="deviceType">
|
||||
<a-radio-group
|
||||
</j-tree-select>
|
||||
</j-form-item>
|
||||
<j-form-item label="设备类型" name="deviceType">
|
||||
<j-radio-group
|
||||
v-model:value="form.deviceType"
|
||||
style="width: 100%"
|
||||
@change="changeValue"
|
||||
>
|
||||
<a-row :span="24" :gutter="10">
|
||||
<a-col
|
||||
<j-row :span="24" :gutter="10">
|
||||
<j-col
|
||||
:span="8"
|
||||
v-for="item in deviceList"
|
||||
:key="item.value"
|
||||
>
|
||||
<div class="button-style">
|
||||
<a-radio-button
|
||||
<j-radio-button
|
||||
:value="item.value"
|
||||
style="height: 100%; width: 100%"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<div class="card-content">
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="10">
|
||||
<j-row :gutter="20">
|
||||
<j-col :span="10">
|
||||
<!-- 图片 -->
|
||||
<div class="img-style">
|
||||
<img :src="item.logo" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
</j-col>
|
||||
<j-col :span="14">
|
||||
<span class="card-style">
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</j-col>
|
||||
</j-row>
|
||||
|
||||
<!-- 勾选 -->
|
||||
<div
|
||||
|
@ -179,21 +179,21 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
</j-radio-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="说明" name="describe">
|
||||
<a-textarea
|
||||
</j-col>
|
||||
</j-row>
|
||||
</j-radio-group>
|
||||
</j-form-item>
|
||||
<j-form-item label="说明" name="describe">
|
||||
<j-textarea
|
||||
v-model:value="form.describe"
|
||||
placeholder="请输入说明"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</j-modal>
|
||||
<DialogTips ref="dialogRef" />
|
||||
</template>
|
||||
|
||||
|
@ -275,6 +275,7 @@ const form = reactive({
|
|||
*/
|
||||
const validateInput = async (_rule: Rule, value: string) => {
|
||||
if (value) {
|
||||
console.log(value.split('').length);
|
||||
if (!isInput(value)) {
|
||||
return Promise.reject('请输入英文或者数字或者-或者_');
|
||||
} else {
|
||||
|
@ -302,8 +303,14 @@ const validateDeviceType = async (_rule: Rule, value: string) => {
|
|||
}
|
||||
};
|
||||
const rules = reactive({
|
||||
id: [{ validator: validateInput, trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
id: [
|
||||
{ validator: validateInput, trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64位字符', trigger: 'change' },
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64位字符', trigger: 'change' },
|
||||
],
|
||||
deviceType: [
|
||||
{
|
||||
required: true,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<Search
|
||||
<pro-search
|
||||
:columns="query.columns"
|
||||
target="product-manage"
|
||||
@search="handleSearch"
|
||||
|
@ -64,7 +64,7 @@
|
|||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<Ellipsis
|
||||
<Ellipsis style="width: calc(100% - 100px)"
|
||||
><span
|
||||
@click.stop="handleView(slotProps.id)"
|
||||
style="font-weight: 600; font-size: 16px"
|
||||
|
@ -72,64 +72,30 @@
|
|||
{{ slotProps.name }}
|
||||
</span></Ellipsis
|
||||
>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<j-row>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>{{ slotProps?.deviceType?.text }}</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
接入方式
|
||||
</div>
|
||||
<Ellipsis
|
||||
><div>
|
||||
{{ slotProps?.accessName }}
|
||||
{{
|
||||
slotProps?.accessName
|
||||
? slotProps?.accessName
|
||||
: '未接入'
|
||||
}}
|
||||
</div></Ellipsis
|
||||
>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<!-- <a-tooltip
|
||||
v-bind="item.tooltip"
|
||||
:title="item.disabled && item.tooltip.title"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="item.popConfirm"
|
||||
v-bind="item.popConfirm"
|
||||
:disabled="item.disabled"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-button :disabled="item.disabled">
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<template v-else>
|
||||
<a-button
|
||||
:disabled="item.disabled"
|
||||
@click="item.onClick"
|
||||
>
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
</a-tooltip> -->
|
||||
<PermissionButton
|
||||
:disabled="item.disabled"
|
||||
:popConfirm="item.popConfirm"
|
||||
|
@ -152,7 +118,7 @@
|
|||
</CardBox>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<a-badge
|
||||
<j-badge
|
||||
:text="slotProps.state === 1 ? '正常' : '禁用'"
|
||||
:status="statusMap.get(slotProps.state)"
|
||||
/>
|
||||
|
@ -161,39 +127,7 @@
|
|||
<a>{{ slotProps.id }}</a>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<!-- <a-tooltip
|
||||
v-for="i in getActions(slotProps)"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="i.popConfirm"
|
||||
v-bind="i.popConfirm"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip> -->
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
|
@ -212,7 +146,7 @@
|
|||
<template #icon><AIcon :type="i.icon" /></template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</a-space>
|
||||
</j-space>
|
||||
</template>
|
||||
</JProTable>
|
||||
<!-- 新增、编辑 -->
|
||||
|
@ -249,11 +183,11 @@ import { omit } from 'lodash-es';
|
|||
import { typeOptions } from '@/components/Search/util';
|
||||
import Save from './Save/index.vue';
|
||||
import { useMenuStore } from 'store/menu';
|
||||
import { useRoute } from 'vue-router';
|
||||
/**
|
||||
* 表格数据
|
||||
*/
|
||||
const menuStory = useMenuStore();
|
||||
const router = useRouter();
|
||||
const isAdd = ref<number>(0);
|
||||
const title = ref<string>('');
|
||||
const params = ref<Record<string, any>>({});
|
||||
|
@ -673,6 +607,12 @@ const saveRef = ref();
|
|||
const handleSearch = (e: any) => {
|
||||
params.value = e;
|
||||
};
|
||||
const route = useRoute();
|
||||
onMounted(() => {
|
||||
if(history.state?.params?.save){
|
||||
add();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -76,8 +76,6 @@ const save = reactive({
|
|||
const type = metadataStore.model.type
|
||||
const _detail: ProductItem | DeviceInstance = props.type === 'device' ? instanceStore.detail : productStore.current
|
||||
const _metadata = JSON.parse(_detail?.metadata || '{}')
|
||||
console.log(_metadata)
|
||||
console.log(type)
|
||||
const list = (_metadata[type] as any[]) || []
|
||||
if (formValue.id) {
|
||||
if (metadataStore.model.action === 'add' && list.some(item => item.id === formValue.id)) {
|
||||
|
|
|
@ -39,7 +39,6 @@ export const validateIdName = async (_rule: Rule, val: Record<any, any>) => {
|
|||
}
|
||||
|
||||
export const validateValueType = async (_rule: Rule, val: Record<any, any>, title = '数据类型') => {
|
||||
console.log(val)
|
||||
if (!val) return Promise.reject(new Error('请输入元素配置'));
|
||||
if (!val?.type) {
|
||||
return Promise.reject(new Error(`请选择${title}`))
|
||||
|
|
|
@ -164,7 +164,6 @@ const beforeUpload: UploadProps['beforeUpload'] = file => {
|
|||
}
|
||||
const fileChange = (info: UploadChangeParam) => {
|
||||
if (info.file.status === 'done') {
|
||||
console.log(info)
|
||||
const { response } = info.file
|
||||
if (response.status === 200) {
|
||||
formModel.upload = response.result
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<j-modal :maskClosable="false" width="1100px" :visible="true" title="选择设备" okText="确定" cancelText="取消" @ok="handleOk"
|
||||
@cancel="handleCancel" :confirmLoading="btnLoading">
|
||||
<div style="margin-top: 10px">
|
||||
<Search :columns="columns" target="iot-card-bind-device" @search="handleSearch" type="simple" />
|
||||
<pro-search :columns="columns" target="iot-card-bind-device" @search="handleSearch" type="simple" />
|
||||
<j-pro-table ref="bindDeviceRef" :columns="columns" :request="queryUnbounded" model="TABLE" :defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}" :rowSelection="{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- 物联卡管理 -->
|
||||
<template>
|
||||
<page-container>
|
||||
<Search :columns="columns" target="iot-card-management-search" @search="handleSearch" />
|
||||
<pro-search :columns="columns" target="iot-card-management-search" @search="handleSearch" />
|
||||
<j-pro-table ref="cardManageRef" :columns="columns" :request="query"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- 平台对接 -->
|
||||
<template>
|
||||
<page-container>
|
||||
<Search :columns="columns" target="platform-search" @search="handleSearch" />
|
||||
<pro-search :columns="columns" target="platform-search" @search="handleSearch" />
|
||||
<j-pro-table ref="platformRef" :columns="columns" :request="queryList"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :params="params" :gridColumn="3">
|
||||
<template #headerTitle>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- 充值管理 -->
|
||||
<template>
|
||||
<page-container>
|
||||
<Search :columns="columns" target="recharge-search" @search="handleSearch" />
|
||||
<pro-search :columns="columns" target="recharge-search" @search="handleSearch" />
|
||||
<j-pro-table ref="rechargeRef" :columns="columns" :request="queryRechargeList" model="TABLE"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :params="params">
|
||||
<template #headerTitle>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- 操作记录 -->
|
||||
<template>
|
||||
<page-container>
|
||||
<Search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="record-search"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
@cancel="_vis = false"
|
||||
:confirmLoading="loading"
|
||||
>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
type="simple"
|
||||
:columns="columns"
|
||||
target="media"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- 国标级联-通道列表 -->
|
||||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
type="simple"
|
||||
:columns="columns"
|
||||
target="media"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="media-cascade"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
type="simple"
|
||||
:columns="columns"
|
||||
target="product"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="notice-config"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -132,6 +132,8 @@ const getTemplateList = async () => {
|
|||
};
|
||||
const { result } = await ConfigApi.getTemplate(params, props.data.id);
|
||||
templateList.value = result;
|
||||
formData.value.templateId = result[0]?.id as string;
|
||||
getTemplateDetail()
|
||||
};
|
||||
|
||||
watch(
|
||||
|
|
|
@ -125,21 +125,64 @@
|
|||
v-bind="validateInfos['configuration.host']"
|
||||
>
|
||||
<j-space>
|
||||
<j-input
|
||||
<j-auto-complete
|
||||
v-model:value="
|
||||
formData.configuration.host
|
||||
"
|
||||
placeholder="请输入服务器地址"
|
||||
style="width: 180px"
|
||||
:options="[
|
||||
{
|
||||
label: 'smtp.163.com',
|
||||
value: 'smtp.163.com',
|
||||
},
|
||||
{
|
||||
label: 'pop.163.com',
|
||||
value: 'pop.163.com',
|
||||
},
|
||||
{
|
||||
label: 'smtp.exmail.qq.com',
|
||||
value: 'smtp.exmail.qq.com',
|
||||
},
|
||||
{
|
||||
label: 'pop.exmail.qq.com',
|
||||
value: 'pop.exmail.qq.com',
|
||||
},
|
||||
{
|
||||
label: 'smtp.qq.com',
|
||||
value: 'smtp.qq.com',
|
||||
},
|
||||
{
|
||||
label: 'pop.qq.com',
|
||||
value: 'pop.qq.com',
|
||||
},
|
||||
{
|
||||
label: 'smtpdm.aliyun.com',
|
||||
value: 'smtpdm.aliyun.com',
|
||||
},
|
||||
{
|
||||
label: 'smtp.126.com',
|
||||
value: 'smtp.126.com',
|
||||
},
|
||||
{
|
||||
label: 'pop.126.com',
|
||||
value: 'pop.126.com',
|
||||
},
|
||||
]"
|
||||
/>
|
||||
<j-input-number
|
||||
v-model:value="
|
||||
formData.configuration.port
|
||||
"
|
||||
:precision="0"
|
||||
:min="1"
|
||||
:max="65535"
|
||||
/>
|
||||
<j-checkbox
|
||||
v-model:value="
|
||||
v-model:checked="
|
||||
formData.configuration.ssl
|
||||
"
|
||||
@change="handleSslChange"
|
||||
>
|
||||
开启SSL
|
||||
</j-checkbox>
|
||||
|
@ -381,7 +424,10 @@ const formRules = ref({
|
|||
],
|
||||
// 邮件
|
||||
'configuration.host': [{ required: true, message: '请输入服务器地址' }],
|
||||
'configuration.sender': [{ required: true, message: '请输入发件人' }],
|
||||
'configuration.sender': [
|
||||
{ required: true, message: '请输入发件人' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
'configuration.username': [
|
||||
{ required: true, message: '请输入用户名' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
|
@ -408,7 +454,6 @@ const { resetFields, validate, validateInfos, clearValidate } = useForm(
|
|||
);
|
||||
|
||||
const getDetail = async () => {
|
||||
console.log('getDetail', route)
|
||||
if (route.params.id === ':id') return;
|
||||
const res = await configApi.detail(route.params.id as string);
|
||||
// formData.value = res.result;
|
||||
|
@ -438,6 +483,12 @@ const handleProviderChange = () => {
|
|||
resetPublicFiles();
|
||||
};
|
||||
|
||||
const handleSslChange = () => {
|
||||
formData.value.configuration.port = formData.value.configuration.ssl
|
||||
? 465
|
||||
: 25;
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置字段值
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<j-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%">
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
type="simple"
|
||||
:columns="columns"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="notice-config"
|
||||
@search="handleSearch"
|
||||
|
@ -26,7 +26,7 @@
|
|||
</PermissionButton>
|
||||
<a-upload
|
||||
name="file"
|
||||
accept="json"
|
||||
accept=".json"
|
||||
:showUploadList="false"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<j-form-item
|
||||
label="通知配置"
|
||||
name="configId"
|
||||
:rules="{ required: true, message: '该字段为必填字段' }"
|
||||
:rules="{ required: true, message: '请选择通知配置' }"
|
||||
>
|
||||
<j-select
|
||||
v-model:value="formData.configId"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
v-for="(item, index) in fileList"
|
||||
:key="index"
|
||||
>
|
||||
<j-input v-model:value="item.name">
|
||||
<j-input v-model:value="item.name" @change="emitEvents">
|
||||
<template #addonAfter>
|
||||
<a-upload
|
||||
name="file"
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
yyyy-MM-dd
|
||||
</j-select-option>
|
||||
<j-select-option value="yyyy-MM-dd HH:mm:ss">
|
||||
yyyy-MM-dd HH:mm:ss
|
||||
<Ellipsis>yyyy-MM-dd HH:mm:ss</Ellipsis>
|
||||
</j-select-option>
|
||||
</j-select>
|
||||
<j-input
|
||||
|
@ -143,7 +143,7 @@ const handleTypeChange = (record: IVariable) => {
|
|||
record.format = 'timestamp';
|
||||
break;
|
||||
case 'double':
|
||||
record.format = '%.0f';
|
||||
record.format = '%.xf';
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -353,7 +353,9 @@
|
|||
placeholder="请输入标题"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item>
|
||||
<j-form-item
|
||||
v-bind="validateInfos['template.sendTo']"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
收件人
|
||||
|
@ -369,9 +371,8 @@
|
|||
</template>
|
||||
<j-select
|
||||
mode="tags"
|
||||
:options="[]"
|
||||
v-model:value="formData.template.sendTo"
|
||||
placeholder="请选择收件人"
|
||||
placeholder="请输入收件人邮箱,多个收件人用换行分隔"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item>
|
||||
|
@ -459,7 +460,13 @@
|
|||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<j-form-item>
|
||||
<j-form-item
|
||||
v-bind="
|
||||
validateInfos[
|
||||
'template.calledNumber'
|
||||
]
|
||||
"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
被叫号码
|
||||
|
@ -507,7 +514,9 @@
|
|||
placeholder="请输入被叫显号"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item>
|
||||
<j-form-item
|
||||
v-bind="validateInfos['template.playTimes']"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
播放次数
|
||||
|
@ -519,9 +528,10 @@
|
|||
</j-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<j-input
|
||||
<j-input-number
|
||||
v-model:value="formData.template.playTimes"
|
||||
placeholder="请输入播放次数"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
|
@ -694,7 +704,6 @@
|
|||
</template>
|
||||
<j-textarea
|
||||
v-model:value="formData.template.message"
|
||||
:maxlength="200"
|
||||
:rows="5"
|
||||
:disabled="formData.type === 'sms'"
|
||||
placeholder="变量格式:${name};
|
||||
|
@ -896,22 +905,48 @@ const formRules = ref({
|
|||
'template.agentId': [{ required: true, message: '请输入agentId' }],
|
||||
'template.messageType': [{ required: true, message: '请选择消息类型' }],
|
||||
'template.markdown.title': [
|
||||
{ required: true, message: '请输入标题' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
{ required: true, message: '请输入标题', trigger: 'change' },
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
],
|
||||
'template.link.title': [
|
||||
{ required: true, message: '请输入标题' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
{ required: true, message: '请输入标题', trigger: 'change' },
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
],
|
||||
// 'template.url': [{ required: true, message: '请输入WebHook' }],
|
||||
// 微信
|
||||
// 'template.agentId': [{ required: true, message: '请输入agentId' }],
|
||||
// 邮件
|
||||
'template.subject': [{ required: true, message: '请输入标题' }],
|
||||
'template.subject': [
|
||||
{ required: true, message: '请输入标题' },
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
],
|
||||
'template.sendTo': [
|
||||
{
|
||||
trigger: 'change',
|
||||
validator(_rule: Rule, value: string[]) {
|
||||
const regEmail =
|
||||
/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
||||
let error;
|
||||
if (value) {
|
||||
value.some((item: string) => {
|
||||
if (!regEmail.test(item)) {
|
||||
error = item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (error)
|
||||
return Promise.reject(error ? `${error}邮件格式错误` : '');
|
||||
else return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
// 阿里云语音
|
||||
'template.templateType': [{ required: true, message: '请选择类型' }],
|
||||
'template.templateCode': [{ required: true, message: '请输入模板ID' }],
|
||||
'template.calledShowNumbers': [
|
||||
'template.calledNumber': [
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
{
|
||||
trigger: 'change',
|
||||
validator(_rule: Rule, value: string) {
|
||||
|
@ -921,6 +956,27 @@ const formRules = ref({
|
|||
},
|
||||
},
|
||||
],
|
||||
'template.calledShowNumbers': [
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
{
|
||||
trigger: 'change',
|
||||
validator(_rule: Rule, value: string) {
|
||||
if (!value) return Promise.resolve();
|
||||
if (!phoneRegEx(value)) return Promise.reject('请输入有效号码');
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
'template.playTimes': [
|
||||
{
|
||||
trigger: 'change',
|
||||
validator(_rule: Rule, value: number) {
|
||||
if (value < 1 || value > 3)
|
||||
return Promise.reject('仅支持1~3次');
|
||||
else return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
// 短信
|
||||
'template.code': [{ required: true, message: '请选择模板' }],
|
||||
'template.signName': [{ required: true, message: '请输入签名' }],
|
||||
|
@ -929,9 +985,9 @@ const formRules = ref({
|
|||
'template.message': [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入',
|
||||
message: '请输入模板内容',
|
||||
},
|
||||
{ max: 500, message: '最多可输入500个字符' },
|
||||
{ max: 500, message: '最多可输入500个字符', trigger: 'change' },
|
||||
],
|
||||
'template.ttsmessage': [{ max: 500, message: '最多可输入500个字符' }],
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<j-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%">
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
type="simple"
|
||||
:columns="columns"
|
||||
@search="handleSearch"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="notice-config"
|
||||
@search="handleSearch"
|
||||
|
@ -26,7 +26,7 @@
|
|||
</PermissionButton>
|
||||
<a-upload
|
||||
name="file"
|
||||
accept="json"
|
||||
accept=".json"
|
||||
:showUploadList="false"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
|
|
|
@ -16,22 +16,22 @@
|
|||
}}
|
||||
</div>
|
||||
<div class="new-alarm-item-content">
|
||||
<a-tooltip
|
||||
<j-tooltip
|
||||
:title="item.alarmName"
|
||||
placement="topLeft"
|
||||
>
|
||||
<a @click="()=>{return jumpDetail(item)}">{{ item.alarmName }}</a>
|
||||
</a-tooltip>
|
||||
</j-tooltip>
|
||||
</div>
|
||||
<div class="new-alarm-item-state">
|
||||
<a-badge
|
||||
<j-badge
|
||||
:status="
|
||||
item.state?.value === 'warning'
|
||||
? 'error'
|
||||
: 'default'
|
||||
"
|
||||
>
|
||||
</a-badge>
|
||||
</j-badge>
|
||||
<span
|
||||
:class="
|
||||
item.state?.value === 'warning'
|
||||
|
@ -55,7 +55,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div v-else class="empty-body">
|
||||
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE"></a-empty>
|
||||
<j-empty :image="Empty.PRESENTED_IMAGE_SIMPLE"></j-empty>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -73,7 +73,7 @@ const props = defineProps({
|
|||
});
|
||||
const menuStore = useMenuStore();
|
||||
const jumpDetail = (item:any) =>{
|
||||
menuStore.jumpPage(`rule-engine/Alarm/Log/Detail`,{id:item.id},{detail:true});
|
||||
menuStore.jumpPage(`rule-engine/Alarm/Log/Detail`,{id:item.id,detail:true});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<div class="DashBoardBox">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<j-row :gutter="24">
|
||||
<j-col :span="6">
|
||||
<TopCard
|
||||
title="今日告警"
|
||||
:value="state.today"
|
||||
|
@ -10,33 +10,33 @@
|
|||
>
|
||||
<Charts :options="state.fifteenOptions"></Charts>
|
||||
</TopCard>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<TopCard
|
||||
title="告警配置"
|
||||
:value="state.config"
|
||||
:footer="alarmState"
|
||||
:img="getImage('/device/device-number.png')"
|
||||
></TopCard>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<NewAlarm :alarm-list="state.alarmList"></NewAlarm>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-row :gutter="24">
|
||||
<j-col :span="24">
|
||||
<div class="alarm-card">
|
||||
<Guide>
|
||||
<template #title>
|
||||
<span style="margin-right: 24px">告警统计</span>
|
||||
<a-select
|
||||
<j-select
|
||||
style="width: 40%"
|
||||
v-model:value="queryCodition.targetType"
|
||||
:options="
|
||||
isNoCommunity ? selectOpt1 : selectOpt2
|
||||
"
|
||||
@change="selectChange"
|
||||
></a-select>
|
||||
></j-select>
|
||||
</template>
|
||||
<template #extra>
|
||||
<TimeSelect
|
||||
|
@ -63,13 +63,13 @@
|
|||
</li>
|
||||
</ul>
|
||||
<div v-else class="empty-body">
|
||||
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE"></a-empty>
|
||||
<j-empty :image="Empty.PRESENTED_IMAGE_SIMPLE"></j-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
|
|
@ -116,9 +116,7 @@
|
|||
@click="i.onClick"
|
||||
type="link"
|
||||
style="padding: 0px"
|
||||
:hasPermission="
|
||||
'rule-engine/Instance:' + i.key
|
||||
"
|
||||
:hasPermission="'rule-engine/Instance:' + i.key"
|
||||
>
|
||||
<template #icon
|
||||
><AIcon :type="i.icon"
|
||||
|
@ -306,11 +304,11 @@ const getActions = (
|
|||
return actions;
|
||||
};
|
||||
const add = () => {
|
||||
current.value = {
|
||||
name:'',
|
||||
description:''
|
||||
},
|
||||
visiable.value = true
|
||||
(current.value = {
|
||||
name: '',
|
||||
description: '',
|
||||
}),
|
||||
(visiable.value = true);
|
||||
};
|
||||
/**
|
||||
* 刷新数据
|
||||
|
@ -326,9 +324,14 @@ const openRuleEditor = (item: any) => {
|
|||
`/${SystemConst.API_BASE}/rule-editor/index.html#flow/${item.id}`,
|
||||
);
|
||||
};
|
||||
const closeSave = () =>{
|
||||
const closeSave = () => {
|
||||
visiable.value = false;
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
if (history.state?.params) {
|
||||
add();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
</style>
|
|
@ -343,6 +343,11 @@
|
|||
@cancel="onPropsCancel"
|
||||
/>
|
||||
</template>
|
||||
<TriggerAlarm
|
||||
:id="_data.id"
|
||||
v-if="triggerVisible"
|
||||
@close="triggerVisible = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -353,6 +358,12 @@ import { PropType } from 'vue';
|
|||
import { ActionsType, ParallelType } from '../../../typings';
|
||||
import Modal from '../Modal/index.vue';
|
||||
import ActionTypeComponent from '../Modal/ActionTypeComponent.vue';
|
||||
import TriggerAlarm from '../TriggerAlarm/index.vue';
|
||||
import { useSceneStore } from '@/store/scene';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
const sceneStore = useSceneStore();
|
||||
const { data: _data } = storeToRefs(sceneStore);
|
||||
|
||||
const props = defineProps({
|
||||
branchesName: {
|
||||
|
@ -438,8 +449,8 @@ const onAdd = () => {
|
|||
};
|
||||
|
||||
const onType = (_type: string) => {
|
||||
actionType.value = _type
|
||||
}
|
||||
actionType.value = _type;
|
||||
};
|
||||
|
||||
const onPropsOk = (data: ActionsType, options?: any) => {
|
||||
emit('update', data, options);
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<template>
|
||||
<j-modal
|
||||
:width="1000"
|
||||
@cancel="emit('close')"
|
||||
@ok="emit('close')"
|
||||
visible
|
||||
title="关联此场景的告警"
|
||||
>
|
||||
<div style="margin-bottom: 24px">关联告警数量:{{ count }}</div>
|
||||
<JProTable
|
||||
:columns="columns"
|
||||
:request="queryAlarmList"
|
||||
model="TABLE"
|
||||
:bodyStyle="{ padding: 0 }"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'id',
|
||||
value: id,
|
||||
termType: 'rule-bind-alarm',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}"
|
||||
>
|
||||
<template #level="slotProps">
|
||||
{{ levelList.find(i => slotProps.level === i.level)?.title || '' }}
|
||||
</template>
|
||||
<template #targetType="slotProps">
|
||||
{{ map[slotProps.targetType] }}
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<j-badge
|
||||
:text="slotProps.state?.text"
|
||||
:status="
|
||||
slotProps.state?.value === 'disabled'
|
||||
? 'error'
|
||||
: 'success'
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</JProTable>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { queryAlarmList } from '@/api/rule-engine/scene';
|
||||
import {
|
||||
getAlarmLevel,
|
||||
getAlarmConfigCount,
|
||||
} from '@/api/rule-engine/dashboard';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const count = ref<number>(0);
|
||||
const levelList = ref<any[]>([]);
|
||||
|
||||
const map = {
|
||||
product: '产品',
|
||||
device: '设备',
|
||||
org: '组织',
|
||||
other: '其他',
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
fixed: 'left',
|
||||
ellipsis: true,
|
||||
title: '名称',
|
||||
},
|
||||
{
|
||||
dataIndex: 'targetType',
|
||||
title: '类型',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'level',
|
||||
title: '告警级别',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'state',
|
||||
title: '状态',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'description',
|
||||
title: '说明',
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
watch(
|
||||
() => props.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
getAlarmConfigCount({
|
||||
terms: [
|
||||
{
|
||||
column: 'id$rule-bind-alarm',
|
||||
value: newId,
|
||||
},
|
||||
],
|
||||
}).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
count.value = (resp.result || 0) as number;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
getAlarmLevel().then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
levelList.value = resp.result?.levels || []
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -19,6 +19,7 @@
|
|||
:format='myFormat'
|
||||
:valueFormat='myFormat'
|
||||
:getPopupContainer='getPopupContainer'
|
||||
popupClassName='manual-time-picker-popup'
|
||||
@change='change'
|
||||
/>
|
||||
</div>
|
||||
|
@ -62,7 +63,7 @@ const change = (e: string) => {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
<style lang='less'>
|
||||
.dropdown-time-picker {
|
||||
>div{
|
||||
position: relative !important;
|
||||
|
@ -80,6 +81,9 @@ const change = (e: string) => {
|
|||
.ant-picker-panel {
|
||||
width: 100%
|
||||
}
|
||||
.ant-picker-footer {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-panel-container {
|
||||
|
|
|
@ -20,6 +20,10 @@ export const getComponent = (type: string): string => {
|
|||
return 'date'
|
||||
case 'tree':
|
||||
return 'tree'
|
||||
case 'file':
|
||||
return 'file'
|
||||
case 'geoPoint':
|
||||
return 'geoPoint'
|
||||
default:
|
||||
return 'input'
|
||||
}
|
||||
|
@ -33,7 +37,7 @@ export const getOption = (data: any[], value?: string | number | boolean, key: s
|
|||
if (item[key] === value) {
|
||||
option = data[i]
|
||||
break
|
||||
} else if (item.children && item.children.length){
|
||||
} else if (item.children && item.children.length) {
|
||||
option = getOption(item.children, value, key)
|
||||
if (option) {
|
||||
break
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<j-advanced-search :columns="columns" target="scene" @search="handleSearch" />
|
||||
<pro-search :columns="columns" target="scene" @search="handleSearch" />
|
||||
<JProTable
|
||||
ref="sceneRef"
|
||||
:columns="columns"
|
||||
|
|
|
@ -3693,10 +3693,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.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.4.tgz#41d52892f0f4d38adc6df02a87290a3042eb5645"
|
||||
integrity sha512-aX+XiGigzxZnrG52xqipxd+WuFwBeZ6+dvLkcvOfLLBqSu8sgfvr/8NJ5hFgv5Eo2QFnUJq3Qf4HXLw9Ogv/yw==
|
||||
jetlinks-ui-components@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#30de07a15481f13ea86ebc817baaab3c99034403"
|
||||
integrity sha512-ULgSPU0xY6xUky3beeHVvpHyAHmT6xHsO5eS5m7a3h7AmCoxA3oTWyF20vC+K1zTJBQ7LFCouySqRRz6GimAPg==
|
||||
dependencies:
|
||||
"@vueuse/core" "^9.12.0"
|
||||
ant-design-vue "^3.2.15"
|
||||
|
|
Loading…
Reference in New Issue