fix: merge
This commit is contained in:
commit
0e3c28e64d
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -59,7 +59,16 @@ export const category = (data: any) => server.post('/device/category/_tree', dat
|
|||
* 获取接入方式
|
||||
* @param data 查询条件
|
||||
*/
|
||||
export const queryGatewayList = (data: any) => server.post('/gateway/device/_query/no-paging', data)
|
||||
const defaultGatewayData = {
|
||||
paging: false,
|
||||
sorts: [
|
||||
{
|
||||
name: 'createTime',
|
||||
order: 'desc',
|
||||
},
|
||||
],
|
||||
}
|
||||
export const queryGatewayList = (data: any = defaultGatewayData) => server.post('/gateway/device/_query/no-paging', data)
|
||||
|
||||
/**
|
||||
* 查询产品列表(分页)
|
||||
|
@ -166,3 +175,13 @@ export const saveDevice = (data:any) => server.post('/device-product',data)
|
|||
* 更新选择设备(设备接入)
|
||||
*/
|
||||
export const updateDevice = (data:any) => server.patch('/device-product',data)
|
||||
|
||||
/**
|
||||
* 获取操作符
|
||||
*/
|
||||
export const getOperator = () => server.get<OperatorItem>('/property-calculate-rule/description')
|
||||
|
||||
/**
|
||||
* 获取聚合函数列表
|
||||
*/
|
||||
export const getStreamingAggType = () => server.get<Record<string, string>[]>('/dictionary/streaming-agg-type/items')
|
|
@ -0,0 +1,21 @@
|
|||
import server from '@/utils/request';
|
||||
/**
|
||||
* 获取告警配置列表
|
||||
*/
|
||||
export const queryList = (data:any) => server.post('/alarm/config/detail/_query',data);
|
||||
/**
|
||||
* 启动告警配置
|
||||
*/
|
||||
export const _enable = (id:string) => server.post(`/alarm/config/${id}/_enable`);
|
||||
/**
|
||||
* 禁用告警配置
|
||||
*/
|
||||
export const _disable = (id:string) => server.post(`/alarm/config/${id}/_disable`);
|
||||
/**
|
||||
* 删除告警配置
|
||||
*/
|
||||
export const remove = (id:string) => server.remove(`/alarm/config/${id}`);
|
||||
/**
|
||||
* 手动触发告警
|
||||
*/
|
||||
export const _execute = (data:any) => server.post('/scene/batch/_execute',data)
|
|
@ -0,0 +1,9 @@
|
|||
import server from '@/utils/request';
|
||||
|
||||
|
||||
// 获取应用管理列表
|
||||
export const getApplyList_api = (data: any) => server.post(`/application/_query/`, data)
|
||||
// 修改应用状态
|
||||
export const changeApplyStatus_api = (id:string,data: any) => server.put(`/application/${id}`, data)
|
||||
// 删除应用
|
||||
export const delApply_api = (id:string) => server.remove(`/application/${id}`)
|
|
@ -52,6 +52,7 @@ const iconKeys = [
|
|||
'RightOutlined',
|
||||
'FileTextOutlined',
|
||||
'UploadOutlined',
|
||||
'LikeOutlined',
|
||||
'ArrowLeftOutlined',
|
||||
'DownloadOutlined'
|
||||
]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<div class="advance-box">
|
||||
<div class="left">
|
||||
<Editor
|
||||
ref="editor"
|
||||
mode="advance"
|
||||
key="advance"
|
||||
v-model:value="_value"
|
||||
|
@ -16,7 +17,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="right">
|
||||
<Operator :id="id" />
|
||||
<Operator :id="id" @add-operator-value="addOperatorValue"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
|
@ -44,10 +45,15 @@ const handleCancel = () => {
|
|||
emit('change', 'simple')
|
||||
}
|
||||
const handleOk = () => {
|
||||
console.log(_value.value)
|
||||
emit('update:value', _value.value)
|
||||
emit('change', 'simple')
|
||||
}
|
||||
|
||||
const editor = ref()
|
||||
const addOperatorValue = (val: string) => {
|
||||
editor.value.addOperatorValue(val)
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="top">
|
||||
<div class="left">
|
||||
<span v-for="item in symbolList.filter((t: SymbolType, i: number) => i <= 3)" :key="item.key"
|
||||
@click="handleInsertCode(item.value)">
|
||||
@click="addOperatorValue(item.value)">
|
||||
{{ item.value }}
|
||||
</span>
|
||||
<span>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item v-for="item in symbolList.filter((t: SymbolType, i: number) => i > 6)" :key="item.key"
|
||||
@click="handleInsertCode(item.value)">
|
||||
@click="addOperatorValue(item.value)">
|
||||
{{ item.value }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
|
@ -149,7 +149,7 @@ onMounted(() => {
|
|||
}, 100);
|
||||
})
|
||||
|
||||
const handleInsertCode = (val: string) => {
|
||||
const addOperatorValue = (val: string) => {
|
||||
editor.value?.insert(val)
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,10 @@ const fullscreenClick = () => {
|
|||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
addOperatorValue
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.editor-box {
|
||||
|
|
|
@ -1,51 +1,64 @@
|
|||
<template>
|
||||
<div class="operator-box">
|
||||
<a-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
||||
<a-tree class="tree" @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||
:tree-data="data">
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div>{{ node.name }}</div>
|
||||
<div :class="node.children?.length > 0 ? 'parent' : 'add'">
|
||||
<a-popover v-if="node.type === 'property'" placement="right" title="请选择使用值" @visibleChange="setVisible">
|
||||
<template #content>
|
||||
<a-space direction="vertical">
|
||||
<a-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
||||
<a-button type="text" @click="recentClick(node)">
|
||||
$recent实时值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="right" title="实时值的上一有效值">
|
||||
<a-button @click="lastClick(node)" type="text">
|
||||
上一值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<a @click="setVisible(true)">添加</a>
|
||||
</a-popover>
|
||||
<div class="tree">
|
||||
<a-tree @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||
:tree-data="data">
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div>{{ node.name }}</div>
|
||||
<div :class="node.children?.length > 0 ? 'parent' : 'add'">
|
||||
<a-popover v-if="node.type === 'property'" placement="right" title="请选择使用值">
|
||||
<template #content>
|
||||
<a-space direction="vertical">
|
||||
<a-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
||||
<a-button type="text" @click="recentClick(node)">
|
||||
$recent实时值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="right" title="实时值的上一有效值">
|
||||
<a-button @click="lastClick(node)" type="text">
|
||||
上一值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<a>添加</a>
|
||||
</a-popover>
|
||||
|
||||
<a v-else @click="addClick(node)">
|
||||
添加
|
||||
</a>
|
||||
<a v-else @click="addClick(node)">
|
||||
添加
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="explain">
|
||||
<ReactMarkdown>{{ item?.description || '' }}</ReactMarkdown>
|
||||
<Markdown :source="item?.description || ''"></Markdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts" name="Operator">
|
||||
import { useProductStore } from '@/store/product';
|
||||
import type { OperatorItem } from './typings';
|
||||
import { treeFilter } from '@/utils/tree'
|
||||
import { Store } from 'jetlinks-store';
|
||||
import { PropertyMetadata } from '@/views/device/Product/typings';
|
||||
import { getOperator } from '@/api/device/product'
|
||||
import Markdown from 'vue3-markdown-it'
|
||||
|
||||
const props = defineProps({
|
||||
id: String
|
||||
})
|
||||
|
||||
interface Emits {
|
||||
(e: 'addOperatorValue', data: string): void;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const item = ref<Partial<OperatorItem>>()
|
||||
const data = ref<OperatorItem[]>([])
|
||||
const dataRef = ref<OperatorItem[]>([])
|
||||
const visible = ref(false)
|
||||
|
||||
const search = (value: string) => {
|
||||
if (value) {
|
||||
|
@ -60,22 +73,52 @@ const selectTree = (k: any, info: any) => {
|
|||
item.value = info.node as unknown as OperatorItem;
|
||||
}
|
||||
|
||||
const setVisible = (_visible: boolean) => {
|
||||
visible.value = !!visible
|
||||
}
|
||||
|
||||
const recentClick = (node: OperatorItem) => {
|
||||
Store.set('add-operator-value', `$recent("${node.id}")`);
|
||||
setVisible(!visible.value);
|
||||
emit('addOperatorValue', `$recent("${node.id}")`)
|
||||
}
|
||||
const lastClick = (node: OperatorItem) => {
|
||||
Store.set('add-operator-value', `$lastState("${node.id}")`);
|
||||
setVisible(!visible.value);
|
||||
emit('addOperatorValue', `$lastState("${node.id}")`)
|
||||
}
|
||||
const addClick = (node: OperatorItem) => {
|
||||
Store.set('add-operator-value', node.code);
|
||||
setVisible(true);
|
||||
emit('addOperatorValue', node.code)
|
||||
}
|
||||
|
||||
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',
|
||||
name: '属性',
|
||||
description: '',
|
||||
code: '',
|
||||
children: _properties
|
||||
.filter((p: PropertyMetadata) => p.id !== id)
|
||||
.map((p: PropertyMetadata) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
description: `### ${p.name}
|
||||
\n 数据类型: ${p.valueType?.type}
|
||||
\n 是否只读: ${p.expands?.readOnly || 'false'}
|
||||
\n 可写数值范围: `,
|
||||
type: 'property',
|
||||
})),
|
||||
};
|
||||
const response = await getOperator();
|
||||
if (response.status === 200) {
|
||||
data.value = [properties, ...response.result];
|
||||
dataRef.value = [properties, ...response.result];
|
||||
}
|
||||
};
|
||||
|
||||
watch(() => props.id,
|
||||
(val) => {
|
||||
getData(val)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.border {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<Editor key="simple" @change="change" v-model:value="_value" :id="id" />
|
||||
{{ ruleEditorStore.state.model }}
|
||||
<Advance v-if="ruleEditorStore.state.model === 'advance'" :model="ruleEditorStore.state.model"
|
||||
{{ _value }}
|
||||
<Advance v-if="ruleEditorStore.state.model === 'advance'" v-model:value="_value" :model="ruleEditorStore.state.model"
|
||||
:virtualRule="virtualRule" :id="id" @change="change" />
|
||||
</template>
|
||||
<script setup lang="ts" name="FRuleEditor">
|
||||
|
|
|
@ -87,7 +87,7 @@ const handleEdit = (index: number) => {
|
|||
}
|
||||
const handleDelete = (index: number) => {
|
||||
editIndex.value = -1
|
||||
_value.value.slice(index, 1)
|
||||
_value.value.splice(index, 1)
|
||||
}
|
||||
const handleClose = () => {
|
||||
editIndex.value = -1
|
||||
|
|
|
@ -1,11 +1,40 @@
|
|||
<template>
|
||||
<a-form-item :name="name.concat(['script'])">
|
||||
<f-rule-editor v-model:value="value.script" :id="id" ></f-rule-editor>
|
||||
<f-rule-editor v-model:value="value.script" :id="id"></f-rule-editor>
|
||||
</a-form-item>
|
||||
<template v-if="showWindow">
|
||||
<a-form-item label="规则配置" :name="name.concat(['isVirtualRule'])">
|
||||
<a-switch v-model:checked="value.isVirtualRule" :checked-value="true" :un-checked-value="false"
|
||||
@change="changeWindow"></a-switch>
|
||||
</a-form-item>
|
||||
<template v-if="value.isVirtualRule">
|
||||
<a-form-item label="窗口" :name="name.concat(['windowType'])" :rules="[
|
||||
{ required: true, message: '请选择窗口' },
|
||||
]">
|
||||
<a-select v-model:value="value.windowType" :options="windowTypeEnum" size="small" allow-clear></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="聚合函数" :name="name.concat(['aggType'])" :rules="[
|
||||
{ required: true, message: '请选择聚合函数' },
|
||||
]">
|
||||
<a-select v-model:value="value.aggType" :options="aggTypeOptions" size="small" allow-clear></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item :label="spanLabel" :name="name.concat(['window', 'span'])" :rules="[
|
||||
{ required: true, message: '请输入窗口长度' },
|
||||
]">
|
||||
<a-input-number v-model:value="value.window.span" size="small" style="width: 100%;"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item :label="everyLabel" :name="name.concat(['window', 'every'])" :rules="[
|
||||
{ required: true, message: '请输入步长' },
|
||||
]">
|
||||
<a-input-number v-model:value="value.window.every" size="small" style="width: 100%;"></a-input-number>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<script setup lang="ts" name="VirtualRuleParam">
|
||||
import { PropType } from 'vue';
|
||||
import FRuleEditor from '@/components/FRuleEditor/index.vue'
|
||||
import { getStreamingAggType } from '@/api/device/product'
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
|
@ -18,7 +47,11 @@ const props = defineProps({
|
|||
type: Array as PropType<string[]>,
|
||||
default: () => ([])
|
||||
},
|
||||
id: String
|
||||
id: String,
|
||||
showWindow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
interface Emits {
|
||||
|
@ -32,5 +65,54 @@ onMounted(() => {
|
|||
type: 'script'
|
||||
})
|
||||
})
|
||||
|
||||
const aggTypeOptions = ref()
|
||||
const getAggTypeList = async () => {
|
||||
aggTypeOptions.value = await getStreamingAggType().then((resp) =>
|
||||
resp.result.map((item: any) => ({
|
||||
label: `${item.value}(${item.text})`,
|
||||
value: item.value,
|
||||
})),
|
||||
);
|
||||
}
|
||||
getAggTypeList()
|
||||
|
||||
const changeWindow = (val: boolean | string | number) => {
|
||||
if (val as boolean) {
|
||||
props.value.type = 'window'
|
||||
if (!props.value.window) {
|
||||
props.value.window = {}
|
||||
}
|
||||
} else {
|
||||
delete props.value.type
|
||||
}
|
||||
}
|
||||
|
||||
const windowTypeEnum = [
|
||||
{ label: '时间窗口', value: 'time' },
|
||||
{ label: '次数窗口', value: 'num' },
|
||||
]
|
||||
|
||||
const spanLabel = computed(() => {
|
||||
switch(props.value.windowType) {
|
||||
case 'time':
|
||||
return '窗口长度(秒)';
|
||||
case 'num':
|
||||
return '窗口长度(次)';
|
||||
default:
|
||||
return '窗口长度'
|
||||
}
|
||||
})
|
||||
|
||||
const everyLabel = computed(() => {
|
||||
switch(props.value.windowType) {
|
||||
case 'time':
|
||||
return '步长(秒)';
|
||||
case 'num':
|
||||
return '步长(次)';
|
||||
default:
|
||||
return '步长'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
|
@ -90,6 +90,11 @@ const insert = (val) => {
|
|||
]);
|
||||
}
|
||||
|
||||
watch(() => props.value,
|
||||
(val) => {
|
||||
instance.setValue(val)
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
editorFormat,
|
||||
insert,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class='JSearch-warp' ref='searchRef'>
|
||||
<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]'>
|
||||
|
@ -94,6 +94,10 @@ const props = defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -235,7 +239,7 @@ const reset = () => {
|
|||
urlParams.target = null
|
||||
}
|
||||
resetNumber.value += 1
|
||||
emit('search', terms)
|
||||
emit('search', { terms: []})
|
||||
}
|
||||
|
||||
watch(width, (value) => {
|
||||
|
@ -375,10 +379,10 @@ handleItems()
|
|||
|
||||
&.simple {
|
||||
.JSearch-items {
|
||||
flex-grow: 4;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.JSearch-footer {
|
||||
flex-grow: 3;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
<template>
|
||||
<div class="title">
|
||||
<div class="title" :style='style'>
|
||||
<div class="title-before"></div>
|
||||
<span>{{ data }}</span>
|
||||
<slot name="extra"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TitleComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
<script setup lang='ts' name='TitleComponent'>
|
||||
import type { CSSProperties, PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
};
|
||||
style: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -67,66 +67,116 @@ const defaultOptions = {
|
|||
],
|
||||
};
|
||||
|
||||
export const useSceneStore = defineStore({
|
||||
id: 'scene',
|
||||
state: (): DataType => {
|
||||
return {
|
||||
data: {
|
||||
trigger: { type: ''},
|
||||
options: defaultOptions,
|
||||
branches: defaultBranches,
|
||||
description: ''
|
||||
},
|
||||
productCache: {}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
initData() {
|
||||
export const useSceneStore = defineStore('scene', () => {
|
||||
const data = reactive<FormModelType | any>({
|
||||
trigger: { type: ''},
|
||||
options: defaultOptions,
|
||||
branches: defaultBranches,
|
||||
description: '',
|
||||
name: '',
|
||||
id: undefined
|
||||
})
|
||||
const productCache = {}
|
||||
|
||||
},
|
||||
/**
|
||||
* 获取详情
|
||||
* @param id
|
||||
*/
|
||||
async getDetail(id: string) {
|
||||
const resp = await detail(id)
|
||||
if (resp.success) {
|
||||
const result = resp.result as SceneItem
|
||||
const triggerType = result.triggerType
|
||||
let branches: any[] = result.branches
|
||||
const getDetail = async (id: string) => {
|
||||
const resp = await detail(id)
|
||||
if (resp.success) {
|
||||
const result = resp.result as SceneItem
|
||||
const triggerType = result.triggerType
|
||||
let branches: any[] = result.branches
|
||||
|
||||
if (!branches) {
|
||||
branches = cloneDeep(defaultBranches)
|
||||
if (triggerType === 'device') {
|
||||
branches.push(null)
|
||||
}
|
||||
} else {
|
||||
const branchesLength = branches.length;
|
||||
if (
|
||||
triggerType === 'device' &&
|
||||
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
||||
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
||||
) {
|
||||
branches.push(null);
|
||||
}
|
||||
if (!branches) {
|
||||
branches = cloneDeep(defaultBranches)
|
||||
if (triggerType === 'device') {
|
||||
branches.push(null)
|
||||
}
|
||||
|
||||
this.data = {
|
||||
...result,
|
||||
trigger: result.trigger || {},
|
||||
branches: cloneDeep(assignmentKey(branches)),
|
||||
options: {...defaultOptions, ...result.options },
|
||||
} else {
|
||||
const branchesLength = branches.length;
|
||||
if (
|
||||
triggerType === 'device' &&
|
||||
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
||||
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
||||
) {
|
||||
branches.push(null);
|
||||
}
|
||||
}
|
||||
},
|
||||
getProduct() {
|
||||
|
||||
Object.assign(data, {
|
||||
...result,
|
||||
trigger: result.trigger || {},
|
||||
branches: cloneDeep(assignmentKey(branches)),
|
||||
options: result.options ? {...defaultOptions, ...result.options } : defaultOptions,
|
||||
})
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
data,
|
||||
productCache,
|
||||
getDetail
|
||||
}
|
||||
})
|
||||
//
|
||||
// export const useSceneStore = defineStore({
|
||||
// id: 'scene',
|
||||
// state: (): DataType => {
|
||||
// return {
|
||||
// data: {
|
||||
// trigger: { type: ''},
|
||||
// options: defaultOptions,
|
||||
// branches: defaultBranches,
|
||||
// description: ''
|
||||
// },
|
||||
// productCache: {}
|
||||
// }
|
||||
// },
|
||||
// actions: {
|
||||
// /**
|
||||
// * 初始化数据
|
||||
// */
|
||||
// initData() {
|
||||
//
|
||||
// },
|
||||
// /**
|
||||
// * 获取详情
|
||||
// * @param id
|
||||
// */
|
||||
// async getDetail(id: string) {
|
||||
// const resp = await detail(id)
|
||||
// if (resp.success) {
|
||||
// const result = resp.result as SceneItem
|
||||
// const triggerType = result.triggerType
|
||||
// let branches: any[] = result.branches
|
||||
//
|
||||
// if (!branches) {
|
||||
// branches = cloneDeep(defaultBranches)
|
||||
// if (triggerType === 'device') {
|
||||
// branches.push(null)
|
||||
// }
|
||||
// } else {
|
||||
// const branchesLength = branches.length;
|
||||
// if (
|
||||
// triggerType === 'device' &&
|
||||
// ((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
||||
// (branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
||||
// ) {
|
||||
// branches.push(null);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// this.data = {
|
||||
// ...result,
|
||||
// trigger: result.trigger || {},
|
||||
// branches: cloneDeep(assignmentKey(branches)),
|
||||
// options: {...defaultOptions, ...result.options },
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// getProduct() {
|
||||
//
|
||||
// }
|
||||
// },
|
||||
// getters: {
|
||||
//
|
||||
// }
|
||||
// })
|
|
@ -1,5 +1,6 @@
|
|||
import type { Slots } from 'vue'
|
||||
import { TOKEN_KEY } from '@/utils/variable'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
/**
|
||||
* 静态图片资源处理
|
||||
|
@ -95,4 +96,16 @@ export const modifySearchColumnValue = (e: any, column: object) => {
|
|||
});
|
||||
});
|
||||
return e;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 仅提示一次的message
|
||||
* @param msg 消息内容
|
||||
* @param type 消息类型
|
||||
*/
|
||||
export const onlyMessage = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||
message[type]({
|
||||
content: msg,
|
||||
key: type
|
||||
})
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 座机号+手机号校验
|
||||
* @param value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const phoneRegEx = (value: string) => {
|
||||
const phone = new RegExp('^(((\\+86)|(\\+86-))|((86)|(86\\-))|((0086)|(0086\\-)))?1[3|5|7|8]\\d{9}$')
|
||||
const mobile = /(0[0-9]{2,3})([2-9][0-9]{6,7})+([0-9]{8,11})?$/
|
||||
return phone.test(value) || mobile.test(value)
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<a-card class="device-product">
|
||||
<Search
|
||||
:columns="query.columns"
|
||||
target="product-manage"
|
||||
|
@ -163,7 +162,6 @@
|
|||
:title="title"
|
||||
@success="refresh"
|
||||
/>
|
||||
</a-card>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
]">
|
||||
<a-select v-model:value="_value.source" :options="PropertySource" size="small" :disabled="metadataStore.model.action === 'edit'"></a-select>
|
||||
</a-form-item>
|
||||
<virtual-rule-param v-if="_value.source === 'rule'" v-model:value="_value.virtualRule" :name="name.concat(['virtualRule'])" :id="id"></virtual-rule-param>
|
||||
<virtual-rule-param v-if="_value.source === 'rule'" v-model:value="_value.virtualRule" :name="name.concat(['virtualRule'])" :id="id" :showWindow="_value.source === 'rule'"></virtual-rule-param>
|
||||
<a-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
|
||||
{ required: true, message: '请选择读写类型' },
|
||||
]">
|
||||
|
|
|
@ -258,12 +258,11 @@
|
|||
placeholder="请输入说明"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ offset: 0, span: 3 }">
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
:loading="btnLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
|
|
|
@ -329,8 +329,6 @@ const getActions = (
|
|||
},
|
||||
icon: 'EditOutlined',
|
||||
onClick: () => {
|
||||
// visible.value = true;
|
||||
// current.value = data;
|
||||
menuStory.jumpPage('notice/Config/Detail', {
|
||||
id: data.id,
|
||||
});
|
||||
|
|
|
@ -51,11 +51,30 @@
|
|||
<a-form-item
|
||||
:name="['templateDetailTable', index, 'value']"
|
||||
:rules="{
|
||||
required: true,
|
||||
required: record.required,
|
||||
message: '该字段为必填字段',
|
||||
}"
|
||||
>
|
||||
<ToUser
|
||||
v-if="record.type === 'user'"
|
||||
v-model:toUser="record.value"
|
||||
:type="data.type"
|
||||
:config-id="formData.configId"
|
||||
/>
|
||||
<ToOrg
|
||||
v-else-if="record.type === 'org'"
|
||||
:type="data.type"
|
||||
:config-id="formData.configId"
|
||||
v-model:toParty="record.value"
|
||||
/>
|
||||
<ToTag
|
||||
v-else-if="record.type === 'tag'"
|
||||
:type="data.type"
|
||||
:config-id="formData.configId"
|
||||
v-model:toTag="record.value"
|
||||
/>
|
||||
<ValueItem
|
||||
v-else
|
||||
v-model:modelValue="record.value"
|
||||
:itemType="record.type"
|
||||
/>
|
||||
|
@ -78,6 +97,9 @@ import type {
|
|||
} from '@/views/notice/Template/types';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import ToUser from '../Detail/components/ToUser.vue';
|
||||
import ToOrg from '../Detail/components/ToOrg.vue';
|
||||
import ToTag from '../Detail/components/ToTag.vue';
|
||||
|
||||
type Emits = {
|
||||
(e: 'update:visible', data: boolean): void;
|
||||
|
@ -110,7 +132,8 @@ const getConfigList = async () => {
|
|||
};
|
||||
const { result } = await TemplateApi.getConfig(params);
|
||||
configList.value = result;
|
||||
formData.value.configId = result[0]?.id;
|
||||
// 设置默认配置
|
||||
if (configList.value.length) formData.value.configId = props.data.configId;
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -131,6 +154,7 @@ const getTemplateDetail = async () => {
|
|||
formData.value.templateDetailTable = result.variableDefinitions.map(
|
||||
(m: any) => ({
|
||||
...m,
|
||||
type: m.expands ? m.expands.businessType : m.type,
|
||||
value: undefined,
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -27,11 +27,17 @@ const _value = computed({
|
|||
get: () => props.toParty,
|
||||
set: (val: string) => emit('update:toParty', val),
|
||||
});
|
||||
|
||||
const typeObj = {
|
||||
weixin: 'wechat',
|
||||
dingTalk: 'dingtalk',
|
||||
};
|
||||
const options = ref([]);
|
||||
const queryData = async () => {
|
||||
if (!props.configId) return;
|
||||
const { result } = await templateApi.getDept(props.type, props.configId);
|
||||
const { result } = await templateApi.getDept(
|
||||
typeObj[props.type],
|
||||
props.configId,
|
||||
);
|
||||
options.value = result.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
|
|
|
@ -28,10 +28,17 @@ const _value = computed({
|
|||
set: (val: string) => emit('update:toUser', val),
|
||||
});
|
||||
|
||||
const typeObj = {
|
||||
weixin: 'wechat',
|
||||
dingTalk: 'dingtalk',
|
||||
};
|
||||
const options = ref([]);
|
||||
const queryData = async () => {
|
||||
if (!props.configId) return;
|
||||
const { result } = await templateApi.getUser(props.type, props.configId);
|
||||
const { result } = await templateApi.getUser(
|
||||
typeObj[props.type],
|
||||
props.configId,
|
||||
);
|
||||
options.value = result.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
formData.template.messageType
|
||||
"
|
||||
placeholder="请选择消息类型"
|
||||
@change="handleMessageTypeChange"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(
|
||||
|
@ -480,7 +481,11 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-form-item>
|
||||
<a-form-item
|
||||
v-bind="
|
||||
validateInfos['template.calledShowNumbers']
|
||||
"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
被叫显号
|
||||
|
@ -713,12 +718,11 @@
|
|||
placeholder="请输入说明"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ offset: 0, span: 3 }">
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
:loading="btnLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
|
@ -757,6 +761,8 @@ import ToTag from './components/ToTag.vue';
|
|||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { phoneRegEx } from '@/utils/validate';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
@ -801,7 +807,7 @@ const resetPublicFiles = () => {
|
|||
formData.value.configId = undefined;
|
||||
|
||||
if (
|
||||
formData.value.type === 'dingTalk' ||
|
||||
formData.value.provider === 'dingTalkMessage' ||
|
||||
formData.value.type === 'weixin'
|
||||
) {
|
||||
formData.value.template.toTag = undefined;
|
||||
|
@ -813,6 +819,7 @@ const resetPublicFiles = () => {
|
|||
if (formData.value.type === 'email')
|
||||
formData.value.template.toParty = undefined;
|
||||
// formData.value.description = '';
|
||||
formData.value.variableDefinitions = [];
|
||||
};
|
||||
|
||||
// 根据通知方式展示对应的字段
|
||||
|
@ -862,7 +869,14 @@ const formRules = ref({
|
|||
// 钉钉
|
||||
'template.agentId': [{ required: true, message: '请输入agentId' }],
|
||||
'template.messageType': [{ required: true, message: '请选择消息类型' }],
|
||||
'template.markdown.title': [{ required: true, message: '请输入标题' }],
|
||||
'template.markdown.title': [
|
||||
{ required: true, message: '请输入标题' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
'template.link.title': [
|
||||
{ required: true, message: '请输入标题' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
// 'template.url': [{ required: true, message: '请输入WebHook' }],
|
||||
// 微信
|
||||
// 'template.agentId': [{ required: true, message: '请输入agentId' }],
|
||||
|
@ -876,7 +890,21 @@ const formRules = ref({
|
|||
'template.signName': [{ required: true, message: '请输入签名' }],
|
||||
// webhook
|
||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
'template.message': [{ required: true, message: '请输入' }],
|
||||
'template.message': [
|
||||
{ required: true, message: '请输入' },
|
||||
{ max: 500, message: '最多可输入500个字符' },
|
||||
],
|
||||
'template.calledShowNumbers': [
|
||||
{
|
||||
trigger: 'blur',
|
||||
validator(_rule: Rule, value: string) {
|
||||
if (!phoneRegEx(value)) {
|
||||
return Promise.reject('请输入有效号码');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { resetFields, validate, validateInfos, clearValidate } = useForm(
|
||||
|
@ -884,39 +912,97 @@ const { resetFields, validate, validateInfos, clearValidate } = useForm(
|
|||
formRules.value,
|
||||
);
|
||||
|
||||
// 钉钉机器人markdown标题变量提取
|
||||
watch(
|
||||
() => formData.value.template.message,
|
||||
() => formData.value.template.markdown?.title,
|
||||
(val) => {
|
||||
if (!val) return;
|
||||
// 已经存在的变量
|
||||
const oldKey = formData.value.variableDefinitions?.map((m) => m.id);
|
||||
// 正则提取${}里面的值
|
||||
const pattern = /(?<=\$\{).*?(?=\})/g;
|
||||
const titleList = val.match(pattern)?.filter((f) => f);
|
||||
const newKey = [...new Set(titleList)];
|
||||
const result = newKey?.map((m) =>
|
||||
oldKey.includes(m)
|
||||
? formData.value.variableDefinitions.find(
|
||||
(item) => item.id === m,
|
||||
)
|
||||
: {
|
||||
id: m,
|
||||
name: '',
|
||||
type: 'string',
|
||||
format: '%s',
|
||||
},
|
||||
);
|
||||
formData.value.variableDefinitions = result as IVariableDefinitions[];
|
||||
variableReg(val);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
// 钉钉机器人link标题变量提取
|
||||
watch(
|
||||
() => formData.value.template.link?.title,
|
||||
(val) => {
|
||||
if (!val) return;
|
||||
variableReg(val);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
// 邮件标题变量提取
|
||||
watch(
|
||||
() => formData.value.template.subject,
|
||||
(val) => {
|
||||
if (!val) return;
|
||||
variableReg(val);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// const clearValid = () => {
|
||||
// setTimeout(() => {
|
||||
// formData.value.variableDefinitions = [];
|
||||
// clearValidate();
|
||||
// }, 200);
|
||||
// };
|
||||
// 模板内容变量提取
|
||||
watch(
|
||||
() => formData.value.template.message,
|
||||
(val) => {
|
||||
if (!val) return;
|
||||
variableReg(val);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
// webhook请求体变量提取
|
||||
watch(
|
||||
() => formData.value.template.body,
|
||||
(val) => {
|
||||
if (!val) return;
|
||||
variableReg(val);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据字段输入内容, 提取变量
|
||||
* @param value
|
||||
*/
|
||||
const variableReg = (value: string) => {
|
||||
// 已经存在的变量
|
||||
const oldKey = formData.value.variableDefinitions?.map((m) => m.id);
|
||||
// 正则提取${}里面的值
|
||||
const pattern = /(?<=\$\{).*?(?=\})/g;
|
||||
const titleList = value.match(pattern)?.filter((f) => f);
|
||||
const newKey = [...new Set(titleList)];
|
||||
const result = newKey?.map((m) =>
|
||||
oldKey.includes(m)
|
||||
? formData.value.variableDefinitions.find((item) => item.id === m)
|
||||
: {
|
||||
id: m,
|
||||
name: '',
|
||||
type: 'string',
|
||||
format: '%s',
|
||||
},
|
||||
);
|
||||
formData.value.variableDefinitions = [
|
||||
...new Set([
|
||||
...formData.value.variableDefinitions,
|
||||
...(result as IVariableDefinitions[]),
|
||||
]),
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* 钉钉机器人 消息类型选择改变
|
||||
*/
|
||||
const handleMessageTypeChange = () => {
|
||||
formData.value.variableDefinitions = [];
|
||||
formData.value.template.message = '';
|
||||
if (formData.value.template.link) {
|
||||
formData.value.template.link.title = '';
|
||||
formData.value.template.link.picUrl = '';
|
||||
formData.value.template.link.messageUrl = '';
|
||||
}
|
||||
if (formData.value.template.markdown) {
|
||||
formData.value.template.markdown.title = '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
|
@ -961,7 +1047,6 @@ const handleTypeChange = () => {
|
|||
const handleProviderChange = () => {
|
||||
formData.value.template =
|
||||
TEMPLATE_FIELD_MAP[formData.value.type][formData.value.provider];
|
||||
console.log('formData.value.template: ', formData.value.template);
|
||||
getConfigList();
|
||||
resetPublicFiles();
|
||||
};
|
||||
|
@ -1023,29 +1108,32 @@ const handleSubmit = () => {
|
|||
if (formData.value.template.messageType === 'link')
|
||||
delete formData.value.template.markdown;
|
||||
// console.log('formData.value: ', formData.value);
|
||||
validate()
|
||||
.then(async () => {
|
||||
formData.value.template.ttsCode =
|
||||
formData.value.template.templateCode;
|
||||
btnLoading.value = true;
|
||||
let res;
|
||||
if (!formData.value.id) {
|
||||
res = await templateApi.save(formData.value);
|
||||
} else {
|
||||
res = await templateApi.update(formData.value);
|
||||
}
|
||||
// console.log('res: ', res);
|
||||
if (res?.success) {
|
||||
message.success('保存成功');
|
||||
router.back();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err: ', err);
|
||||
})
|
||||
.finally(() => {
|
||||
btnLoading.value = false;
|
||||
});
|
||||
// 提交必填验证无法通过, 实际已有值, 问题未知, 暂时解决方法: 延迟验证
|
||||
setTimeout(() => {
|
||||
validate()
|
||||
.then(async () => {
|
||||
formData.value.template.ttsCode =
|
||||
formData.value.template.templateCode;
|
||||
btnLoading.value = true;
|
||||
let res;
|
||||
if (!formData.value.id) {
|
||||
res = await templateApi.save(formData.value);
|
||||
} else {
|
||||
res = await templateApi.update(formData.value);
|
||||
}
|
||||
// console.log('res: ', res);
|
||||
if (res?.success) {
|
||||
message.success('保存成功');
|
||||
router.back();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err: ', err);
|
||||
})
|
||||
.finally(() => {
|
||||
btnLoading.value = false;
|
||||
});
|
||||
}, 200);
|
||||
};
|
||||
|
||||
// test
|
||||
|
|
|
@ -114,6 +114,14 @@
|
|||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<span v-if="column.dataIndex === 'type'">
|
||||
{{ getMethodTxt(record.type) }}
|
||||
</span>
|
||||
<span v-if="column.dataIndex === 'provider'">
|
||||
{{ getProviderTxt(record.type, record.provider) }}
|
||||
</span>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
|
@ -159,9 +167,9 @@
|
|||
<script setup lang="ts">
|
||||
import TemplateApi from '@/api/notice/template';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { getImage, LocalStore } from '@/utils/comm';
|
||||
// import { getImage, LocalStore } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
// import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
|
||||
import { NOTICE_METHOD, MSG_TYPE } from '@/views/notice/const';
|
||||
|
||||
|
@ -254,6 +262,14 @@ const getLogo = (type: string, provider: string) => {
|
|||
const getMethodTxt = (type: string) => {
|
||||
return NOTICE_METHOD.find((f) => f.value === type)?.label;
|
||||
};
|
||||
/**
|
||||
* 根据类型展示对应文案
|
||||
* @param type
|
||||
* @param provider
|
||||
*/
|
||||
const getProviderTxt = (type: string, provider: string) => {
|
||||
return MSG_TYPE[type].find((f: any) => f.value === provider)?.label;
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增
|
||||
|
@ -301,13 +317,6 @@ const handleExport = () => {
|
|||
downloadObject(configRef.value.dataSource, `通知配置`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
const handleView = (id: string) => {
|
||||
message.warn(id + '暂未开发');
|
||||
};
|
||||
|
||||
const syncVis = ref(false);
|
||||
const debugVis = ref(false);
|
||||
const logVis = ref(false);
|
||||
|
@ -326,8 +335,6 @@ const getActions = (
|
|||
},
|
||||
icon: 'EditOutlined',
|
||||
onClick: () => {
|
||||
// visible.value = true;
|
||||
// current.value = data;
|
||||
menuStory.jumpPage('notice/Template/Detail', {
|
||||
id: data.id,
|
||||
});
|
||||
|
|
|
@ -0,0 +1,434 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<div>
|
||||
<Search
|
||||
:columns="query.columns"
|
||||
target="device-instance"
|
||||
@search="handleSearch"
|
||||
></Search>
|
||||
<JTable
|
||||
:columns="columns"
|
||||
:request="queryList"
|
||||
ref="tableRef"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="add"
|
||||
><plus-outlined />新增</a-button
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img
|
||||
:src="getImage('/alarm/alarm-config.png')"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3 style="font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="content-des-title">
|
||||
关联场景联动
|
||||
</div>
|
||||
<div class="rule-desc">
|
||||
{{ (slotProps?.scene || []).map((item: any) => item?.name).join(',') || '' }}
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<div class="content-des-title">
|
||||
告警级别
|
||||
</div>
|
||||
<div class="rule-desc">
|
||||
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
|
||||
slotProps.level }}
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<a-tooltip
|
||||
v-bind="item.tooltip"
|
||||
:title="item.disabled && item.tooltip.title"
|
||||
v-if="
|
||||
item.key != 'trigger' ||
|
||||
slotProps.sceneTriggerType == 'manual'
|
||||
"
|
||||
>
|
||||
<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>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #targetType="slotProps">
|
||||
<span>{{ map[slotProps.targetType] }}</span>
|
||||
</template>
|
||||
<template #level="slotProps">
|
||||
<a-tooltip
|
||||
placement="topLeft"
|
||||
:title="(Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
|
||||
slotProps.level"
|
||||
>
|
||||
<div class="ellipsis">
|
||||
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
|
||||
slotProps.level }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #sceneId="slotProps">
|
||||
<span
|
||||
>{{(slotProps?.scene || []).map((item: any) => item?.name).join(',') || ''}}</span
|
||||
>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<a-badge
|
||||
:text="
|
||||
slotProps.state?.value === 'enabled'
|
||||
? '正常'
|
||||
: '禁用'
|
||||
"
|
||||
:status="
|
||||
slotProps.state?.value === 'enabled'
|
||||
? 'success'
|
||||
: 'error'
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
v-for="i in getActions(slotProps)"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<span
|
||||
v-if="
|
||||
i.key != 'trigger' ||
|
||||
slotProps.sceneTriggerType == 'manual'
|
||||
"
|
||||
>
|
||||
<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>
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import JTable from '@/components/Table';
|
||||
import {
|
||||
queryList,
|
||||
_enable,
|
||||
_disable,
|
||||
remove,
|
||||
_execute,
|
||||
} from '@/api/rule-engine/configuration';
|
||||
import { queryLevel } from '@/api/rule-engine/config';
|
||||
import { Store } from 'jetlinks-store';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
const params = ref<Record<string, any>>({});
|
||||
let isAdd = ref<number>(0);
|
||||
let title = ref<string>('');
|
||||
const tableRef = ref<Record<string, any>>({});
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'targetType',
|
||||
key: 'targetType',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '告警级别',
|
||||
dataIndex: 'level',
|
||||
key: 'level',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '关联场景联动',
|
||||
dataIndex: 'sceneId',
|
||||
wdith: 250,
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
width: 150,
|
||||
scopedSlots: true,
|
||||
},
|
||||
];
|
||||
const map = {
|
||||
product: '产品',
|
||||
device: '设备',
|
||||
org: '组织',
|
||||
other: '其他',
|
||||
};
|
||||
const query = {
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 'enabled',
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 'disabled',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
key: 'description',
|
||||
dataIndex: 'description',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const handleSearch = (e: any) => {
|
||||
params.value = e;
|
||||
};
|
||||
const queryDefaultLevel = () => {
|
||||
queryLevel().then((res) => {
|
||||
if (res.status === 200) {
|
||||
Store.set('default-level', res.result?.levels || []);
|
||||
}
|
||||
});
|
||||
};
|
||||
queryDefaultLevel();
|
||||
const getActions = (
|
||||
data: Partial<Record<string, any>>,
|
||||
type?: 'card' | 'table',
|
||||
): ActionsType[] => {
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
const actions = [
|
||||
{
|
||||
key: 'trigger',
|
||||
text: '手动触发',
|
||||
disabled: data?.state?.value === 'disabled',
|
||||
tooltip: {
|
||||
title:
|
||||
data?.state?.value === 'disabled'
|
||||
? '未启用,不能手动触发'
|
||||
: '手动触发',
|
||||
},
|
||||
popConfirm: {
|
||||
title: '确定手动触发?',
|
||||
onConfirm: async () => {
|
||||
const scene = (data.scene || [])
|
||||
.filter((item: any) => item?.triggerType === 'manual')
|
||||
.map((i) => {
|
||||
return { id: i?.id };
|
||||
});
|
||||
_execute(scene).then((res) => {
|
||||
if (res.status === 200) {
|
||||
message.success('操作成功');
|
||||
tableRef.value?.reload();
|
||||
} else {
|
||||
message.error('操作失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
icon: 'LikeOutlined',
|
||||
},
|
||||
{
|
||||
key: 'edit',
|
||||
text: '编辑',
|
||||
tooltip: {
|
||||
title: '编辑',
|
||||
},
|
||||
|
||||
icon: 'EditOutlined',
|
||||
onClick: () => {
|
||||
title.value = '编辑';
|
||||
isAdd.value = 2;
|
||||
nextTick(() => {});
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
text: data.state?.value !== 'disabled' ? '禁用' : '启用',
|
||||
tooltip: {
|
||||
title: data.state?.value !== 'disabled' ? '禁用' : '启用',
|
||||
},
|
||||
icon:
|
||||
data.state?.value !== 'disabled'
|
||||
? 'StopOutlined'
|
||||
: 'CheckCircleOutlined',
|
||||
popConfirm: {
|
||||
title: `${
|
||||
data.state?.value !== 'disabled'
|
||||
? '禁用告警不会影响关联的场景状态,确定要禁用吗'
|
||||
: '确认启用'
|
||||
}?`,
|
||||
onConfirm: async () => {
|
||||
let response = undefined;
|
||||
if (data.state?.value === 'disabled') {
|
||||
response = await _enable(data.id);
|
||||
} else {
|
||||
response = await _disable(data.id);
|
||||
}
|
||||
if (response && response.status === 200) {
|
||||
message.success('操作成功!');
|
||||
tableRef.value?.reload();
|
||||
} else {
|
||||
message.error('操作失败!');
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
text: '删除',
|
||||
disabled: data?.state?.value !== 'disabled',
|
||||
tooltip: {
|
||||
title:
|
||||
data?.state?.value !== 'disabled'
|
||||
? '请先禁用该告警,再删除'
|
||||
: '删除',
|
||||
},
|
||||
popConfirm: {
|
||||
title: '确认删除?',
|
||||
onConfirm: async () => {
|
||||
const resp = await remove(data.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
tableRef.value?.reload();
|
||||
} else {
|
||||
message.error('操作失败!');
|
||||
}
|
||||
},
|
||||
},
|
||||
icon: 'DeleteOutlined',
|
||||
},
|
||||
];
|
||||
if (type === 'card')
|
||||
return actions.filter((i: ActionsType) => i.key !== 'view');
|
||||
return actions;
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.content-des-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
.rule-desc {
|
||||
white-space: nowrap; /*强制在同一行内显示所有文本,直到文本结束或者遭遇br标签对象才换行。*/
|
||||
overflow: hidden; /*超出部分隐藏*/
|
||||
text-overflow: ellipsis; /*隐藏部分以省略号代替*/
|
||||
}
|
||||
</style>
|
|
@ -193,6 +193,14 @@ const query = {
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
key: 'description',
|
||||
dataIndex: 'description',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const columns = [
|
||||
|
@ -320,7 +328,6 @@ const refresh = () => {
|
|||
tableRef.value?.reload();
|
||||
};
|
||||
const handleSearch = (e: any) => {
|
||||
console.log(e);
|
||||
params.value = e;
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
<template>
|
||||
<a-modal
|
||||
title='触发规则'
|
||||
visible
|
||||
:width='820'
|
||||
@click='save'
|
||||
@cancel='cancel'
|
||||
>
|
||||
<a-steps :current='addModel.stepNumber'>
|
||||
<a-step>
|
||||
<template #title>选择产品</template>
|
||||
</a-step>
|
||||
<a-step>
|
||||
<template #title>选择设备</template>
|
||||
</a-step>
|
||||
<a-step>
|
||||
<template #title>触发类型</template>
|
||||
</a-step>
|
||||
</a-steps>
|
||||
<div class='steps-content'>
|
||||
<Product :rowKey='addModel.productId' />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class='steps-action'>
|
||||
<template>
|
||||
<a-button v-if='addModel.stepNumber === 0' @click='cancel'>取消</a-button>
|
||||
<a-button v-else>上一步</a-button>
|
||||
</template>
|
||||
<template>
|
||||
<a-button type='primary' v-if='addModel.stepNumber < 2'>下一步</a-button>
|
||||
<a-button type='primary' v-else>确定</a-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='AddModel'>
|
||||
import type { PropType } from 'vue'
|
||||
import { TriggerDevice } from '@/views/rule-engine/Scene/typings'
|
||||
import { onlyMessage } from '@/utils/comm'
|
||||
import { detail as deviceDetail } from '@/api/device/instance'
|
||||
import Product from './Product.vue'
|
||||
|
||||
type Emit = {
|
||||
(e: 'cancel'): void
|
||||
(e: 'update:value', data: TriggerDevice): void
|
||||
(e: 'update:options', data: any): void
|
||||
}
|
||||
|
||||
interface AddModelType extends Omit<TriggerDevice, 'selectorValues'> {
|
||||
stepNumber: number
|
||||
deviceKeys: Array<{ label: string, value: string }>
|
||||
orgId: Array<{ label: string, value: string }>
|
||||
productDetail: any
|
||||
selectorValues: Array<{ label: string, value: string }>
|
||||
metadata: {
|
||||
properties?: any[]
|
||||
functions?: any[]
|
||||
events?: any[]
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: Object as PropType<TriggerDevice>,
|
||||
default: () => ({
|
||||
productId: '',
|
||||
selector: 'fixed',
|
||||
selectorValues: [],
|
||||
})
|
||||
},
|
||||
options: {
|
||||
type: Object as PropType<any>,
|
||||
default: () => ({
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const addModel = reactive<AddModelType>({
|
||||
productId: '',
|
||||
selector: 'fixed',
|
||||
selectorValues: [],
|
||||
stepNumber: 0,
|
||||
deviceKeys: [],
|
||||
orgId: [],
|
||||
productDetail: {},
|
||||
metadata: {}
|
||||
})
|
||||
|
||||
Object.assign(addModel, props.value)
|
||||
|
||||
const handleOptions = () => {
|
||||
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emit("cancel")
|
||||
}
|
||||
|
||||
const handleMetadata = (metadata: string) => {
|
||||
try {
|
||||
addModel.metadata = JSON.parse(metadata)
|
||||
} catch (e) {
|
||||
console.warn('handleMetadata: ' + e)
|
||||
}
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
if (addModel.stepNumber === 0) {
|
||||
addModel.productId ? addModel.stepNumber = 1 : onlyMessage('请选择产品', 'error')
|
||||
} else if (addModel.stepNumber === 1) {
|
||||
const isFixed = addModel.selector === 'fixed' // 是否选择方式为设备
|
||||
if ((['fixed', 'org'].includes(addModel.selector) ) && addModel.selectorValues?.length) {
|
||||
return onlyMessage(isFixed ? '请选择设备' : '请选择部门', 'error')
|
||||
}
|
||||
// 选择方式为设备且仅选中一个设备时,物模型取该设备
|
||||
if (isFixed && addModel.selectorValues?.length === 1) {
|
||||
const resp = await deviceDetail(addModel.selectorValues[0].value)
|
||||
addModel.metadata
|
||||
} else {
|
||||
|
||||
}
|
||||
//
|
||||
}
|
||||
// handleOptions()
|
||||
// emit('update:value', {})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,234 @@
|
|||
<template>
|
||||
<Search
|
||||
:columns="columns"
|
||||
type='simple'
|
||||
@search="handleSearch"
|
||||
class='search'
|
||||
/>
|
||||
<j-table
|
||||
:columns='columns'
|
||||
ref='actionRef'
|
||||
:request='productQuery'
|
||||
:gridColumn='2'
|
||||
model='CARD'
|
||||
>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value='slotProps'
|
||||
:active="selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.state"
|
||||
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
|
||||
:statusNames="{ 1: 'success', 0: 'error', }"
|
||||
@click="handleClick"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img :src="getImage('/device-product.png')" />
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3 style="font-weight: 600" >
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>直连设备</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
</j-table>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Product'>
|
||||
import { getProviders, queryGatewayList, queryProductList } from '@/api/device/product'
|
||||
import { queryTree } from '@/api/device/category'
|
||||
import { getTreeData_api } from '@/api/system/department'
|
||||
import { isNoCommunity } from '@/utils/utils'
|
||||
import { getImage } from '@/utils/comm'
|
||||
|
||||
const actionRef = ref()
|
||||
const params = ref({})
|
||||
const props = defineProps({
|
||||
rowKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const selectedRowKeys = ref(props.rowKey)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '网关类型',
|
||||
dataIndex: 'accessProvider',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () => getProviders().then((resp: any) => {
|
||||
if (isNoCommunity) {
|
||||
return (resp?.result || []).map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}))
|
||||
} else {
|
||||
return (resp?.result || []).filter((item: any) => [
|
||||
'mqtt-server-gateway',
|
||||
'http-server-gateway',
|
||||
'mqtt-client-gateway',
|
||||
'tcp-server-gateway',
|
||||
].includes(item.id))
|
||||
.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '接入方式',
|
||||
dataIndex: 'accessName',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () => queryGatewayList().then((resp: any) =>
|
||||
resp.result.map((item: any) => ({
|
||||
label: item.name, value: item.id
|
||||
}))
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '设备类型',
|
||||
dataIndex: 'deviceType',
|
||||
width: 150,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '直连设备', value: 'device' },
|
||||
{ label: '网关子设备', value: 'childrenDevice' },
|
||||
{ label: '网关设备', value: 'gateway' },
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
width: '90px',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '禁用', value: 0 },
|
||||
{ label: '正常', value: 1 },
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'describe',
|
||||
ellipsis: true,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
dataIndex: 'classifiedId',
|
||||
title: '分类',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
options: queryTree({ paging: false }).then(resp => resp.result),
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
dataIndex: 'id$dim-assets',
|
||||
title: '所属组织',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
options: getTreeData_api({ paging: false }).then((resp: any) => {
|
||||
const formatValue = (list: any[]) => {
|
||||
return list.map((item: any) => {
|
||||
if (item.children) {
|
||||
item.children = formatValue(item.children);
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
value: JSON.stringify({
|
||||
assetType: 'product',
|
||||
targets: [
|
||||
{
|
||||
type: 'org',
|
||||
id: item.id,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
return formatValue(resp.result)
|
||||
}),
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const handleSearch = (p: any) => {
|
||||
params.value = p
|
||||
actionRef.value.required()
|
||||
}
|
||||
|
||||
const productQuery = (p: any) => {
|
||||
const sorts: any = [];
|
||||
|
||||
if (props.rowKey) {
|
||||
sorts.push({
|
||||
name: 'id',
|
||||
value: props.rowKey,
|
||||
});
|
||||
}
|
||||
sorts.push({ name: 'createTime', order: 'desc' });
|
||||
p.sorts = sorts
|
||||
return queryProductList(p)
|
||||
}
|
||||
|
||||
const handleClick = (detail: any) => {
|
||||
const _selected = new Set(selectedRowKeys.value)
|
||||
if (_selected.has(detail.id)) {
|
||||
_selected.delete(detail.id)
|
||||
} else {
|
||||
_selected.add(detail.id)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div class='device'>
|
||||
<a-form-item
|
||||
:rules='rules'
|
||||
name='device'
|
||||
>
|
||||
<template #label>
|
||||
<TitleComponent data='触发规则' style='font-size: 14px;' />
|
||||
</template>
|
||||
<AddButton
|
||||
style='width: 100%'
|
||||
@click='visible = true'
|
||||
>
|
||||
<Title :options='data.options.trigger' />
|
||||
</AddButton>
|
||||
</a-form-item>
|
||||
<AddModel v-if='visible' @cancel='visible = false' v-model='data.device' v-model:options='data.options.trigger' />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='SceneSaveDevice'>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSceneStore } from '@/store/scene'
|
||||
import AddModel from './AddModal.vue'
|
||||
import AddButton from '../components/AddButton.vue'
|
||||
import Title from '../components/Title.vue'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data } = storeToRefs(sceneStore)
|
||||
const visible = ref(false)
|
||||
|
||||
const rules = [{
|
||||
validator(_: any, v: any) {
|
||||
if (!v) {
|
||||
return Promise.reject(new Error('请配置设备触发规则'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
}]
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'index'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'inex'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div class='rule-button-warp' :style='style'>
|
||||
<div class='rule-button add-button' @click='click'>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='AddButton'>
|
||||
import type { PropType, CSSProperties} from 'vue'
|
||||
|
||||
type Emit = {
|
||||
(e: 'click'): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
style: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const click = () => {
|
||||
emit('click')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.rule-button-warp {
|
||||
display: inline-block;
|
||||
padding: 14px 16px;
|
||||
background-color: #fafafa;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
.rule-button {
|
||||
display: inline-block;
|
||||
padding: 6px 20px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 22px;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
color: #bdbdbd;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div :class='["trigger-options-content", isAdd ? "is-add" : ""]'>
|
||||
<span v-if='!isAdd'> 点击配置设备触发 </span>
|
||||
<template v-else>
|
||||
<div class='center-item'>
|
||||
<AIcon v-if='options.selectorIcon' :type='options.selectorIcon' class='icon-padding-right' />
|
||||
<span class='trigger-options-name'>
|
||||
<Ellipsis style='width: 310px'>
|
||||
{{ options.name }}
|
||||
</Ellipsis>
|
||||
</span>
|
||||
<span v-if='options.extraName'>{{ options.extraName }}</span>
|
||||
</div>
|
||||
<template v-if='options.onlyName'>
|
||||
<div v-if='options.productName' class='center-item'>
|
||||
<AIcon type='icon-chanpin1' class='icon-padding-right' />
|
||||
<span className='trigger-options-type'>{{ options.productName }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if='options.when'>
|
||||
<span className='trigger-options-when'>{{ options.when }}</span>
|
||||
</div>
|
||||
<div v-if='options.time'>
|
||||
<span className='trigger-options-time'>{{ options.time }}</span>
|
||||
</div>
|
||||
<div v-if='options.extraTime'>
|
||||
<span className='trigger-options-extraTime'>{{ options.extraTime }}</span>
|
||||
</div>
|
||||
<div v-if='options.action' class='center-item'>
|
||||
<AIcon :type='options.typeIcon' class='icon-padding-right' />
|
||||
<span className='trigger-options-action'>{{ options.productName }}</span>
|
||||
</div>
|
||||
<div v-if='options.type' class='center-item'>
|
||||
<AIcon :type='options.typeIcon' class='icon-padding-right' />
|
||||
<span className='trigger-options-type'>{{ options.type }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='DeviceTitle'>
|
||||
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const isAdd = computed(() => {
|
||||
console.log(props.options, Object.keys(props.options).length)
|
||||
return !!Object.keys(props.options).length
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.trigger-options-content {
|
||||
|
||||
.center-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon-padding-right {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -2,14 +2,18 @@
|
|||
<page-container>
|
||||
<div class='scene-warp'>
|
||||
<div class='header'>
|
||||
|
||||
<Ellipsis :tooltip='data.name' style='max-width: 50%'>
|
||||
<span class='title'>{{ data.name }}</span>
|
||||
</Ellipsis>
|
||||
<div class='type'>
|
||||
<img :src='TriggerHeaderIcon[data.triggerType]' />
|
||||
{{ keyByLabel[data.triggerType] }}
|
||||
</div>
|
||||
</div>
|
||||
<a-form ref='sceneForm' :model='data'>
|
||||
|
||||
<a-form ref='sceneForm' :model='data' :colon='false' layout='vertical'>
|
||||
<Device v-if='data.triggerType === "device"' />
|
||||
<Manual v-else-if='data.triggerType === "manual"' />
|
||||
<Timer v-else-if='data.triggerType === "timer"' />
|
||||
</a-form>
|
||||
<PermissionButton
|
||||
type='primary'
|
||||
|
@ -17,19 +21,26 @@
|
|||
>
|
||||
保存
|
||||
</PermissionButton>
|
||||
<!-- <a-button type='primary' :loading='loading'>保存</a-button>-->
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Scene'>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSceneStore } from '@/store/scene'
|
||||
import { TriggerHeaderIcon } from './asstes'
|
||||
import { keyByLabel } from '../typings'
|
||||
import Device from './Device/index.vue'
|
||||
import Manual from './Manual/index.vue'
|
||||
import Timer from './Timer/index.vue'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data } = storeToRefs(sceneStore)
|
||||
const { getDetail } = sceneStore
|
||||
|
||||
const { getDetail, data } = useSceneStore()
|
||||
const route = useRoute();
|
||||
const loading = ref(false)
|
||||
console.log('data',data)
|
||||
|
||||
getDetail(route.query.id as string)
|
||||
|
||||
|
@ -45,17 +56,24 @@ getDetail(route.query.id as string)
|
|||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
color: rgba(#000, .8);
|
||||
font-weight: bold;
|
||||
}
|
||||
.type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 100px;
|
||||
min-width: 80px;
|
||||
margin-left: 16px;
|
||||
padding: 4px 8px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 2px;
|
||||
img {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
<template>
|
||||
<div class="does-container">
|
||||
<div v-show="props.type === 'internal-standalone'">
|
||||
<h1>1.概述</h1>
|
||||
<div>
|
||||
内部独立应用适用于将<span>官方开发</span>的其他应用与<span
|
||||
>物联网平台相互集成</span
|
||||
>
|
||||
,例如将可视化平台集成至物联网平台,或者将物联网平台集成至可视化平台。以实现多处访问、集中管控的业务场景。
|
||||
</div>
|
||||
<div>
|
||||
内部独立应用的<span>后端服务</span>相互<span>独立运行</span>,互不影响。
|
||||
</div>
|
||||
<div class="image">
|
||||
<a-image width="100%" :src="img1" />
|
||||
</div>
|
||||
|
||||
<h1>2.接入方式说明</h1>
|
||||
<div>1、页面集成</div>
|
||||
<div>
|
||||
集成其他应用的<span>前端页面</span>至物联网平台中。为实现应用与物联网平台数据互联互通,
|
||||
<span>通常还需要配置API服务</span>。
|
||||
</div>
|
||||
<div>2、API客户端</div>
|
||||
<div>
|
||||
<span>物联网平台</span>请求<span>其他应用</span>
|
||||
的接口,以实现将物联网平台集成至其他应用系统。如需实现<span
|
||||
>其他应用</span
|
||||
>
|
||||
登录后可以访问<span>物联网平台</span>页面,<span>还需要配置单点登录</span>。
|
||||
</div>
|
||||
<div>3、API服务</div>
|
||||
<div>
|
||||
<span>外部应用</span
|
||||
>请求<span>物联网平台</span>的接口,实现物联网平台的服务调用能力,
|
||||
<span>通常还需要配置页面集成</span>。
|
||||
</div>
|
||||
<div>
|
||||
配置API服务后,系统将<span>自动创建</span>对应的<span>“第三方应用”用户</span>。用户的
|
||||
<span>账号/密码</span>分别对应appid/secureKey。
|
||||
</div>
|
||||
<div>
|
||||
第三方用户<span>可调用的API服务</span>在其应用管理卡片的<span
|
||||
>其他-{'>'}赋权</span
|
||||
>
|
||||
页面,进行<span>自定义配置</span>。
|
||||
</div>
|
||||
<div>4、单点登录</div>
|
||||
<div>通过<span>第三方平台账号</span>登录到物联网平台。</div>
|
||||
</div>
|
||||
<div v-show="props.type === 'internal-integrated'">
|
||||
<h1>1.概述</h1>
|
||||
<div>
|
||||
内部集成应用适用于将<span>官方开发</span>的其他应用与<span
|
||||
>物联网平台相互集成</span
|
||||
>
|
||||
,例如将可视化平台集成至物联网平台,或者将物联网平台集成至可视化平台。以实现多处访问、集中管控的业务场景。
|
||||
</div>
|
||||
<div>内部独立应用的<span>后端服务在同一个环境运行</span>。</div>
|
||||
<div class="image">
|
||||
<a-image width="100%" :src="img2" />
|
||||
</div>
|
||||
<h1>2.接入方式说明</h1>
|
||||
<div>1、页面集成</div>
|
||||
<div>
|
||||
集成其他应用的<span>前端页面</span>
|
||||
至物联网平台中。集成后系统顶部将新增对应的应用管理菜单
|
||||
</div>
|
||||
<div>2、API客户端</div>
|
||||
<div>
|
||||
<span>物联网平台</span
|
||||
>去请求其他应用的接口,以实现将物联网平台集成至其他应用
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="props.type === 'dingtalk-ent-app'">
|
||||
<div class="url">
|
||||
钉钉开放平台:
|
||||
<a
|
||||
href="https://open-dev.dingtalk.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
https://open-dev.dingtalk.com
|
||||
</a>
|
||||
</div>
|
||||
<h1>1.概述</h1>
|
||||
<div>钉钉企业内部应用适用于通过钉钉登录<span>物联网平台</span></div>
|
||||
<div class="image">
|
||||
<a-image width="100%" :src="img4" />
|
||||
</div>
|
||||
<h1>2.接入方式说明</h1>
|
||||
<div>1、单点登录</div>
|
||||
<div>通过钉钉账号登录到物联网平台。</div>
|
||||
</div>
|
||||
<div v-show="props.type === 'wechat-webapp'">
|
||||
<div class="url">
|
||||
微信开放平台:
|
||||
<a
|
||||
href="https://open.weixin.qq.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
https://open.weixin.qq.com
|
||||
</a>
|
||||
</div>
|
||||
<h1>1.概述</h1>
|
||||
<div>微信网站应用适用于通过微信授权登录<span>物联网平台</span></div>
|
||||
<div class="image">
|
||||
<a-image width="100%" :src="img3" />
|
||||
</div>
|
||||
<h1>2.接入方式说明</h1>
|
||||
<div>1、单点登录</div>
|
||||
<div>通过微信账号登录到物联网平台。</div>
|
||||
</div>
|
||||
<div v-show="props.type === 'third-party'">
|
||||
<h1>1. 概述</h1>
|
||||
<div>
|
||||
第三方应用适用于<span>第三方应用</span>与<span
|
||||
>物联网平台相互集成</span
|
||||
>
|
||||
。例如将公司业务管理系统集成至物联网平台,或者将物联网平台集成至业务管理系统。以实现多处访问、集中管控的业务场景。
|
||||
</div>
|
||||
<div class="image">
|
||||
<a-image width="100%" :src="img5" />
|
||||
</div>
|
||||
<h1>2.接入方式说明</h1>
|
||||
<div>1、页面集成</div>
|
||||
<div>
|
||||
集成其他应用的<span>前端页面</span>至物联网平台中。为实现应用与物联网平台数据互联互通,
|
||||
<span>还需要配置API服务</span>。
|
||||
</div>
|
||||
<div>2、API客户端</div>
|
||||
<div>
|
||||
<span>物联网平台</span>请求<span>第三方应用</span>
|
||||
的接口,以实现将物联网平台集成至其他应用。如需实现<span>第三方应用</span>登录后可以访问
|
||||
<span>物联网平台</span>页面,<span>还需要配置单点登录</span>。
|
||||
</div>
|
||||
<div>3、API服务</div>
|
||||
<div>
|
||||
<span>第三方应用</span
|
||||
>通过API服务配置,请求物联网平台接口,实现<span
|
||||
>物联网平台</span
|
||||
>
|
||||
的服务调用能力,<span>通常还需要配置页面集成</span>。
|
||||
</div>
|
||||
<div>
|
||||
配置API服务后,系统将<span>自动创建</span>对应的<span>“第三方应用”用户</span>。用户的
|
||||
<span>账号/密码</span>分别对应appid/secureKey。
|
||||
</div>
|
||||
<div>
|
||||
第三方用户<span>可调用的API服务</span>在其应用管理卡片的<span
|
||||
>其他-{'>'}赋权</span
|
||||
>
|
||||
页面,进行<span>自定义配置</span>。
|
||||
</div>
|
||||
<div>4、单点登录</div>
|
||||
<div>通过<span>第三方平台账号</span>登录到物联网平台。</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getImage } from '@/utils/comm';
|
||||
import type { applyType } from '../typing';
|
||||
const props = defineProps<{
|
||||
type: applyType;
|
||||
}>();
|
||||
|
||||
const img1 = getImage('/apply/1.png');
|
||||
const img2 = getImage('/apply/2.png');
|
||||
const img3 = getImage('/apply/3.png');
|
||||
const img4 = getImage('/apply/4.png');
|
||||
const img5 = getImage('/apply/5.png');
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.does-container {
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
color: rgba(#000, 0.8);
|
||||
font-size: 14px;
|
||||
background-color: #fafafa;
|
||||
|
||||
.url {
|
||||
padding: 8px 16px;
|
||||
color: #2f54eb;
|
||||
background-color: rgba(#a7bdf7, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 16px 0;
|
||||
color: rgba(#000, 0.85);
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 6px 0;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.image {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div class="form-label-container">
|
||||
<span class="text">{{ props.text }}</span>
|
||||
<span class="required">*</span>
|
||||
<a-tooltip>
|
||||
<template #title>{{ props.tooltip }}</template>
|
||||
<AIcon type="QuestionCircleOutlined" style="color: #00000073;cursor: inherit;" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
text: string;
|
||||
tooltip: string;
|
||||
required?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.form-label-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.required {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
color: #ff4d4f;
|
||||
font-size: 14px;
|
||||
font-family: SimSun, sans-serif;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,505 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<a-card class="save-container">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="14">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form.data"
|
||||
layout="vertical"
|
||||
class="form"
|
||||
>
|
||||
<a-form-item label="名称" name="name">
|
||||
<a-input
|
||||
v-model:value="form.data.name"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="应用" name="provider">
|
||||
<a-radio-group
|
||||
v-model:value="form.data.provider"
|
||||
class="radio-container"
|
||||
@change="form.data.integrationModes = []"
|
||||
>
|
||||
<a-radio-button value="internal-standalone">
|
||||
<div>
|
||||
<a-image
|
||||
:preview="false"
|
||||
:src="
|
||||
getImage('/apply/provider1.png')
|
||||
"
|
||||
width="64px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>内部独立应用</p>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
<a-radio-button value="internal-integrated">
|
||||
<div>
|
||||
<a-image
|
||||
:preview="false"
|
||||
:src="
|
||||
getImage('/apply/provider2.png')
|
||||
"
|
||||
/>
|
||||
<p>内部集成应用</p>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
<a-radio-button value="wechat-webapp">
|
||||
<div>
|
||||
<a-image
|
||||
:preview="false"
|
||||
:src="
|
||||
getImage('/apply/provider3.png')
|
||||
"
|
||||
/>
|
||||
<p>微信网站应用</p>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
<a-radio-button value="dingtalk-ent-app">
|
||||
<div>
|
||||
<a-image
|
||||
:preview="false"
|
||||
:src="
|
||||
getImage('/apply/provider4.png')
|
||||
"
|
||||
/>
|
||||
<p>钉钉企业内部应用</p>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
<a-radio-button value="third-party">
|
||||
<div>
|
||||
<a-image
|
||||
:preview="false"
|
||||
:src="
|
||||
getImage('/apply/provider5.png')
|
||||
"
|
||||
/>
|
||||
<p>第三方应用</p>
|
||||
</div>
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="接入方式" name="integrationModes">
|
||||
<a-checkbox-group
|
||||
v-model:value="form.data.integrationModes"
|
||||
:options="joinOptions"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-collapse
|
||||
v-model:activeKey="form.integrationModesISO"
|
||||
>
|
||||
<a-collapse-panel
|
||||
key="page"
|
||||
v-show="
|
||||
form.data.integrationModes.includes('page')
|
||||
"
|
||||
header="页面集成"
|
||||
>
|
||||
<a-form-item
|
||||
:name="['page', 'baseUrl']"
|
||||
class="resetLabel"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="接入地址"
|
||||
required
|
||||
tooltip="填写访问其它平台的地址"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.data.page.baseUrl"
|
||||
placeholder="请输入接入地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="路由方式"
|
||||
:name="['page', 'routeType']"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="form.data.page.routeType"
|
||||
style="width: 120px"
|
||||
>
|
||||
<a-select-option value="hash"
|
||||
>hash</a-select-option
|
||||
>
|
||||
<a-select-option value="history"
|
||||
>history</a-select-option
|
||||
>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel
|
||||
key="apiClient"
|
||||
v-show="
|
||||
form.data.integrationModes.includes(
|
||||
'apiClient',
|
||||
)
|
||||
"
|
||||
header="API客户端"
|
||||
>
|
||||
<a-form-item
|
||||
class="resetLabel"
|
||||
:name="['apiClient', 'baseUrl']"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="接口地址"
|
||||
required
|
||||
tooltip="访问Api服务的地址"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.baseUrl
|
||||
"
|
||||
placeholder="请输入接入地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="resetLabel"
|
||||
:name="[
|
||||
'apiClient',
|
||||
'authConfig',
|
||||
'oauth2',
|
||||
'authorizationUrl',
|
||||
]"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="授权地址"
|
||||
required
|
||||
tooltip="认证授权地址"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.authConfig
|
||||
.oauth2.authorizationUrl
|
||||
"
|
||||
placeholder="请输入授权地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="resetLabel"
|
||||
:name="[
|
||||
'apiClient',
|
||||
'authConfig',
|
||||
'oauth2',
|
||||
'tokenUrl',
|
||||
]"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="token地址"
|
||||
required
|
||||
tooltip="设置token令牌的地址"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.authConfig
|
||||
.oauth2.tokenUrl
|
||||
"
|
||||
placeholder="请输入token地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="回调地址"
|
||||
:name="[
|
||||
'apiClient',
|
||||
'authConfig',
|
||||
'oauth2',
|
||||
'redirectUri',
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="回调地址"
|
||||
tooltip="授权完成后跳转到具体页面的回调地址"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.authConfig
|
||||
.oauth2.redirectUri
|
||||
"
|
||||
placeholder="请输入回调地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="resetLabel"
|
||||
:name="[
|
||||
'apiClient',
|
||||
'authConfig',
|
||||
'oauth2',
|
||||
'clientId',
|
||||
]"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="appId"
|
||||
required
|
||||
tooltip="第三方应用唯一标识"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.authConfig
|
||||
.oauth2.clientId
|
||||
"
|
||||
placeholder="请输入appId"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="resetLabel"
|
||||
:name="[
|
||||
'apiClient',
|
||||
'authConfig',
|
||||
'oauth2',
|
||||
'clientSecret',
|
||||
]"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<template #label>
|
||||
<FormLabel
|
||||
text="appKey"
|
||||
required
|
||||
tooltip="第三方应用唯一标识的密钥"
|
||||
/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="
|
||||
form.data.apiClient.authConfig
|
||||
.oauth2.clientSecret
|
||||
"
|
||||
placeholder="请输入appKey"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="请求头"> </a-form-item>
|
||||
<a-form-item label="参数"> </a-form-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel
|
||||
key="apiServer"
|
||||
v-show="
|
||||
form.data.integrationModes.includes(
|
||||
'apiServer',
|
||||
)
|
||||
"
|
||||
header="API服务"
|
||||
>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel
|
||||
key="ssoClient"
|
||||
v-show="
|
||||
form.data.integrationModes.includes(
|
||||
'ssoClient',
|
||||
)
|
||||
"
|
||||
header="单点登录"
|
||||
>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
<a-form-item label="说明" name="description">
|
||||
<a-textarea
|
||||
v-model:value="form.data.description"
|
||||
placeholder="请输入说明"
|
||||
showCount
|
||||
:maxlength="200"
|
||||
:rows="5"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button v-if="!routeQuery.view">保存</a-button>
|
||||
</a-col>
|
||||
<a-col :span="10"><Does :type="form.data.provider" /></a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Does from './components/Does.vue';
|
||||
import FormLabel from './components/FormLabel.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import type { applyType, formType } from './typing';
|
||||
const routeQuery = useRoute().query;
|
||||
|
||||
const initForm: formType = {
|
||||
name: '',
|
||||
provider: 'internal-standalone',
|
||||
integrationModes: [],
|
||||
config: '',
|
||||
description: '',
|
||||
page: {
|
||||
baseUrl: '',
|
||||
routeType: 'hash',
|
||||
},
|
||||
apiClient: {
|
||||
baseUrl: '',
|
||||
authConfig: {
|
||||
type: '',
|
||||
oauth2: {
|
||||
authorizationUrl: '',
|
||||
tokenUrl: '',
|
||||
redirectUri: '',
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const form = reactive({
|
||||
data: { ...initForm },
|
||||
integrationModesISO: [] as string[],
|
||||
});
|
||||
const joinOptions = computed(() => {
|
||||
if (form.data.provider === 'internal-standalone')
|
||||
return [
|
||||
{
|
||||
label: '页面集成',
|
||||
value: 'page',
|
||||
},
|
||||
{
|
||||
label: 'API客户端',
|
||||
value: 'apiClient',
|
||||
},
|
||||
{
|
||||
label: 'API服务',
|
||||
value: 'apiServer',
|
||||
},
|
||||
{
|
||||
label: '单点登录',
|
||||
value: 'ssoClient',
|
||||
},
|
||||
];
|
||||
else if (form.data.provider === 'internal-integrated')
|
||||
return [
|
||||
{
|
||||
label: '页面集成',
|
||||
value: 'page',
|
||||
},
|
||||
{
|
||||
label: 'API客户端',
|
||||
value: 'apiClient',
|
||||
},
|
||||
];
|
||||
else if (form.data.provider === 'wechat-webapp')
|
||||
return [
|
||||
{
|
||||
label: '单点登录',
|
||||
value: 'ssoClient',
|
||||
},
|
||||
];
|
||||
else if (form.data.provider === 'dingtalk-ent-app')
|
||||
return [
|
||||
{
|
||||
label: '单点登录',
|
||||
value: 'ssoClient',
|
||||
},
|
||||
];
|
||||
else if (form.data.provider === 'third-party')
|
||||
return [
|
||||
{
|
||||
label: '页面集成',
|
||||
value: 'page',
|
||||
},
|
||||
{
|
||||
label: 'API客户端',
|
||||
value: 'apiClient',
|
||||
},
|
||||
{
|
||||
label: 'API服务',
|
||||
value: 'apiServer',
|
||||
},
|
||||
{
|
||||
label: '单点登录',
|
||||
value: 'ssoClient',
|
||||
},
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.save-container {
|
||||
.form {
|
||||
.ant-form-item {
|
||||
&.resetLabel {
|
||||
:deep(.ant-form-item-required) {
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
.radio-container {
|
||||
.ant-radio-button-wrapper {
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
padding: 0 15px;
|
||||
box-sizing: content-box;
|
||||
margin-right: 20px;
|
||||
|
||||
> :last-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
:deep(.ant-image) {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,30 @@
|
|||
export type applyType = 'internal-standalone'
|
||||
| 'wechat-webapp'
|
||||
| 'internal-integrated'
|
||||
| 'dingtalk-ent-app'
|
||||
| 'third-party'
|
||||
|
||||
export type formType = {
|
||||
name: string;
|
||||
provider: applyType;
|
||||
integrationModes: string[];
|
||||
config: string;
|
||||
description: string;
|
||||
page: {
|
||||
baseUrl:string,
|
||||
routeType:'hash' | 'history'
|
||||
},
|
||||
apiClient: {
|
||||
baseUrl: string,
|
||||
authConfig: {
|
||||
type:string,
|
||||
oauth2 :{
|
||||
authorizationUrl:string,
|
||||
tokenUrl: string,
|
||||
redirectUri:string,
|
||||
clientId:string,
|
||||
clientSecret:string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,399 @@
|
|||
<template>
|
||||
<div>
|
||||
应用管理
|
||||
</div>
|
||||
<page-container class="apply-container">
|
||||
<div class="apply-container">
|
||||
<Search :columns="columns" @search="search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:request="getApplyList_api"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
:params="params"
|
||||
:gridColumn="3"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<div style="display: flex; align-items: center">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:add`"
|
||||
type="primary"
|
||||
@click="() => table.toSave()"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<p style="margin: 0 0 0 30px; color: #0000008c">
|
||||
<AIcon
|
||||
type="ExclamationCircleOutlined"
|
||||
style="margin-right: 12px"
|
||||
/>
|
||||
应用管理将多个应用系统的登录简化为一次登录,实现多处访问、集中管控的业务场景。
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
:actions="table.getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img :src="getImage('/apply.png')" />
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3 class="card-item-content-title">
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
类型
|
||||
</div>
|
||||
<div>
|
||||
{{
|
||||
table.getTypeLabel(
|
||||
slotProps.provider,
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
说明
|
||||
</div>
|
||||
<div>{{ slotProps.description }}</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<a-tooltip
|
||||
v-bind="item.tooltip"
|
||||
:title="item.disabled && item.tooltip.title"
|
||||
>
|
||||
<a-dropdown
|
||||
placement="bottomRight"
|
||||
v-if="item.key === 'others'"
|
||||
>
|
||||
<a-button>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item.text }}</span>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item
|
||||
v-for="(o, i) in item.children"
|
||||
:key="i"
|
||||
>
|
||||
<a-button
|
||||
type="link"
|
||||
@click="o.onClick"
|
||||
>
|
||||
<AIcon :type="o.icon" />
|
||||
<span>{{ o.text }}</span>
|
||||
</a-button>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<PermissionButton
|
||||
v-else
|
||||
:uhasPermission="item.permission"
|
||||
:tooltip="item.tooltip"
|
||||
:pop-confirm="item.popConfirm"
|
||||
@click="item.onClick"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<AIcon :type="item.icon" />
|
||||
<span v-if="item.key !== 'delete'">{{
|
||||
item.text
|
||||
}}</span>
|
||||
</PermissionButton>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
|
||||
<template #provider="slotProps">
|
||||
{{ table.getTypeLabel(slotProps.provider) }}
|
||||
</template>
|
||||
<template #status="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state.value"
|
||||
:text="slotProps.state.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
v-for="i in table.getActions(slotProps, 'table')"
|
||||
:uhasPermission="i.permission"
|
||||
type="link"
|
||||
:tooltip="i.tooltip"
|
||||
:pop-confirm="i.popConfirm"
|
||||
@click="i.onClick"
|
||||
:disabled="i.disabled"
|
||||
>
|
||||
<AIcon :type="i.icon" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts" name="Apply">
|
||||
import PermissionButton from '@/components/PermissionButton/index.vue';
|
||||
import {
|
||||
getApplyList_api,
|
||||
changeApplyStatus_api,
|
||||
delApply_api,
|
||||
} from '@/api/system/apply';
|
||||
import { ActionsType } from '@/components/Table';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const menuStory = useMenuStore();
|
||||
const permission = 'system/User';
|
||||
const typeOptions = [
|
||||
{
|
||||
label: '内部独立应用',
|
||||
value: 'internal-standalone',
|
||||
},
|
||||
{
|
||||
label: '微信网站应用',
|
||||
value: 'wechat-webapp',
|
||||
},
|
||||
{
|
||||
label: '内部集成应用',
|
||||
value: 'internal-integrated',
|
||||
},
|
||||
{
|
||||
label: '钉钉企业内部应用',
|
||||
value: 'dingtalk-ent-app',
|
||||
},
|
||||
{
|
||||
label: '第三方应用',
|
||||
value: 'third-party',
|
||||
},
|
||||
];
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'provider',
|
||||
key: 'provider',
|
||||
ellipsis: true,
|
||||
fixed: 'left',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: typeOptions,
|
||||
},
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
rename: 'status',
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 'enabled',
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 'disabled',
|
||||
},
|
||||
],
|
||||
},
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
scopedSlots: true,
|
||||
},
|
||||
];
|
||||
const params = ref({});
|
||||
const search = (newParams: any) => (params.value = {...newParams});
|
||||
|
||||
const tableRef = ref();
|
||||
const table = {
|
||||
refresh: () => {
|
||||
tableRef.value.reload();
|
||||
},
|
||||
toSave: (id?: string, view = false) => {
|
||||
if (id) menuStory.jumpPage('system/Apply/Save', {}, { id, view });
|
||||
else menuStory.jumpPage('system/Apply/Save');
|
||||
},
|
||||
changeStatus: (row: any) => {
|
||||
const state = row.state.value === 'enabled' ? 'disabled' : 'enabled';
|
||||
changeApplyStatus_api(row.id, { state }).then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功');
|
||||
table.refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
clickDel: (row: any) => {
|
||||
delApply_api(row.id).then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功');
|
||||
table.refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
getActions: (
|
||||
data: Partial<Record<string, any>>,
|
||||
type: 'card' | 'table',
|
||||
) => {
|
||||
if (!data) return [];
|
||||
const disabled = data.state.value === 'enabled';
|
||||
|
||||
const result = [
|
||||
{
|
||||
permission: true,
|
||||
key: 'edit',
|
||||
text: '编辑',
|
||||
tooltip: {
|
||||
title: '编辑',
|
||||
},
|
||||
icon: 'EditOutlined',
|
||||
onClick: () => table.toSave(data.id),
|
||||
},
|
||||
{
|
||||
permission: true,
|
||||
key: 'action',
|
||||
text: disabled ? '禁用' : '启用',
|
||||
tooltip: {
|
||||
title: disabled ? '禁用' : '启用',
|
||||
},
|
||||
popConfirm: {
|
||||
title: `确认${disabled ? '禁用' : '启用'}`,
|
||||
onConfirm: () => table.changeStatus(data),
|
||||
},
|
||||
icon: disabled ? 'StopOutlined' : 'PlayCircleOutlined',
|
||||
},
|
||||
{
|
||||
permission: true,
|
||||
key: 'delete',
|
||||
text: '删除',
|
||||
tooltip: {
|
||||
title: disabled ? '请先禁用再删除' : '删除',
|
||||
},
|
||||
popConfirm: {
|
||||
title: '确认删除?',
|
||||
onConfirm: () => table.clickDel(data),
|
||||
},
|
||||
disabled,
|
||||
icon: 'DeleteOutlined',
|
||||
},
|
||||
] as ActionsType[];
|
||||
const otherServers = data.integrationModes.map(
|
||||
(item: any) => item.value as string,
|
||||
);
|
||||
const others = {
|
||||
key: 'others',
|
||||
text: '其他',
|
||||
icon: 'EllipsisOutlined',
|
||||
children: [] as ActionsType[],
|
||||
};
|
||||
// 有集成菜单权限
|
||||
if (otherServers.includes('page'))
|
||||
others.children?.push({
|
||||
permission: true,
|
||||
key: 'page',
|
||||
text: '集成菜单',
|
||||
tooltip: {
|
||||
title: '集成菜单',
|
||||
},
|
||||
icon: 'MenuUnfoldOutlined',
|
||||
onClick: () => {},
|
||||
});
|
||||
// 有api操作权限
|
||||
if (otherServers.includes('apiServer'))
|
||||
others.children?.push(
|
||||
{
|
||||
permission: true,
|
||||
key: 'empowerment',
|
||||
text: '赋权',
|
||||
tooltip: {
|
||||
title: '赋权',
|
||||
},
|
||||
icon: 'icon-fuquan',
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
permission: true,
|
||||
key: 'viewApi',
|
||||
text: '查看API',
|
||||
tooltip: {
|
||||
title: '查看API',
|
||||
},
|
||||
icon: 'icon-chakanAPI',
|
||||
onClick: () => {},
|
||||
},
|
||||
);
|
||||
// 其他不为空
|
||||
if (others.children.length > 0) {
|
||||
if (type === 'card') {
|
||||
result.splice(result.length - 1, 0, others);
|
||||
} else {
|
||||
result.splice(result.length - 1, 0, ...others.children);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
getTypeLabel: (val: string) => {
|
||||
if (!val) return '';
|
||||
return typeOptions.find((item) => item.value === val)?.label;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.apply-container {
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,124 +1,134 @@
|
|||
<template>
|
||||
<div class="data-source-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
<page-container>
|
||||
<div class="data-source-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getDataSourceList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog({})"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state?.value"
|
||||
:text="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
>
|
||||
</BadgeStatus>
|
||||
</template>
|
||||
<template #typeId="slotProps">
|
||||
{{
|
||||
(table.typeOptions.value.length &&
|
||||
table.getTypeLabel(slotProps.typeId)) ||
|
||||
''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getDataSourceList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog({})"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:manage`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title:
|
||||
slotProps?.typeId === 'rabbitmq'
|
||||
? '暂不支持管理功能'
|
||||
: table.getRowStatus(slotProps)
|
||||
? '管理'
|
||||
: '请先启用数据源',
|
||||
}"
|
||||
@click="
|
||||
() =>
|
||||
router.push(
|
||||
`/system/DataSource/Management?id=${slotProps.id}`,
|
||||
)
|
||||
"
|
||||
:disabled="slotProps?.typeId === 'rabbitmq' || !table.getRowStatus(slotProps)"
|
||||
>
|
||||
<AIcon type="icon-ziyuankuguanli" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确定要${
|
||||
table.getRowStatus(slotProps) ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.clickChangeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '禁用'
|
||||
: '启用',
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state?.value"
|
||||
:text="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
>
|
||||
<AIcon
|
||||
:type="
|
||||
table.getRowStatus(slotProps)
|
||||
? 'StopOutlined'
|
||||
: 'PlayCircleOutlined'
|
||||
</BadgeStatus>
|
||||
</template>
|
||||
<template #typeId="slotProps">
|
||||
{{
|
||||
(table.typeOptions.value.length &&
|
||||
table.getTypeLabel(slotProps.typeId)) ||
|
||||
''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:manage`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title:
|
||||
slotProps?.typeId === 'rabbitmq'
|
||||
? '暂不支持管理功能'
|
||||
: table.getRowStatus(slotProps)
|
||||
? '管理'
|
||||
: '请先启用数据源',
|
||||
}"
|
||||
@click="
|
||||
() =>
|
||||
router.push(
|
||||
`/system/DataSource/Management?id=${slotProps.id}`,
|
||||
)
|
||||
"
|
||||
/>
|
||||
<!-- <AIcon type="PlayCircleOutlined" /> -->
|
||||
</PermissionButton>
|
||||
:disabled="
|
||||
slotProps?.typeId === 'rabbitmq' ||
|
||||
!table.getRowStatus(slotProps)
|
||||
"
|
||||
>
|
||||
<AIcon type="icon-ziyuankuguanli" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确定要${
|
||||
table.getRowStatus(slotProps)
|
||||
? '禁用'
|
||||
: '启用'
|
||||
}吗?`,
|
||||
onConfirm: () =>
|
||||
table.clickChangeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '禁用'
|
||||
: '启用',
|
||||
}"
|
||||
>
|
||||
<AIcon
|
||||
:type="
|
||||
table.getRowStatus(slotProps)
|
||||
? 'StopOutlined'
|
||||
: 'PlayCircleOutlined'
|
||||
"
|
||||
/>
|
||||
<!-- <AIcon type="PlayCircleOutlined" /> -->
|
||||
</PermissionButton>
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="table.getRowStatus(slotProps)"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="table.getRowStatus(slotProps)"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialogs">
|
||||
<EditDialog ref="editDialogRef" @confirm="table.refresh" />
|
||||
<div class="dialogs">
|
||||
<EditDialog ref="editDialogRef" @confirm="table.refresh" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="DataSource">
|
||||
|
@ -132,7 +142,7 @@ import {
|
|||
getDataSourceList_api,
|
||||
getDataTypeDict_api,
|
||||
changeStatus_api,
|
||||
delDataSource_api
|
||||
delDataSource_api,
|
||||
} from '@/api/system/dataSource';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
|
@ -243,7 +253,7 @@ const table = {
|
|||
key: 'action',
|
||||
scopedSlots: true,
|
||||
width: '200px',
|
||||
fixed:'right'
|
||||
fixed: 'right',
|
||||
},
|
||||
],
|
||||
|
||||
|
@ -298,7 +308,6 @@ table.getTypeOption();
|
|||
|
||||
<style lang="less" scoped>
|
||||
.data-source-container {
|
||||
padding: 24px;
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
<template>
|
||||
<div class="department-container">
|
||||
<a-card class="department-content">
|
||||
<div class="left">
|
||||
<LeftTree @change="(id) => (departmentId = id)" />
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="product" tab="产品">
|
||||
<Product
|
||||
:parentId="departmentId"
|
||||
@open-device-bind="openDeviceBind"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="device" tab="设备">
|
||||
<Device
|
||||
:parentId="departmentId"
|
||||
v-model:bindBool="bindBool"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="user" tab="用户">
|
||||
<User :parentId="departmentId" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
<page-container>
|
||||
<div class="department-container">
|
||||
<a-card class="department-content">
|
||||
<div class="left">
|
||||
<LeftTree @change="(id) => (departmentId = id)" />
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="product" tab="产品">
|
||||
<Product
|
||||
:parentId="departmentId"
|
||||
@open-device-bind="openDeviceBind"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="device" tab="设备">
|
||||
<Device
|
||||
:parentId="departmentId"
|
||||
v-model:bindBool="bindBool"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="user" tab="用户">
|
||||
<User :parentId="departmentId" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Department">
|
||||
|
@ -46,7 +48,6 @@ const openDeviceBind = () => {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.department-container {
|
||||
padding: 24px;
|
||||
.department-content {
|
||||
:deep(.ant-card-body) {
|
||||
display: flex;
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<template>
|
||||
<div class="menu-detail-container">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="basic" tab="基本信息"> <BasicInfo /> </a-tab-pane>
|
||||
<a-tab-pane key="button" tab="按钮管理">
|
||||
<ButtonMange />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
<page-container>
|
||||
<div class="menu-detail-container">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="basic" tab="基本信息">
|
||||
<BasicInfo />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="button" tab="按钮管理">
|
||||
<ButtonMange />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -24,7 +28,7 @@ const activeKey = ref('basic');
|
|||
}
|
||||
.ant-tabs-tabpane {
|
||||
background-color: #f0f2f5;
|
||||
padding: 24px;
|
||||
padding-top: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,73 +1,79 @@
|
|||
<template>
|
||||
<div class="menu-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="table.getList"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.toDetails({})"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<a-button
|
||||
style="margin-left: 12px"
|
||||
@click="router.push('/system/Menu/Setting')"
|
||||
>菜单配置</a-button
|
||||
>
|
||||
<!-- <PermissionButton
|
||||
:uhasPermission="true"
|
||||
@click="router.push('/system/Menu/Setting')"
|
||||
>
|
||||
菜单配置
|
||||
</PermissionButton> -->
|
||||
</template>
|
||||
<template #createTime="slotProps">
|
||||
{{ moment(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip>
|
||||
<template #title>查看</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
@click="table.toDetails(slotProps)"
|
||||
>
|
||||
<search-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<page-container>
|
||||
<div class="menu-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="table.getList"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
:tooltip="{ title: '新增子菜单' }"
|
||||
@click="table.addChildren(slotProps)"
|
||||
@click="table.toDetails({})"
|
||||
>
|
||||
<AIcon type="PlusCircleOutlined" />
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `是否删除该菜单`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
<a-button
|
||||
style="margin-left: 12px"
|
||||
@click="router.push('/system/Menu/Setting')"
|
||||
>菜单配置</a-button
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
<!-- <PermissionButton
|
||||
:uhasPermission="true"
|
||||
@click="router.push('/system/Menu/Setting')"
|
||||
>
|
||||
菜单配置
|
||||
</PermissionButton> -->
|
||||
</template>
|
||||
<template #createTime="slotProps">
|
||||
{{
|
||||
moment(slotProps.createTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip>
|
||||
<template #title>查看</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
@click="table.toDetails(slotProps)"
|
||||
>
|
||||
<search-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
:tooltip="{ title: '新增子菜单' }"
|
||||
@click="table.addChildren(slotProps)"
|
||||
>
|
||||
<AIcon type="PlusCircleOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `是否删除该菜单`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -269,8 +275,6 @@ const table = reactive({
|
|||
|
||||
<style lang="less" scoped>
|
||||
.menu-container {
|
||||
padding: 24px;
|
||||
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
|
|
|
@ -1,120 +1,127 @@
|
|||
<template>
|
||||
<div class="permission-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
<page-container>
|
||||
<div class="permission-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getPermission_api"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
:defaultParams="{ sorts: [{ name: 'id', order: 'asc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog(undefined)"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<a-dropdown trigger="hover">
|
||||
<a-button>批量操作</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<a-upload
|
||||
name="file"
|
||||
action="#"
|
||||
accept=".json"
|
||||
:showUploadList="false"
|
||||
:before-upload="table.clickImport"
|
||||
:disabled="
|
||||
!hasPermission(`${permission}:import`)
|
||||
"
|
||||
>
|
||||
<PermissionButton
|
||||
:hasPermission="`${permission}:import`"
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getPermission_api"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
:defaultParams="{ sorts: [{ name: 'id', order: 'asc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog(undefined)"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<a-dropdown trigger="hover">
|
||||
<a-button>批量操作</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<a-upload
|
||||
name="file"
|
||||
action="#"
|
||||
accept=".json"
|
||||
:showUploadList="false"
|
||||
:before-upload="table.clickImport"
|
||||
:disabled="
|
||||
!hasPermission(
|
||||
`${permission}:import`,
|
||||
)
|
||||
"
|
||||
>
|
||||
导入
|
||||
<PermissionButton
|
||||
:hasPermission="`${permission}:import`"
|
||||
>
|
||||
导入
|
||||
</PermissionButton>
|
||||
</a-upload>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:export`"
|
||||
:popConfirm="{
|
||||
title: `确认导出?`,
|
||||
onConfirm: () =>
|
||||
table.clickExport(),
|
||||
}"
|
||||
>
|
||||
导出
|
||||
</PermissionButton>
|
||||
</a-upload>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:export`"
|
||||
:popConfirm="{
|
||||
title: `确认导出?`,
|
||||
onConfirm: () => table.clickExport(),
|
||||
}"
|
||||
>
|
||||
导出
|
||||
</PermissionButton>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #status="slotProps">
|
||||
<StatusLabel :status-value="slotProps.status" />
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #status="slotProps">
|
||||
<StatusLabel :status-value="slotProps.status" />
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确定要${
|
||||
slotProps.status ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.changeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{ title: slotProps.status ? '禁用' : '启用' }"
|
||||
>
|
||||
<AIcon
|
||||
:type="
|
||||
slotProps.status
|
||||
? 'StopOutlined'
|
||||
: 'PlayCircleOutlined '
|
||||
"
|
||||
/>
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确定要${
|
||||
slotProps.status ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.changeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{
|
||||
title: slotProps.status ? '禁用' : '启用',
|
||||
}"
|
||||
>
|
||||
<AIcon
|
||||
:type="
|
||||
slotProps.status
|
||||
? 'StopOutlined'
|
||||
: 'PlayCircleOutlined '
|
||||
"
|
||||
/>
|
||||
</PermissionButton>
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: slotProps.status
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: slotProps.status
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialogs">
|
||||
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
|
||||
<div class="dialogs">
|
||||
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -281,7 +288,6 @@ const table = reactive({
|
|||
|
||||
<style lang="less" scoped>
|
||||
.permission-container {
|
||||
padding: 24px;
|
||||
|
||||
.ant-dropdown-trigger {
|
||||
margin-left: 12px;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<a-card class="api-page-container">
|
||||
<p>
|
||||
<AIcon type="ExclamationCircleOutlined" style="margin-right: 12px;" />配置系统支持API赋权的范围
|
||||
</p>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="5">
|
||||
<LeftTree @select="treeSelect" :mode="props.mode" />
|
||||
|
@ -117,7 +120,6 @@ function init() {
|
|||
|
||||
<style scoped>
|
||||
.api-page-container {
|
||||
padding: 24px;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<page-container>
|
||||
<Api mode="api" />
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Platforms">
|
||||
|
|
|
@ -1,55 +1,59 @@
|
|||
<template>
|
||||
<div class="relationship-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
<page-container>
|
||||
<div class="relationship-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getRelationshipList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog(undefined)"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getRelationshipList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog(undefined)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
|
||||
</div>
|
||||
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Relationship">
|
||||
|
@ -181,7 +185,6 @@ const table = {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.relationship-container {
|
||||
padding: 24px;
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<div class="details-container">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="1" tab="权限分配"><Permiss /></a-tab-pane>
|
||||
<a-tab-pane key="2" tab="用户管理"><User /></a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
<page-container>
|
||||
<div class="details-container">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="1" tab="权限分配"><Permiss /></a-tab-pane>
|
||||
<a-tab-pane key="2" tab="用户管理"><User /></a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Detail">
|
||||
|
@ -17,17 +19,9 @@ const activeKey = ref('1');
|
|||
|
||||
<style lang="less" scoped>
|
||||
.details-container {
|
||||
|
||||
|
||||
|
||||
:deep(.ant-tabs-nav-wrap) {
|
||||
background-color: #fff;
|
||||
padding: 24px 0 0 24px;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-content-holder) {
|
||||
padding: 24px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
<template>
|
||||
<a-card class="role-container">
|
||||
<Search :columns="query.columns" />
|
||||
<page-container>
|
||||
<a-card class="role-container">
|
||||
<Search :columns="query.columns" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getRoleList_api"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.clickAdd"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getRoleList_api"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.clickEdit(slotProps)"
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.clickAdd"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `确定要删除吗`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</template>
|
||||
|
||||
<div class="dialogs">
|
||||
<AddDialog ref="addDialogRef" />
|
||||
</div>
|
||||
</a-card>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.clickEdit(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `确定要删除吗`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialogs">
|
||||
<AddDialog ref="addDialogRef" />
|
||||
</div>
|
||||
</a-card>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Role">
|
||||
|
@ -146,12 +148,10 @@ nextTick(() => {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.role-container {
|
||||
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,46 +1,49 @@
|
|||
<template>
|
||||
<div class="user-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
<page-container>
|
||||
<div class="user-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getUserList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<!-- <a-button
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getUserList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<!-- <a-button
|
||||
type="primary"
|
||||
@click="table.openDialog('add')"
|
||||
style="margin-right: 10px"
|
||||
><AIcon type="PlusOutlined" />新增</a-button
|
||||
> -->
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:add`"
|
||||
type="primary"
|
||||
@click="table.openDialog('add')"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #type="slotProps">
|
||||
{{ slotProps.type.name }}
|
||||
</template>
|
||||
<template #status="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.status"
|
||||
:text="slotProps.status ? '正常' : '禁用'"
|
||||
:statusNames="{
|
||||
1: 'success',
|
||||
0: 'error',
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<!-- <a-tooltip>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:add`"
|
||||
type="primary"
|
||||
@click="table.openDialog('add')"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #type="slotProps">
|
||||
{{ slotProps.type.name }}
|
||||
</template>
|
||||
<template #status="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.status"
|
||||
:text="slotProps.status ? '正常' : '禁用'"
|
||||
:statusNames="{
|
||||
1: 'success',
|
||||
0: 'error',
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<!-- <a-tooltip>
|
||||
<template #title>编辑</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
|
@ -50,7 +53,7 @@
|
|||
<AIcon type="EditOutlined" />
|
||||
</a-button>
|
||||
</a-tooltip> -->
|
||||
<!-- <a-popconfirm
|
||||
<!-- <a-popconfirm
|
||||
:title="`确定${slotProps.status ? '禁用' : '启用'}吗?`"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
|
@ -66,7 +69,7 @@
|
|||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-popconfirm> -->
|
||||
<!-- <a-tooltip>
|
||||
<!-- <a-tooltip>
|
||||
<template #title>重置密码</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
|
@ -76,7 +79,7 @@
|
|||
<AIcon type="icon-zhongzhimima" />
|
||||
</a-button>
|
||||
</a-tooltip> -->
|
||||
<!-- <a-popconfirm
|
||||
<!-- <a-popconfirm
|
||||
title="确认删除"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
|
@ -97,66 +100,67 @@
|
|||
</a-tooltip>
|
||||
</a-popconfirm> -->
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog('edit')"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: `${slotProps.status ? '禁用' : '启用'}`,
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确定${
|
||||
slotProps.status ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.changeStatus(slotProps),
|
||||
}"
|
||||
>
|
||||
<stop-outlined v-if="slotProps.status" />
|
||||
<play-circle-outlined v-else />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '重置密码',
|
||||
}"
|
||||
@click="table.openDialog('reset', slotProps)"
|
||||
>
|
||||
<AIcon type="icon-zhongzhimima" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{
|
||||
title: slotProps.status
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog('edit')"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: `${slotProps.status ? '禁用' : '启用'}`,
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确定${
|
||||
slotProps.status ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.changeStatus(slotProps),
|
||||
}"
|
||||
>
|
||||
<stop-outlined v-if="slotProps.status" />
|
||||
<play-circle-outlined v-else />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '重置密码',
|
||||
}"
|
||||
@click="table.openDialog('reset', slotProps)"
|
||||
>
|
||||
<AIcon type="icon-zhongzhimima" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
:tooltip="{
|
||||
title: slotProps.status
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialogs">
|
||||
<EditUserDialog ref="editDialogRef" @confirm="table.refresh" />
|
||||
<div class="dialogs">
|
||||
<EditUserDialog ref="editDialogRef" @confirm="table.refresh" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="UserMange">
|
||||
|
@ -354,8 +358,6 @@ type modalType = '' | 'add' | 'edit' | 'reset';
|
|||
|
||||
<style lang="less" scoped>
|
||||
.user-container {
|
||||
padding: 24px;
|
||||
|
||||
:deep(.ant-table-tbody) {
|
||||
.ant-table-cell {
|
||||
.ant-space-item {
|
||||
|
|
40
yarn.lock
40
yarn.lock
|
@ -703,10 +703,10 @@
|
|||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@npmcli/arborist@*", "@npmcli/arborist@^6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.jetlinks.cn/@npmcli%2farborist/-/arborist-6.2.2.tgz#3ea668e7d368376a8477bd7bc3389bf634603b5b"
|
||||
integrity sha512-cjK9CuA1cEovr4E1ljdgYU1UBdKJb4KvvULAEYOM1/qU0Que2X4DKyjIDBEy8MSWRY6PyaQ8oLGhwYIh8gUEEA==
|
||||
"@npmcli/arborist@*", "@npmcli/arborist@^6.2.3":
|
||||
version "6.2.3"
|
||||
resolved "https://registry.jetlinks.cn/@npmcli%2farborist/-/arborist-6.2.3.tgz#31f8aed2588341864d3811151d929c01308f8e71"
|
||||
integrity sha512-lpGOC2ilSJXcc2zfW9QtukcCTcMbl3fVI0z4wvFB2AFIl0C+Q6Wv7ccrpdrQa8rvJ1ZVuc6qkX7HVTyKlzGqKA==
|
||||
dependencies:
|
||||
"@isaacs/string-locale-compare" "^1.1.0"
|
||||
"@npmcli/fs" "^3.1.0"
|
||||
|
@ -3894,11 +3894,11 @@ libnpmaccess@*:
|
|||
npm-registry-fetch "^14.0.3"
|
||||
|
||||
libnpmdiff@*:
|
||||
version "5.0.10"
|
||||
resolved "https://registry.jetlinks.cn/libnpmdiff/-/libnpmdiff-5.0.10.tgz#1813cc63b0370fdd41187ca0ce39df655536d648"
|
||||
integrity sha512-FZdlnoPkj8w4RM3j5eLYhYzf5q416Tpl2aO3fc77gJ9ZeJFS8cVQAR6gK5+pSAaiRJGSlef4/em0uKBOTQjXXA==
|
||||
version "5.0.11"
|
||||
resolved "https://registry.jetlinks.cn/libnpmdiff/-/libnpmdiff-5.0.11.tgz#a8d3b9ff61e55f5cb377efc4ef06c7987236f5a1"
|
||||
integrity sha512-oF+BCE8LwfSZaUkmIEKmfX4WmvE6puZhYKnRayynHrh6f1qMRqoutqIXlPS6wCF8IRV6sgAhXYOsBUYC6PTPCA==
|
||||
dependencies:
|
||||
"@npmcli/arborist" "^6.2.2"
|
||||
"@npmcli/arborist" "^6.2.3"
|
||||
"@npmcli/disparity-colors" "^3.0.0"
|
||||
"@npmcli/installed-package-contents" "^2.0.0"
|
||||
binary-extensions "^2.2.0"
|
||||
|
@ -3909,11 +3909,11 @@ libnpmdiff@*:
|
|||
tar "^6.1.13"
|
||||
|
||||
libnpmexec@*:
|
||||
version "5.0.10"
|
||||
resolved "https://registry.jetlinks.cn/libnpmexec/-/libnpmexec-5.0.10.tgz#281585adbf22935400f3c0456f88add4c69e4e74"
|
||||
integrity sha512-m7Hqi2xXbzIjVbb+4PbOwkBvHLgG0tnQwCvzW7iTA8pL6FsnKSWfgTpWLiDLoPGCdO2q0D766ikvdknziomKzg==
|
||||
version "5.0.11"
|
||||
resolved "https://registry.jetlinks.cn/libnpmexec/-/libnpmexec-5.0.11.tgz#ac579b6ac1bd20c0ea191386129ba5cc5051ef61"
|
||||
integrity sha512-4Ec55gMBgGiJmaFjSVNc8s9iu6xBuqGJubtrWrK+5uCHbSoQd8Fng/cLE63hyZQTwyj0LTvHn0j/UEr0bTPTvw==
|
||||
dependencies:
|
||||
"@npmcli/arborist" "^6.2.2"
|
||||
"@npmcli/arborist" "^6.2.3"
|
||||
"@npmcli/run-script" "^6.0.0"
|
||||
chalk "^4.1.0"
|
||||
ci-info "^3.7.1"
|
||||
|
@ -3927,11 +3927,11 @@ libnpmexec@*:
|
|||
walk-up-path "^1.0.0"
|
||||
|
||||
libnpmfund@*:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.jetlinks.cn/libnpmfund/-/libnpmfund-4.0.10.tgz#b6228e4fcf91ed2064d59c4f7af701c1313d10e0"
|
||||
integrity sha512-fPR3Y01Mditp/FNT4BUsilHCHgvzZRwxpQBbaUYBRG0lxBdO+AT8pHta9SmCSLwUn60bwmw2SDBxDv6bMWUi5Q==
|
||||
version "4.0.11"
|
||||
resolved "https://registry.jetlinks.cn/libnpmfund/-/libnpmfund-4.0.11.tgz#201aa162af6062387b3e505a732e0de101e2846e"
|
||||
integrity sha512-tDJqNcTAEQURma4UXBVIpyw1CrL5RPla0rnx5dBK2jt+zPa6i62RwcYLNa9vHUYdGBoN993fZtl77ddEFj72xQ==
|
||||
dependencies:
|
||||
"@npmcli/arborist" "^6.2.2"
|
||||
"@npmcli/arborist" "^6.2.3"
|
||||
|
||||
libnpmhook@*:
|
||||
version "9.0.3"
|
||||
|
@ -3950,11 +3950,11 @@ libnpmorg@*:
|
|||
npm-registry-fetch "^14.0.3"
|
||||
|
||||
libnpmpack@*:
|
||||
version "5.0.10"
|
||||
resolved "https://registry.jetlinks.cn/libnpmpack/-/libnpmpack-5.0.10.tgz#9c84139f80d34068ffc66d09313931fb6e9c4554"
|
||||
integrity sha512-yCkyi+XS7WS0XXXdCnt+/b6zEdXqhanIvS6sw8yzZ5lHElJruggDodZRBQR9HYewa1xeq5Lr11eOpEODenEpjA==
|
||||
version "5.0.11"
|
||||
resolved "https://registry.jetlinks.cn/libnpmpack/-/libnpmpack-5.0.11.tgz#b054a62e0c553b5685b02266a4a5036d9828ebdf"
|
||||
integrity sha512-Ke2URk4d96SkxTEEUdW7TOWb0DLFrDWAdBEc1SPF/JrhebhS3/Rm1kazWOZ6JhK6PQBIsVPGmBq5MwboAtSR4w==
|
||||
dependencies:
|
||||
"@npmcli/arborist" "^6.2.2"
|
||||
"@npmcli/arborist" "^6.2.3"
|
||||
"@npmcli/run-script" "^6.0.0"
|
||||
npm-package-arg "^10.1.0"
|
||||
pacote "^15.0.8"
|
||||
|
|
Loading…
Reference in New Issue